Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

【C言語】初期化されていない配列にアクセスするとどうなる?挙動と注意点を解説

はじめに

C言語において、初期化されていない(未初期化の)配列を使用した場合、プログラムは正常に実行されるのでしょうか。本記事では、未初期化配列へのアクセス時に起こる現象を、サンプルコードと実行結果を交えて詳しく解説します。

結論:未初期化配列を使うとどうなるか

  • 未初期化の配列を使用しても、コンパイルエラーや実行時エラーは一切発生しません

  • しかし、配列が未初期化のままだと、予測不能な値(不定値・ゴミ値) が出力される可能性があります。

  • そのため、バグやセキュリティ上の問題を防ぐ観点からも、配列の要素は必ずデフォルト値で初期化しておく ことが重要です。

サンプルプログラム1

以下は、初期化の状態が異なる3つの配列(a、b、c)にアクセスして、それぞれの要素を表示するC言語プログラムです。

#include <stdio.h>
int main(void){
    int a[4];
    int b[4] = {1};
    int c[4] = {1,2,3,4};
    int i; //ループカウンタ

    //各配列の全要素を表示
    printf("\nArray a:\n");
    for( i=0; i<4; i++ )
        printf("arr[%d]: %d\n",i,a[i]);

    printf("\nArray b:\n");
    for( i=0; i<4; i++)
        printf("arr[%d]: %d\n",i,b[i]);

    printf("\nArray c:\n");
    for( i=0; i<4; i++ )
        printf("arr[%d]: %d\n",i, c[i]);

    return 0;
}

実行結果

このプログラムを実行すると、次のような結果が出力されます。

Array a:
arr[0]: 4195872
arr[1]: 0
arr[2]: 4195408
arr[3]: 0

Array b:
arr[0]: 1
arr[1]: 0
arr[2]: 0
arr[3]: 0

Array c:
arr[0]: 1
arr[1]: 2
arr[2]: 3
arr[3]: 4

結果のポイント

  • 配列a(完全に未初期化):メモリ上に残っていた無意味な値(ゴミ値)がそのまま表示されています。

  • 配列b(先頭だけ {1} で初期化):明示的に初期化された arr[0] は 1 ですが、残りの要素は自動的に 0 で初期化 されています。これは、初期化子を1つでも指定すると、残りの要素がゼロで埋められるというC言語の仕様によるものです。

  • 配列c(すべて初期化済み):意図どおり 1〜4 が正しく表示されています。

注意点

配列を初期化せずに使用した場合、デフォルトではゴミ値(不定値)が出力され、エラーメッセージは一切表示されません。これはローカル変数がスタック領域に確保され、そこに以前使われていたデータが残っているためです。つまり、プログラムは「一見正常に動いている」ように見えても、実際には未定義動作(UB: Undefined Behavior)を引き起こしている危険があります。

続いて、別のパターンでも同様の挙動を確認してみましょう。

サンプルプログラム2

#include <stdio.h>
int main(void){
    int A[4];
    int B[4];
    int C[4] = {1,2};
    int i; //ループカウンタ

    //各配列の全要素を表示
    printf("\nArray A:\n");
    for( i=0; i<4; i++ )
        printf("arr[%d]: %d\n",i,A[i]);

    printf("\nArray B:\n");
    for( i=0; i<4; i++)
        printf("arr[%d]: %d\n",i,B[i]);

    printf("\nArray C:\n");
    for( i=0; i<4; i++ )
        printf("arr[%d]: %d\n",i, C[i]);

    return 0;
}

実行結果

このプログラムを実行すると、次のような結果になります。

Array A:
arr[0]: 4195856
arr[1]: 0
arr[2]: 4195408
arr[3]: 0

Array B:
arr[0]: -915120393
arr[1]: 32767
arr[2]: 0
arr[3]: 0

Array C:
arr[0]: 1
arr[1]: 2
arr[2]: 0
arr[3]: 0

まとめ

  • 未初期化の配列にアクセスしてもエラーは出ませんが、出力される値は毎回異なる不定値になる可能性があり、極めて不安定です。

  • 部分的に初期化した場合は、残りの要素が自動的に 0 で埋められます。

  • 安全なコードを書くためには、宣言時に {0} などで全要素を明示的に初期化する習慣をつけましょう。

  1. C言語の文字操作を徹底解説!宣言方法と入出力関数の使い方

    Cプログラミング言語において、文字(character)は英大文字(A〜Z)、英小文字(a〜z)、数字(0〜9)、空白(ホワイトスペース)、または特殊記号のいずれかとして扱われます。文字の宣言方法C言語で文字型変数を宣言する際は、char 型を使用します。文字定数はシングルクォーテーション( )で囲んで指定します。char a = A; /* 文字定数を使用した宣言 */このように宣言することで、変数 a に1文字分のデータを格納できます。文字入出力関数の種類C言語には、文字を入出力するための関数がいくつか用意されています。代表的なものは以下の3組です。scanf / printf: 書式指定

  2. C言語のポインタ入門!宣言・初期化から配列アクセスの実例まで徹底解説

    ポインタ(pointer)とは、他の変数のメモリアドレスを格納するための変数です。C言語においてポインタは、メモリを直接操作したり、関数間でデータを効率的にやり取りしたりするために欠かせない重要な概念です。 ポインタの宣言・初期化とアクセス まず、次のような通常の整数変数の宣言を見てみましょう。 int qty = 179; 変数qtyには値「179」が格納されると同時に、メモリ上のどこかにその格納場所(アドレス)が割り当てられます。 ポインタの宣言 int *p; 「p」はポインタ変数であり、別の整数型(int)変数のアドレスを保持します。変数名の前にアスタリスク(*)を付けることで、「こ