Stephen Prata による C++ Primer Plus を読んでいます。彼は次の例を挙げています。
char dog[8] = { 'b', 'e', 'a', 'u', 'x', ' ', 'I', 'I'}; // not a string!
char cat[8] = {'f', 'a', 't', 'e', 's', 's', 'a', '\0'}; // a string!
コメント付き:
これらの配列は両方とも char の配列ですが、2 番目のみが文字列です。null 文字は、C スタイルの文字列で基本的な役割を果たします。たとえば、C++ には、cout で使用されるものを含め、文字列を処理する多くの関数があります。それらはすべて、ヌル文字に到達するまで文字列を文字単位で処理することによって機能します。前の例の cat のようなナイス文字列を表示するように cout に指示すると、最初の 7 文字が表示され、null 文字が検出されて停止します。しかし、前の例の犬の配列 (文字列ではない) を表示するよう cout に指示するほど不謹慎な場合、cout は配列内の 8 文字を出力し、メモリをバイト単位で行進し続け、各バイトをnull 文字に到達するまで、印刷する文字。ヌル文字は、実際にはゼロに設定されたバイトであるため、記憶によく見られる傾向がありますが、通常、損傷はすぐに抑えられます。ただし、文字列以外の文字配列を文字列として扱うべきではありません。
ここで、変数をグローバルに宣言すると、次のようになります。
#include <iostream>
using namespace std;
char a[8] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};
char b[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
int main(void)
{
cout << a << endl;
cout << b << endl;
return 0;
}
出力は次のようになります。
abcdefgh12345678
12345678
したがって、実際には、cout は「メモリをバイト単位で行進し続けます」が、2 番目の文字配列の最後までのみです。char 配列の任意の組み合わせでも同じことが起こります。他のすべてのアドレスが 0 に初期化されていると考えているため、cout が停止します。これは本当ですか?私が次のようなことをした場合:
for (int i = 0; i < 100; ++i)
{
cout << *(&a + i) << endl;
}
出力でほとんど空のスペースが得られますが (おそらく 95% など)、どこでもではありません。
ただし、次のように、char 配列を少し短く宣言するとします。
char a[3] = {'a', 'b', 'c'};
char b[3] = {'1', '2', '3'};
他のすべてを同じに保つと、次の出力が得られます。
abc
123
現在、cout は最初の char 配列を通過することさえありません。2 番目の配列は言うまでもありません。なぜこうなった?最初のシナリオと同様に、メモリアドレスを確認しましたが、それらは連続しています。例えば、
cout << &a << endl;
cout << &b << endl;
与える
003B903C
003B9040
この場合、なぜ動作が異なるのでしょうか? 最初の char 配列を超えて読み取らないのはなぜですか?
最後に、main 内で変数を宣言すると、Prata によって提案された動作が得られます。つまり、null 文字に到達する前に、多くのがらくたが出力されます。
最初のケースでは、char 配列がヒープ上で宣言され、これが 0 に初期化されていると推測しています (しかし、どこでもそうではないのはなぜですか?)。
これらの例では、Visual Studio 2010 を使用しています。