4

「C++ Premiere」ブックからC++の文字列に関する例をテストしています。

const int size = 9;
char name1[size];
char name2[size] = "C++owboy";   // 8 characters here

cout << "Howdy! I'm " << name2 << "! What's your name?" << endl;

cin >> name1;  // I input "Qwertyuiop" - 11 chars. It is more than the size of name1 array;

// now I do cout
cout << "Well, your name has " << strlen(name1) << " letters";  // "Your name has 11 letters".
cout << " and is stored in an array of " << size(name1) << " bytes"; // ...stored in an array of 9 bytes.

8 文字 + '\0' 文字だけで 11 文字が配列に格納されるのはどうしてでしょうか? コンパイルすると広くなりますか?または、文字列は別の場所に保存されていますか?

また、私はできません:

const int size = 9;
char name2[size] = "C++owboy_12345";   // assign 14 characters to 9 chars array

しかし、私が上に書いたことを行うことができます:

cin >> name1;   // any length string into an array of smaller size

ここでのトリックは何ですか?NetBeans と Cygwin g++ コンパイラを使用しています。

4

4 に答える 4

9

配列のサイズよりも多くのエントリを配列に書き込むと、未定義の動作が発生します。コンピューターは、そのデータをどこにでも保存することも、まったく保存しないこともあります。

通常、データは、たまたまメモリ内で次に来るものに保存されます。それは、別の変数、命令ストリーム、または椅子の下にある爆弾の制御レジスタである可能性があります。

簡単に言えば、バッファオーバーフローのバグをコーディングしました。そうしないでください。


楽しみのために:未定義の動作は、C++ 標準がコメントしていない動作です。標準では何の制約も課されていないため、何でもかまいません。

ある特定のケースでは、この動作により、私の銀行残高が 10 ドルから 18 億ドルに増加しました: http://ideone.com/35FQW

そのプログラムがそのように振る舞う理由がわかりますか?

于 2012-07-12T15:34:21.903 に答える
5

name1 にはメモリ内のアドレスが与えられます。80 バイトを書き込むと、その場所からメモリに 80 バイト以上が書き込まれます。name1 のアドレス + 20 に格納された変数がある場合、name1 への 80 バイトの書き込みによってそのデータが上書きされます。これは C/C++ での動作と同じです。これらはバッファー オーバーフローと呼ばれ、プログラムのハッキングに使用できます。

于 2012-07-12T15:35:14.800 に答える
4

これは、典型的なバッファ オーバーフローです。これが、入力をバッファに入れる場合、常に入力のサイズをチェックすることになっている理由です。何が起こっているかは次のとおりです。

C++ (および C) では、配列名は配列の最初の要素への単なるポインターです。コンパイラは配列のサイズを認識しており、コンパイル時にいくつかのチェックを行います。ただし、実行時には、それは単に char* として扱われます。

を行ったときcin >> name1、 char* を に渡しましたcincin割り当てられたスペースがどれくらい大きいかはわかりません。あるのはメモリへのポインタだけです。したがって、十分なスペースが割り当てられていると想定し、すべてを書き込み、配列の最後を過ぎます。ここに写真があります:

Bytes   1  2  3  4  5  6  7  8  9  10 11 12 13 14 15
Before  |-----name1 array-------|  |--- other data-|
After   Q  w  e  r  t  y  u  i  o  p  \0 |-er data-|

ご覧のとおり、配列の後に保存された他のデータを上書きしました。この他のデータはジャンクである場合もありますが、重要であり、トリッキーなバグを意味する場合もあります。言うまでもなく、攻撃者はユーザー入力でプログラム メモリを上書きできるため、これはセキュリティ上の脆弱性です。

サイズに関する混乱は、 (null ターミネータ)strlenが見つかるまでバイトをカウントするためです。つまり、10 文字が見つかることを意味します。'\0'一方size(name1)、コンパイラによって提供される配列の実際のサイズを使用します。

これらの問題のため、引数として配列を取る C 関数を見ると、配列サイズも取られます。そうしないと、その大きさを判断する方法がありません。これらの問題を回避するには、std::string などの C++ オブジェクトを使用することをお勧めします。

于 2012-07-12T16:07:11.827 に答える
3

ここにはトリックはありません:)バッファ外のメモリに書き込んでいます。これは未定義の動作です

于 2012-07-12T15:35:06.917 に答える