printf("y = %s\n", y);
この場合、未定義の動作です。言い換えれば、あなたは幸運でした。おそらく、NUL にヒットする前に目に見えない文字を印刷したのかもしれません。スタックの配置のために配列の後にゼロがあるのかもしれません。星が正しいのかもしれません。
普段は「UBだから触るな」とは言いませんが、妙に言わざるを得ない感じです。
ほら、これがあなたのプログラムです:
#include <stdio.h>
int main() {
char y[4] = {'a', 'a', 'a', 'a'};
char z[4] = {'b', 'b', 'b'};
printf("y = %s\n", y);
printf("z = %s\n", z);
}
次に、特別なコンパイラ フラグを使用してコンパイルします。
$ cc -O3 so15727258.c -o so15727258 -fstack-protector-all -Wall
そしてそれを実行します:
$ ./so15727258
y = aaaa?>A??0F
z = bbb
おっと、ハハ、それはまったくのゴミです。さらに良いことに、スタック プロテクターのためにランダム化されたガベージであるため、(単純に) 決定論的ではありません。ウー!
まだ納得できませんか?特別なコンパイラ フラグは奇妙すぎましたか? 試す
#include <stdio.h>
int bar() {
char x[4096];
}
int foo() {
char y[4] = {'a', 'a', 'a', 'a'};
char z[4] = {'b', 'b', 'b'};
printf("y = %s\n", y);
printf("z = %s\n", z);
}
int main() {
bar();
foo();
}
それをコンパイルします。
$ cc so15727258.c -o so15727258 -Wall
そしてそれを実行します:
$ ./so15727258
y = aaaa?????ic?
z = bbb
それでも総ゴミ!覚えておいてください。これらの例はすべて説明用です。もちろん、これは未定義の動作なので、まったく異なる結果が得られる可能性があり、ここに戻って「しかし XYZ は機能する」と言ってください。それがまさに未定義の振る舞いの定義です。