第12章の2 記憶クラスの種類

「記憶クラス」とは宣言する変数をどこに記憶するかを指定します。
このホームページでは「自動変数」、「外部変数」、「静的変数」に分けて「記憶クラス」を説明します。

(1)自動変数

  • 関数内部で宣言され、宣言された関数の中でのみ使用可能。(= ローカル変数)
  • 関数実行中のみメモリ上のスタックに確保され、関数の実行が終了すると、メモリ上から削除される。(⇒ メモリの有効利用)
  • 関数が呼ばれるたびに初期化を行う。
  • auto int a; のように宣言する。
    ただし、「auto」は通常省略され、単に「int a;」のように宣言する。
  • 明示的に初期化を行わないと、初期値は不定値になってしまう。
  • 前章までの学習で使用していた変数はすべてこの自動変数に該当する。

(2)外部変数

  • 関数外で定義され、定義以降のどの関数からでも使用可能。(= グローバル変数)
  • プログラム開始処理の前に一度だけ初期化を行う。
  • プログラム実行中に常に同じ場所に配置され値を保持。
  • 明示的に初期化を行わない場合は、初期値は 0 になる。(明示的に初期化をしたほうがわかりやすい。)

(3)静的変数

  • プログラム実行中に常に同じ場所に配置され値を保持 → 値を保持したいときに使用。(外部変数の機能)
  • 関数内部で宣言され、宣言された関数の中でのみ使用可能。(自動変数の機能)
  • プログラム開始処理の前に一度だけ初期化を行う。
  • static int a; のように宣言する。
  • 明示的に初期化を行わない場合は、初期値は 0 になる。(明示的に初期化をしたほうがわかりやすい。)

(4)自動変数と静的変数の使用比較

#include <stdio.h>

int min1(int n);
int min2(int n);

int main(void)
{
    printf("自動変数:最小値 = %d\n",min1(100));
    printf("自動変数:最小値 = %d\n",min1(10));
    printf("自動変数:最小値 = %d\n",min1(50));
    printf("静的変数:最小値 = %d\n",min2(100));
    printf("静的変数:最小値 = %d\n",min2(10));
    printf("静的変数:最小値 = %d\n",min2(50));
    
    return 0;
}

min1()は自動変数を使って、
min2()は静的変数を使って、
引数の最小値を正しく保持できるかを比較する。

/*** 自動変数を使った例 ***/
int min1(int n)
{
    /* min として自動変数を宣言 */
    int min = 999;
    
    if (n < min) {
        min = n;    /* min を更新 */
    }
    return min;
}

自動変数として宣言された「min」は、min1()が実行されている間のみメモリ上に存在し、
関数が呼ばれるたびに 999 に設定される。

そのため、更新された最小値を記憶する事ができない。

/*** 静的変数を使った例 ***/
int min2(int n)
{
    /* min として静的変数を宣言 */
    static int min = 999; 
    
    if (n < min) {
        min = n;    /* min を更新 */
    }
    return min;
}

静的変数として宣言された「min」は、プログラムが実行している間はメモリ上に存在でき、コンパイル時に一度だけ 999 に設定される。
そのため、更新された最小値を記憶する事ができる

【実行結果例】
自動変数:最小値 = 100   
自動変数:最小値 = 10     | 値が保持できない
自動変数:最小値 = 50   
静的変数:最小値 = 100   
静的変数:最小値 = 10     | 値が保持できる
静的変数:最小値 = 10   

〇 演習問題

次の手順に従い、プログラムを作成しなさい。

  1. 外部変数で整数型の配列 seiseki[100][2] を用意する。
  2. main関数で次の処理を行う。
    • 「Ctrl+Z」(UNIXの環境では「Ctrl+D」) が入力されるまで、学生番号と点数を入力し、入力した学生番号と点数を引数にして、set_ten関数を呼ぶ。
    • Ctrl+Z が入力されたら、配列 seiseki の中身をデータがセットされた個数分表示する。
  3. set_ten関数の仕様は以下である。
    関数宣言:int set_ten( int no, int ten );
    引数:no … 学生番号
       ten … 点数
    返却値:配列 seiseki にセットしたデータ数
  4. set_ten関数の処理内容は以下である。
    • 整数型の静的変数で errcnt と setcnt を宣言する。
    • 引数の点数が 0点未満か 100点より大きいときには errcnt の個数を更新し、次のメッセージを表示する。
      「入力エラーです。エラーの回数は errcnt 回です。」
    • そうでなければ配列 seiseki の setcnt番目に引数の番号と点数を代入し、setcnt の値を更新する。
    • setcnt の値を return する。

【実行結果例】
学生番号と点数を入力してください(終了条件:整数値以外の入力)1
44
学生番号と点数を入力してください 2
65
学生番号と点数を入力してください 3
76
学生番号と点数を入力してください 4
-1
入力エラーです。エラーの回数は1回です。
学生番号と点数を入力してください 4
51
学生番号と点数を入力してください 5
101
入力エラーです。エラーの回数は2回です。
学生番号と点数を入力してください e
学生番号 = 1 点数 = 44
学生番号 = 2 点数 = 65
学生番号 = 3 点数 = 76
学生番号 = 4 点数 = 51

※ 水色文字はキーボードからの入力

解答例

#include <stdio.h>

int set_ten(int no, int ten);
int seiseki[100][2];

int main(void)
{
int tensu, gno, cnt = 0;

printf("学生番号と点数を入力してください(終了条件:整数値以外の入力)");
while(scanf("%d%d", &gno, &tensu) == 2) {
cnt = set_ten(gno, tensu);
printf("学生番号と点数を入力してください ");
}
for (int i = 0; i < cnt; i++) {
printf("学生番号 = %d 点数 = %d\n", seiseki[i][0], seiseki[i][1]);
}

return 0;
}

int set_ten(int no, int ten)
{
static int errcnt = 0;
static int setcnt = 0;

if (ten < 0 || ten > 100) {
errcnt++;
printf("入力エラーです。エラーの回数は%d回です。\n", errcnt);
}
else {
seiseki[setcnt][0] = no;
seiseki[setcnt][1] = ten;
setcnt++;
}

コメント