10

最初の例は、ポインタを削除しようとすると機能しません。ヌルターミネータを追加するとプログラムがハングするか、ヌルターミネータがないと次のようになります。

Debug Assertion Failed Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)VisualStudio2008から

//Won't work when deleting pointer:
    char *at = new char [3];
    at = "tw"; //   <-- not sure what's going on here that strcpy does differently
    at[2] = '\0'; // <-- causes program to hang
    delete at;

//Works fine when deleting pointer:
    char *at = new char [3];
    strcpy(at,"t");
    at[1] = 'w';
    at[2] = '\0';
    delete at;

では、strcpyの代わりに二重引用符を使用するとどうなりますか?どちらも文字列を完全に削除し、デバッガーは何も変わりません。

4

9 に答える 9

14

あなたがするとき

char *at = ...;

at = "hello";

基本的に、ポインタ値(つまり、によって割り当てられたメモリnew[]のアドレス)を静的定数文字列のアドレスで上書きします。これは、後でそのdeleteメモリを削除するときに、以前はによって返されなかったポインタを渡すことを意味しますnew

それは悪いことです。

CおよびC++では、ポインタへの割り当ては通常、ポイントされているメモリに対して何も行わず、ポインタ自体を変更します。文字列が「第一級市民」である言語に慣れている場合、これは混乱を招く可能性があります。

また、を使用したdelete[]場合はを使用する必要がありますnew[]

于 2009-10-16T12:34:40.563 に答える
12

achar*は文字列ではないからです。これは、ある文字への単なるポインタであり、従う文字がさらにある可能性があり、最後の文字の後には。が存在するという規則があります'\0'

C(したがってC ++)のような文字列リテラルは"abc"文字の配列であり、コンパイラはサイレントに。を追加し'\0'ます。配列をポインターに割り当てると、配列はポインターを最初の要素にサイレントに変換します。結果はそれです

at = "tw";

つまり、ポインタatには文字列リテラルの最初の文字のアドレスが割り当てられます"tw"。これにより、古い値が失われます。これは動的に割り当てられた文字配列のアドレスであったため、この配列をリークしています。

後で配列内の文字に割り当てると、at文字列リテラル内のある文字に新しい値が割り当てられます。これは未定義の動作を引き起こし、プログラムがすぐにハングまたはクラッシュするのは、これを行ったときに発生する可能性のある最善の方法です。(多くのプラットフォームでは、読み取り専用メモリに書き込んでいます。)

後であなたはatに渡りますdelete[](そしてあなたが呼んだので、ではなく、ではありませんdeletenew[]new)。その際、割り当てられた文字配列ではなく、文字列リテラルのアドレスを渡します。もちろん、これはヒープマネージャを台無しにします。(VCのランタイムライブラリは、デバッグモードでこれをキャッチします。)

std::strcpy一方、ある配列から別の配列に文字列を1文字ずつコピーします。ポインタは変更されず、メモリの一部のみがコピーされます。ターゲット配列へのポインタは、その後もターゲット配列を指し、その配列内のデータのみが変更されます。

これを追加しましょう:C ++の初心者として、std::stringC文字列ではなくを使用する必要があります。それはあなたのためにすべての汚い仕事をし、正しいセマンティクスを持っています。

于 2009-10-16T12:46:01.283 に答える
9

理解すべきことが3つあります。

1)char *at;は単なるポインタ変数です。
ポインタ変数は、単にメモリアドレスを保持していることを意味します。

2)new char[3]ヒープに割り当てられたメモリの開始アドレスを返します。

3)"hello"文字列リテラルのアドレスを返します。

char *at = new char [3];
//at now contains the address of the memory allocated on the heap


at = "hello";
//at now contains the address of the static string. 
// (and by the way you just created a 3 byte memory leak)


delete[] at; 
//WOOPS!!!! you can't do that because you aren't deleting 
// the original 3 chars anymore which were allocated on the heap!
//Since at contains the string literal's memory address you're 
// trying to delete the string literal.

読み取り専用メモリの変更に関する注意:

また、文字列リテラルを変更しないでください。つまり、これは絶対に行わないでください。

char *at = "hello";
at[2] = '\0'; 

文字列リテラルのメモリは読み取り専用である必要があり、それを変更すると、結果はC++言語で定義されません。

C ++を使用しているので:

C ++を使用しているため、std::string代わりに型の使用を検討してください。

#include <string>

using namespace std;

int main(int argc, char **argv)
{
  string s = "hello";
  s += " world!";

  //s now contains "hello world!"

  s = "goodbye!";

  //Everything is still valid, and s contains "goodbye!"


  //No need to cleanup s. 

  return 0;
}
于 2009-10-16T12:33:50.263 に答える
5

使用することを忘れないでください

delete []

[]で何かを割り当てるときはいつでも。

于 2009-10-16T12:34:14.787 に答える
4

ポインタはアドレスを保持します。ポインタの=演算子は、保持されているアドレスを変更します。

at = "tw";

配列「tw」(文字twを保持するためにコンパイラーによって作成された配列)を指すようになり、newで作成した配列を指しなくなります。ファイルに作成されます。

at[2] = '\0';

complier配列の最後にNULLを追加します。

于 2009-10-16T12:35:21.960 に答える
0

最初の例では、で値を変更し、2番目の例では、ポイントでの値を変更しています。二重引用符で囲まれた文字列にchar*を割り当てると、静的constポインタに割り当てられます。

特に、最初の例では、現在、メモリ内の別の場所を指しています。

于 2009-10-16T12:33:42.700 に答える
0

最初の例では、メモリを割り当て、「at」変数でそれをポイントしています。あなたがするとき

at = "tw"

char*を定数文字列に効果的に再ポイントします。これにより、メモリがリークします。「at」を削除し続けると、スタックメモリを削除しようとしています。

strcpyは各文字を調べ、それらの値を割り当てた新しいメモリにコピーします。これは、ディープコピーとも呼ばれます。

于 2009-10-16T12:36:41.027 に答える
0

最初の例では、メモリリークが発生しています。

変数atは、文字列自体ではなく、メモリアドレスへのポインタです。のアドレスをポインタに割り当てると、で"tw"取得した元のアドレスが失われますnewatで割り当てなかったアドレスを指すようになったnewため、割り当てることができませんdelete

ポインタを整数と考えると、おそらくもっと意味があります。説明のために、アドレスとして任意の番号を割り当てました。

char *at = new char[3];    // 0x1000
at = "tw";                 // 0x2000
at[2] = '\0';              // set char at 0x2002 to 0
delete at;                 // delete 0x2000 (whoops, didn't allocate that!)
于 2009-10-16T12:43:01.517 に答える
0

あなたは2つのことを間違えます:ポインタが何か違うものを指すようにすること(これは割り当てが行うことです)とポインタが指す場所にいくつかのデータをコピーすることです。

at = "tw";

このコードはat、読み取り専用メモリのどこかに作成されたリテラル「tw」を指し示します。それに書き込もうとするのは未定義の動作です。

char *at = new char [3];
strcpy(at,"t");

このコードは、3文字にメモリを割り当て、メモリのatこの部分をポイントして(1行目)、。が指すメモリにデータをコピーしatます。

また、で割り当てられたメモリは、ではなく、new[]割り当てを解除する必要があることを忘れないでくださいdelete[]delete

ポインタについてもっと学ぶことをお勧めします。この議論はこれをカバーしています。

于 2009-10-16T12:49:12.443 に答える