私が試したとき
char bla[32] = "foobar";
int i;
putchar(bla[i]);
とstrlen(bla) < i < 32
、bla[i]
いつものよう\0
です。しかし、これは実際には未定義の動作ではなく、回避する必要がありますか?
私が試したとき
char bla[32] = "foobar";
int i;
putchar(bla[i]);
とstrlen(bla) < i < 32
、bla[i]
いつものよう\0
です。しかし、これは実際には未定義の動作ではなく、回避する必要がありますか?
C99 標準のセクション 6.7.8 のパラグラフ 21 には、次のように記載されています。
集合体の要素またはメンバーよりもブレースで囲まれたリスト内の初期化子が少ない場合、または配列内の要素よりも既知のサイズの配列を初期化するために使用される文字列リテラル内の文字が少ない場合、集合体の残りの部分は静的ストレージ期間を持つオブジェクトと同じように暗黙的に初期化されます。
そしてパラグラフ10は、静的算術型(charを含む)がゼロに初期化されると述べています。
それに基づいて、文字列リテラルを初期化子として使用する場合、配列の残りの部分がゼロに初期化されることを期待する必要があります。
C89仕様、セクション8.7「初期化」:
配列のサイズが固定されている場合、初期化子の数は配列のメンバーの数を超えてはなりません。数が少ない場合、末尾のメンバーは0で初期化されます。
したがって、使用法では、末尾の文字はゼロで初期化されます。
C 言語は、初期化に関してはオール オア ナッシングの原則に従います。オブジェクトが完全に初期化されていないか、完全に初期化されています。後者は、オブジェクト全体を初期化するのに必要な数よりも少ない初期化子を指定すると、オブジェクトの残りの部分がコンパイラによって暗黙的にゼロ初期化されることを意味します。
これは、すべての集計タイプに適用されます。あなたの場合、たまたま文字列リテラルで初期化された文字配列です。この場合、例えば、
int a[100] = { 1 };
int
最初の配列が で初期化1
され、残りが に設定された100 の配列が得られ0
ます。
これは明確に定義された動作であり、実際には機能だと思います。配列内の 1 つの要素を初期化する限り、またはstruct
明示的に初期化されていない残りのすべての要素が に初期化され0
ます。
それが未定義の振る舞いであるという事実は、それが何でもできることを意味します。それは毎回同じことをするかもしれません、しかし行われることは誰の推測でもあります。
これはコンパイラの「機能」ではなく、十分に文書化された動作です。C プログラミング言語は、初期化されていない変数の値を保証しません。したがって、i 値が何であるかを推測しているだけで、プロセスや Windows プラットフォームに属していないメモリに簡単にアクセスできます。たとえば、これによりアクセス違反例外が発生します。詳細については、 http://en.wikipedia.org/wiki/Uninitialized_variableを参照してください。
配列の初期化されていない部分の内容は、それが配置されている場所 (つまり、どのデータ セグメント) によって異なります。スタック上にある場合、初期化されていない要素はランダムな値です。通常、グローバル スコープの配列の場合、初期内容も未定義です。スペシケータが提供されている場合static
、コンパイラはプログラムの開始時にその内容をゼロで初期化します。
この初期化されていない部分へのアクセスは禁止されておらず、これは未定義の動作を想定していませんが、結果は未定義になる可能性があります。bla[i]
ランダムな値またはセグメンテーション違反の例外があるため、 ifへのアクセスもi > sizeof(bla)
未定義の動作ではありません。