2017-09-17 7 views
-1

私はC言語には新しく、文字列に終端の '\ 0'文字を手動で追加する必要があるときはちょっと混乱しています。 (明瞭のために)文字列の長さを計算するために、この機能を考える:なぜC文字列に終端文字 ' 0'を含めるべきか?

int stringLength(char string[]) 
{ 
    int i = 0; 
    while (string[i] != '\0') { 
     i++; 
} 
    return i; 
} 

ヌル終端文字に基づいて文字列の長さを計算します。したがって、次の場合を使用して、 '\ 0'文字の役割は何ですか?

ケース1:

char * stack1 = "stack"; 
printf("WORD %s\n", stack1); 
printf("Length %d\n", stringLength(stack1)); 

プリント:

WORD stack 
Length 5 

ケース2:

char stack2[5] = "stack"; 
printf("WORD %s\n", stack2); 
printf("Length %d\n", stringLength(stack2)); 

プリント:

WORD stack��� 
Length 8 

(これらの結果は毎回変わりますが、決して正確ではありません)。

ケース3:

char stack3[6] = "stack"; 
printf("WORD %s\n", stack3); 
printf("Length %d\n", stringLength(stack3)); 

プリント:

WORD stack 
Length 5 

ケース4:

char stack4[6] = "stack"; 
stack4[5] = '\0'; 
printf("WORD %s\n", stack4); 
printf("Length %d\n", stringLength(stack4)); 

プリント:

WORD stack 
Length 5 

ケース5:

char * stack5 = malloc(sizeof(char) * 5); 
if (stack5 != NULL) { 
    stack5[0] = 's'; 
    stack5[1] = 't'; 
    stack5[2] = 'a'; 
    stack5[3] = 'c'; 
    stack5[4] = 'k'; 
    printf("WORD %s\n", stack5); 
    printf("Length %d\n", stringLength(stack5)); 
} 
free(stack5); 

プリント:

WORD stack 
Length 5 

ケース6:

char * stack6 = malloc(sizeof(char) * 6); 
if (stack6 != NULL) { 
    stack6[0] = 's'; 
    stack6[1] = 't'; 
    stack6[2] = 'a'; 
    stack6[3] = 'c'; 
    stack6[4] = 'k'; 
    stack6[5] = '\0'; 
    printf("WORD %s\n", stack6); 
    printf("Length %d\n", stringLength(stack6)); 
} 
free(stack6); 

プリント:

WORD stack 
Length 5 

つまり、私は例との違いを知りたいのですが1、2、3、4(また、なぜeケース2のrraticな振る舞いで、1と3にヌル終端文字を指定する必要はありません。また、3と4の両方が同じ働きをしていますか?)また、5と6が十分なメモリが割り当てられていなくても(空白文字の各文字に5文字のスロットしか割り当てられていないので、どのように '\ 0'文字、つまり6番目の文字が検出されますか)

大変申し訳ありませんこの途方も長い質問のために、それはちょうど私がどこか他の

+1

非常に広く文字列が配列に格納されている場合は、文字列の終わりを知る方法が必要です。 2つの最も明白な方法は、(1)別個の文字カウントを保持すること、または(2)ある文字(例えば '\ 0')で文字列を終了することです。オプション2は今日もっとも一般的な方法であると思われ、Cは文字列定数を ''\ 0' 'で自動的に終了します。標準のCライブラリは、 ''\ 0' 'で終了する文字列もexpcetします。 –

+0

@TomKarzes: "* Cは文字列定数を '\ 0' *" "文字列 - *リテラル*で自動的に終了します。 – alk

+0

試練とエラーでCを習得しようとしないでください。うつ病を引き起こすことが知られています。 – alk

答えて

3

ケース1の場合、文字列リテラル(読み取り専用メモリ上にある定数)が暗黙的に追加されます(\0が作成されます)。

\0の位置が文字列の終わりを見つけるために使用されているため、stringLength()ファンクションは5を出力します。

2の場合は、5文字の文字列でサイズ5の文字配列を初期化しようとしています。この場合、区切り文字の区切り文字は空白ではありません。文字列に隣接するメモリは何でもかまいません。どこかに\0があるかもしれません。この\0は、あなたが得る奇妙な文字を説明する文字列の最後とみなされます。あなたが与えた出力の場合、この\0は文字列の長さを計算する際に考慮された3文字以上の後にのみ見つかったようです。時間の経過とともにメモリの内容が変化するので、出力が常に同じではない可能性があります。

ケース3の場合、暗黙的に格納される\0を格納するのに十分なスペースを残して、サイズ6の文字配列をサイズ5の文字列で初期化しています。したがって、正常に動作します。 stack4のサイズは6であるので、その最後のインデックスは、あなたは、その古い値自体に変数を上書きしている5ですので

ケース4は

char stack4[5] = '\0'; 

で何も変更は行われません3.場合と同様です。 stack4[5]は、あなたがそれを上書きする前でさえも\0でした。

ケース5では、文字配列を完全に埋めるために、スペースを残さずに\0にします。しかし、文字列を印刷すると、右に印刷されます。私はそれがmalloc()によって割り当てられたメモリに隣接するメモリがちょうど\0の値であるゼロであったためだと思います。しかし、これは未定義の動作であり、信頼されるべきではありません。実際に何が起こるかは、実装に依存します。
calloc()のように割り当てられたメモリは、malloc()で初期化されません。

両方

char str[2]='\0'; 

char str[2]=0; 

ちょうど同じです。

しかし、ゼロには頼ることはできません。動的に割り当てられたメモリは、オペレーティングシステムの動作とセキュリティ上の理由から、デフォルト値としてゼロを持つ可能性があります。詳細については、hereおよびhereを参照してください。

動的に割り当てられるメモリのデフォルト値をゼロにする必要がある場合は、calloc()を使用できます。

ケース6の末尾には\0があり、その他の位置には文字が入ります。適切な文字列は、印刷するときに表示されます。

+3

*「ケース5の場合... malloc()によって割り当てられたメモリに隣接するメモリがゼロだったからだと思います」* - 間違いなく/真になることはできませんでした。 * Undefined Behavior * - メモリ内の次のバイトがちょうど '0'になると何か起こりますが、動作しますが、何が起こるかは保証されません - *と*' malloc'メモリを初期化しません。しかし、あなたがその声明を修正すれば、確かに投票に値すると考えられる全てが、より良くなると考えられます。 –

+1

@ DavidC.Rankin私を修正していただきありがとうございます。私はそれを編集した。 –

+1

これは私の理解に非常に助けてくれました。ありがとうございました。 '\ 0 '文字を追加すると文字列リテラルではないので、' stack6 [5] =' \ 0 '; 'という行を明示的に追加しなかった場合のケース6ではどうなりますか?明示的に文字を追加しているからではないと思う。したがって、 'calloc'ではなく' malloc'を使用すると、終端文字の動作が未定義になります(つまり、以前のメモリ使用量から逃げようとしています)? – Coach

4

これらの特定のインスタンスは常にヌル文字の余地を残しておく必要があります文字列のストレージに良い教訓的な説明を見つけることができなかったのです。いくつかの例では、明示的に長さ5を与えています。そのような場合は、未定義の動作が発生します。

文字列リテラルは常にヌルターミネータを自動的に取得します。 strlenは5の長さを返しますが、実際には6バイトを取ります。

ケース5は、が定義されていないため、のように見えることがあります。メモリ内の文字列に続いて値が0になることはおそらくありますが、それに頼ることはできません。

関連する問題