スコープと記憶域期間 解答ページ | Programming Place Plus C言語編 第22章

トップページC言語編第22章

問題① 🔗

問題① 次のプログラムの実行結果を答えてください。

#include <stdio.h>

int num = 100;

void func(void);

int main(void)
{
    {
        int num = 300;
        printf("%d\n", num);
    }

    func();
    printf("%d\n", num);
}

void func(void)
{
    int num = 200;

    printf("%d\n", num);
    {
        printf("%d\n", num);
    }
}


実行結果は次のようになります。

実行結果:

300
200
200
100

main関数の最初にある printf関数では、同じブロック内にある変数num の値が出力されます。

次に、func関数内にある 2つの printf関数ですが、これはいずれも func関数内の変数num の値が出力されます。

main関数に戻ってきた後の printf関数では、その位置から可視なのはグローバル変数の num だけですから、グローバル変数の num の値が出力されます。

ルールとしては、今実行している箇所と同じブロックが優先され、そこから外へ外へとスコープを広げて、宣言を探しにいくということです。

問題② 🔗

問題② 呼び出すたびに 0、1、2 … という具合に増加する整数を出力する countup_print関数を作ってください。


静的ローカル変数を使って実現できます。

#include <stdio.h>

void countup_print(void);

int main(void)
{
    for (int i = 0; i < 5; ++i) {
        countup_print();
    }
}

void countup_print(void)
{
    static int num = 0;
    printf("%d\n", num);
    ++num;
}

実行結果:

0
1
2
3
4

静的ローカル変数は、静的記憶域期間を持つため、プログラムの開始直後にオブジェクトが構築され、プログラムが終了するまでメモリに存在し続けます。そのため、関数を抜けても、最後に記憶していた値を失いません。

便利なようにも思える反面、明確に不便なところもあって、たとえばカウントを 0 に戻したいと思ったとき、自然に実現する方法がありません。せいぜい、引数で指示を与えるくらいのことしかできません。

void countup_print(_Bool reset)
{
    static int num = 0;
    if (reset) {
        num = 0;
    }
    printf("%d\n", num);
    ++num;
}

こういうことをしていると、プログラムはどんどん複雑化していきますし、使い方を間違える可能性も高くなります。

グローバル変数を使って実現すれば、0 に戻す機能を付けやすくなりますが、スコープを狭く保つべしという基本原則からは遠ざかることになります。

#include <stdio.h>

int g_num = 0;

void countup_print(void);
void countup_reset(void);

int main(void)
{
    for (int i = 0; i < 5; ++i) {
        countup_print();
    }
    countup_reset();
    for (int i = 0; i < 5; ++i) {
        countup_print();
    }
}

void countup_print(void)
{
    printf("%d\n", g_num);
    ++g_num;
}

void countup_reset(void)
{
    g_num = 0;
}

実行結果:

0
1
2
3
4
0
1
2
3
4

問題③ 🔗

問題③ 次のプログラムで、コメントの箇所にある printf関数が、グローバル変数の方の num の値を出力できるようにプログラムを書き換えてください。

#include <stdio.h>

int num = 100;

int main(void)
{
    int num;

    num = 10;
    printf("%d\n", num);
    printf("%d\n", num);  // グローバル変数の方を出力したい
}


1つの方法は、ブロックで囲むことです。

#include <stdio.h>

int num = 100;

int main(void)
{
    {
        int num;

        num = 10;
        printf("%d\n", num);
    }
    printf("%d\n", num);  // グローバル変数の方を出力したい
}

実行結果:

10
100

変数名が被らないのが一番良いです。できるなら、グローバル変数の名前を変えましょう。g などのグローバル変数であることをあらわすプリフィックスを付けたり、長い名前にしたりします。

#include <stdio.h>

int g_num = 100;

int main(void)
{
    int num;

    num = 10;
    printf("%d\n", num);
    printf("%d\n", g_num); // グローバル変数の方を出力したい
}

実行結果:

10
100


参考リンク 🔗


更新履歴 🔗

≪さらに古い更新履歴≫

 全面的に文章を見直し、修正を行った。

 サンプルプログラムに含まれていた余計なコードを削除。

 新規作成。



第22章のメインページへ

C言語編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る