3

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 を使用しています。

4

4 に答える 4

5

範囲外のメモリの内容は不確定です。所有していないメモリにアクセスすると、読み取りのためであっても、未定義の動作が発生します。

于 2013-10-14T05:51:35.167 に答える
1

「\0」は、文字列の長さを示すためのソリューションです。文字列の前に値を格納することで、どれくらいの長さかがわかるとしましょう。

しかし、あなたの場合は、意図的に関数を除外した場合であり、通常、コードも区切り文字 (ヌル文字) を検索し続けます。指定されたメモリの境界の背後にあるものは定義されておらず、大きく異なります。gdbを使用したデバッグモードのMingwでは、通常はゼロになり、gdbがないと、ただのジャンクになります...これは私の経験です。ローカルで宣言された変数の場合、それらは通常スタック上にあるため、読んでいるのはおそらくコールスタックです。

于 2013-10-14T21:27:24.787 に答える