const char * src = "hello";
呼び出しstrlen(src);
はサイズ5を返します。
今、私はこれを行うと言います:
char* dest = new char[strlen(src)];
strcpy(dest, src);
それはうまくいくはずではないようですが、私がすべてを出力すると、それは正しく見えます。最後にヌルターミネータにスペースを割り当てていないようです...これは正しいですか?ありがとう
ターミネータにスペースを割り当てていないのは正しいですが、これを行わなくても、必ずしもプログラムが失敗するわけではありません。ヒープに関する次の情報を上書きしている可能性があります。または、ヒープマネージャーが割り当てサイズを16バイトの倍数などに切り上げているため、このバグの目に見える影響が必ずしも見られるとは限りません。
Valgrindまたは他のヒープデバッガーでプログラムを実行すると、この問題をより早く検出できる場合があります。
はい、少なくともstrlen(src)+1文字を割り当てる必要があります。
それはうまくいくはずではないようですが、私がすべてを出力すると、それは正しく見えます。
未定義動作の世界へようこそ。これを行うと、何でも起こり得ます。プログラムがクラッシュしたり、コンピューターがクラッシュしたり、コンピューターが爆発したり、悪魔が鼻から飛び出したりする可能性があります。
そして最悪の場合、プログラムは正常に実行され、ある日、誰かが配列に割り当てた文字が少なすぎるために機密データをどこかで上書きしているため、ガベージを吐き出し始めるまで、目立たないように動作しているように見えます。これで、ヒープが破損し、100万マイル離れた場所でセグメンテーション違反が発生します。さらに悪いことに、プログラムが破損したヒープと一緒に楽しく動作し、機能が破損したクレジットカード番号で動作し、大きな問題が発生します。
動作しているように見えても、動作しません。それは未定義動作です。それが何をするか確信が持てないので、それを避けてください、そしてあなたがそれを試みたときにそれが何をするかは大丈夫ですが、別のプラットフォームでは大丈夫ではないかもしれません。
私が読んだ(stackoverflowにあった)最高の説明は次のようになりました:
制限速度が50で、60で運転している場合。運が良ければチケットを受け取れないかもしれませんが、ある日は今日ではないかもしれませんが、明日ではないかもしれませんが、ある日警官があなたを待っています。その日あなたは支払うでしょうそしてあなたは心から支払うでしょう。
誰かがオリジナルを見つけることができれば、私はむしろ彼らが私の説明よりもはるかに雄弁であったことを指摘したいと思います。
strcpy
null で終了する文字と他のすべての文字をコピーします。
したがって、長さhello
+ 1 の 6 をバッファ サイズの 5 にコピーしています。
ただし、ここにはバッファ オーバーフローがあり、自分のものではないメモリを上書きすると、未定義の結果が生じます。
または、dest = strdup(src)を使用することもできます。これにより、文字列に十分なメモリが割り当てられ、ヌルターミネータに1が割り当てられます(Julianoの回答には+1)。
ええ、誰もが要点をカバーしました。失敗する保証はありません。実際には、ヌル ターミネータは通常 0 であり、0 は特定のメモリ アドレスにある非常に一般的な値です。だから、たまたまうまくいくだけです。これをテストするには、一連のメモリを取得し、大量のガベージを書き込み、そこにその文字列を書き込み、それを操作してみます。
とにかく、ここで私が目にする主な問題は、あなたが C について話しているのに、次のコード行があることです。
char* dest = new char[strlen(src)];
これは、標準の C コンパイラではコンパイルされません。C にはキーワードがありませんnew
。それが C++ です。C では、通常、メモリ割り当て関数の 1 つを使用しますmalloc
。私はそれが気の利いたように見えることを知っていますが、実際にはそうではありません.
これが、動作しているように見えるすべての C プログラムで、常に、常に、常にvalgrindを実行する必要がある理由です。