ポインタを使用してヒープに動的メモリを割り当てる場合、
char *buffer_heap = new char[15];
メモリ内では次のように表されます。
ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««þþþ
なぜ最後にýýýý««««««««þþþの代わりにNULL終了文字がないのですか?
ポインタを使用してヒープに動的メモリを割り当てる場合、
char *buffer_heap = new char[15];
メモリ内では次のように表されます。
ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««þþþ
なぜ最後にýýýý««««««««þþþの代わりにNULL終了文字がないのですか?
Í はバイト 0xCD で、Windows デバッグ アロケータが 15 バイトのメモリに書き込み、初期化されていないヒープ メモリであることを示します。初期化されていないスタックは 0xCC になります。メモリを読み取って予期せずこの値を取得した場合、「うーん、おそらくこれを初期化するのを忘れた」と考えることができるという考えです。また、それをポインターとして読み取って逆参照すると、Windows はプロセスをクラッシュさせますが、初期化されていないバッファーがランダムまたは任意の値で満たされている場合、まぐれによって有効なポインターが取得され、コードがすべての原因になる可能性があります。トラブルの種類。C++ は、初期化されていないメモリが保持する値を示しません。また、非デバッグ アロケータは、割り当てごとに特別な値でメモリを埋める時間を無駄にしません。
この後に 4 バイトの ý (バイト 0xFD) が続きます。これは、Windows デバッグ アロケーターがバッファーの末尾にある範囲外の領域を示すために使用します。デバッガーでこのような領域に書き込みを行っていることに気付いた場合、「うーん、おそらくここでバッファーをオーバーランした」と考えることができるという考えです。また、バッファが解放されたときに値が変更された場合、メモリ アロケータは、コードが間違っていることを警告できます。
« はバイト 0xAB、þ は 0xFE です。おそらく、これらは目印としても意図されています (これらはもっともらしいポインターやオフセットではないため、ヒープ構造の一部を形成しません)。それらが何を意味するのかはわかりませんが、おそらく 0xFD のようなより多くのガード データです。
最後に、15 バイトのバッファの末尾から 16 番目のバイト (つまり、先頭から数えて 31 番目のバイト) の 0 バイトを見つけたと思います。
Windowsを使用していることに言及せずに「C++」として質問すると、これがC++の動作であることを示唆しています。そうではなく、特定のコンパイラ オプションやリンクされた dll を使用して、C++ の 1 つの実装がどのように動作するかです。C++ では、バッファの最後を超えて読み取ることは許可されていません。Microsoft は親切に対応し、クラッシュしたり悪化したりせずに済むようにしています。
そのメモリを初期化していません。あなたはすでにそこにあったものを見ているだけです...
初期化する必要があります。組み込み型は、デフォルトのコンストラクターを明示的に呼び出すことにより、ゼロに初期化できます。
char *b = new char[15]();
すべてのCスタイルの文字列は文字のシーケンスとして表されますが、文字のすべてのシーケンスが文字列であるとは限りません。
\ 0は通常、文字列リテラルを直接割り当てる場合、または文字列リテラルを自分で追加する場合に使用されます。そして、その配列を\0を考慮した関数を持つ文字列として扱う場合にのみ意味があります。
メモリを割り当てるだけで初期化しない場合は、ランダムなものでいっぱいになります。そこに0がある場合とない場合があります。次のステップで、意味のあるものをそこに配置する必要があります。それを文字列にするかどうかはあなた次第です。
char
はネイティブタイプであるため、初期化されていません。それがC++のやり方です(これはCの遺産です)。
それを受け入れて、0で自分で終了します。
char *buffer_heap = new char[15];
*buffer_heap = '\0';
または、バッファ全体を初期化する場合:
std::fill(buffer, buffer + 15, 0);
初期化されたタイプを割り当てた場合にのみ初期化されます。それ以外の場合、そこに意味のある値が必要な場合は、自分でそれらを記述する必要があります。
一方、より良い答えは、そもそもこれを行うべきではないということです。存在することを忘れてnew[]
、振り返らないでください。
Linux 上の GNU C++ (g++) では、このプログラムはすぐに終了します。
#include <algorithm>
#include <iterator>
#include <vector>
#include <cstddef>
#include <cstdlib>
#include <iostream>
namespace {
class rand_functor {
public:
int operator ()() const { return ::std::rand(); }
};
}
int main()
{
using ::std::cout;
using ::std::vector;
using ::std::ostream_iterator;
using ::std::generate;
using ::std::equal;
using ::std::copy;
char *tmp = new char[1000];
// This just fills a bunch of memory with random stuff, then deallocates it
// in the hopes of making a match more likely.
generate(tmp, tmp+1000, rand_functor());
delete[] tmp;
vector<char *> smalls;
smalls.push_back(new char[15]);
do {
smalls.push_back(new char[15]);
} while (equal(smalls[0], smalls[0]+15, smalls[smalls.size() - 1]));
cout << " In one allocation I got: [";
copy(smalls[0], smalls[0]+15, ostream_iterator<char>(cout));
cout << "]\nAnd in another allocation I got: [";
copy(smalls[smalls.size() - 1], smalls[smalls.size() - 1]+15,
ostream_iterator<char>(cout));
cout << "]\n";
cout << "It took " << smalls.size() << " allocations to find a non-matching one.\n";
return 0;
}