-4

C 文字配列にはヌル ターミネータが必要なため、次のコードは 4 つの aといくつかの文字化け文字を出力します。

char y[4] = {'a', 'a', 'a', 'a'};
printf("y = %s\n", y);

出力:

y = aaaa�

ただし、次のコードは文字化けを生成しません。

char y[4] = {'a', 'a', 'a', 'a'};
char z[4] = {'b', 'b', 'b'};

printf("y = %s\n", y); 
printf("z = %s\n", z);

出力:

y = aaaa
z = bbb

zの 4 番目の文字がnull ターミネータで自動的に初期化されることを理解しています。また、私はそれを推測しyzメモリ内で隣同士に割り当てられます。

しかし、この場合、C はどのように 4 a s を正しく出力し、前者では正しく出力しないのでしょうか? 次のバイトがすでに別の変数に割り当てられていることを識別しているので、印刷を停止する必要がありますか?

4

3 に答える 3

5

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 は機能する」と言ってください。それがまさに未定義の振る舞いの定義です。

于 2013-03-31T07:11:39.510 に答える
2

あなたのプログラムは、動作しているように見えても未定義の動作を示します。'\0'ほとんどの文字列操作と印刷では、文字列をで終了する必要があります。

場合によってはまだ機能しているように見えるのはなぜなのか疑問に思っている場合は、オブジェクト間 (または隣接するオブジェクト) にゼロバイトがあり、文字列ターミネータとして機能している可能性があります。

于 2013-03-31T07:13:12.713 に答える
0

運が良かっただけではありません...テストできます。配列の直後のバイトのメモリ内容を出力します。約束できるよ 目を閉じてゼロだ...

于 2013-03-31T07:17:33.763 に答える