40

次の場合を考えてみましょう。

#include<stdio.h>
int main()
{
    char A[5];
    scanf("%s",A);
    printf("%s",A);
}

私の質問は、charA[5]に2文字しか含まれていないかどうかです。「ab」と言ってから、、とA[0]='a'言いA[1]='b'ますA[2]='\0'。しかし、入力が「abcde」'\0'である場合、その場合はどこにありますか。A[5]含まれ'\0'ますか?はいの場合、なぜですか? sizeof(A)答えとして常に5を返します。次に、配列がいっぱいになったときに、カウントされない余分なバイトが予約され'\0'sizeof()いますか?

4

8 に答える 8

60

4文字を超える文字を入力すると、余分な文字とnullターミネータが配列の末尾の外側に書き込まれ、配列に属していないメモリが上書きされます。これはバッファオーバーフローです。

Cは、所有していないメモリを壊すことを防ぎません。これにより、未定義の動作が発生します。プログラムは何でも実行できます。クラッシュしたり、他の変数を黙ってゴミ箱に捨てたり、混乱を招いたり、無害になったり、その他のことをしたりする可能性があります。プログラムが確実に動作するか、確実にクラッシュするという保証はないことに注意してください。すぐにクラッシュすることに頼ることさえできません。

これは、なぜscanf("%s")危険であり、決して使用してはならないのかを示す良い例です。アレイのサイズがわからないため、安全に使用する方法がありません。代わりに、scanfを避け、 fgets()などのより安全なものを使用してください。

fgets()は、ストリームから最大で1つ小さいサイズの文字を読み込み、sが指すバッファーにそれらを格納します。EOFまたは改行の後で読み取りが停止します。改行が読み取られると、バッファに格納されます。終了ヌルバイト('\ 0')は、バッファーの最後の文字の後に格納されます。

例:

if (fgets(A, sizeof A, stdin) == NULL) {
    /* error reading input */
}

厄介なことに、fgets()は、配列の最後に末尾の改行文字('\ n')を残します。したがって、コードで削除することもできます。

size_t length = strlen(A);
if (A[length - 1] == '\n') {
    A[length - 1] = '\0';
}

うーん。単純な(しかし壊れた)ものscanf("%s")は7行の怪物に変わりました。そして、それはその日の2番目のレッスンです。CはI/Oと文字列の処理が得意ではありません。それはできて、安全にできますが、Cはずっと蹴って悲鳴を上げます。

于 2012-08-18T15:55:34.757 に答える
10

すでに指摘したように、N文字を正しく格納するには、長さN+1の配列を定義/割り当てる必要があります。scanfが読み取る文字数を制限することができます。あなたの例では、次のようになります。

scanf("%4s", A);

最大を読み取るために。stdinからの4文字。

于 2012-08-18T16:01:17.060 に答える
5

cの文字配列は、メモリブロックへのポインタにすぎません。文字用に5バイトを予約するようにコンパイラーに指示すると、予約されます。そこに5バイト以上入れようとすると、予約した5バイトを超えてメモリが上書きされます。

これが、cが深刻なセキュリティ実装を持つことができる理由です。あなたはあなたが4文字+\0だけを書くつもりであることを知っている必要があります。Cを使用すると、プログラムがクラッシュするまでメモリを上書きできます。

charfoo[5]を文字列とは考えないでください。5バイトを置く場所と考えてください。nullなしで5文字を格納できますが、strcpyを使用せずにmemcpy(otherCharArray、foo、5)を実行する必要があることを覚えておく必要があります。また、otherCharArrayにはこれらの5バイトに十分なスペースがあることも知っておく必要があります。

于 2012-08-18T16:27:57.783 に答える
4

未定義の動作になってしまいます。

あなたが言うように、のサイズは常に5になるので、A5以上を読み取ると、メモリに書き込もうとしますが、変更することは想定されていません。charscanf

いいえ、\0シンボル用に予約されたスペース/文字はありません。

于 2012-08-18T15:54:37.217 に答える
4

長さが4文字を超える文字列scanfは、配列の境界を超えて書き込みを行います。結果として生じる動作は未定義であり、運が良ければ、プログラムがクラッシュします。

scanf配列に格納するには長すぎる文字列の書き込みを停止しない理由がわからない場合は、5であることを知るA方法がないためです。配列をパラメータとしてC関数に渡すと、配列は減衰します。配列の最初の要素を指すポインタへ。したがって、関数内で配列のサイズを照会する方法はありません。scanfsizeof(A)

配列に読み込まれる文字数を制限するには、

scanf("%4s", A);
于 2012-08-18T16:01:35.393 に答える
3

予約されている文字はないため、配列全体をnullで終了できないポイントまで埋めないように注意する必要があります。Char関数はnullターミネータに依存しており、説明した状況に陥った場合、Char関数から悲惨な結果が得られます。

表示される多くのCコードは、strncpyなどの関数の「n」導関数を使用します。そのマニュアルページから、次のように読むことができます。

strcpy()およびstrncpy()関数はs1を返します。stpcpy()およびstpncpy()関数は、s1の終了する `\0'文字へのポインタを返します。stpncpy()がs1をNUL文字で終了しない場合、代わりにs1 [n]へのポインタを返します(これは必ずしも有効なメモリ位置を参照しているわけではありません)。

strlenは、ヌル文字に依存して文字バッファーの長さを決定します。その文字が欠落していると、誤った結果が得られます。

于 2012-08-18T15:53:15.850 に答える
-1

ヌル文字は配列の終了に使用されます。これは配列の最後にあり、配列がその時点で終了していることを示しています。配列は自動的に最後の文字をヌル文字にするので、コンパイラは配列が終了したことを簡単に理解できます。

于 2014-02-07T16:51:08.030 に答える
-3

\ 0はターミネータ演算子であり、配列がいっぱいになると終了します。配列がいっぱいでない場合は、配列の最後から読み取る文字列を入力すると、\0が配列の最後になります。

于 2017-08-01T05:35:01.927 に答える