为什么指向 char 数组的指针必须需要 strcpy 才能将字符分配给其数组,而双引号分配不起作用?

发布于 2024-08-08 04:26:06 字数 621 浏览 7 评论 0原文

当你去删除指针时,第一个例子不起作用。当我添加空终止符时,程序要么挂起,要么没有它,我得到:

Debug Assertion Failed Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) from Visual Studio 2008

//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 的?它们都会完美地计算出字符串,并且调试器不会显示任何不同的内容。

The first example does not work when you go to delete the pointer. The program either hangs when I add the null terminator or without it I get:

Debug Assertion Failed Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) from Visual Studio 2008

//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;

So what's going on when I use double quotes instead of strcpy? Both of them will cout the string perfectly and debugger does not show anything different.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

凌乱心跳 2024-08-15 04:26:06

当你这样做时,

char *at = ...;

at = "hello";

你基本上用静态常量字符串的地址覆盖了指针值(即由new[]为你分配的内存地址)。这意味着当您稍后删除内存时,您将传递delete一个先前未由new返回的指针。

这是一件坏事。

在 C 和 C++ 中,对指针的赋值通常不会对所指向的内存执行任何操作,它们会更改指针本身。如果您习惯了字符串更多是“一等公民”的语言,这可能会令人困惑。

另外,如果您使用了 new[],则应该使用 delete[]

When you do

char *at = ...;

at = "hello";

You're basically overwriting the pointer value (i.e., the address of the memory allocated for you by new[]) with the address of a static constant string. This means that when you later delete that memory, you're passing delete a pointer not previously returned by new.

That is a bad thing to be doing.

In C and C++, assignments to pointers typically don't do anything to the memory being pointed at, they change the pointer itself. This might be confusing if you're used to a language where strings are more of "first class citizens".

Also, you should use delete[] if you used new[].

睫毛溺水了 2024-08-15 04:26:06

因为 char* 不是字符串。它只是一个指向某个字符的指针,约定可能有更多字符跟随,并且在最后一个字符之后有一个 '\0'

C 中的字符串文字(因此在 C++ 中)如 "abc" 只是一个字符数组,编译器会默默地添加一个 '\0'。当您将数组分配给指针时,数组会默默地将指针转换为第一个元素。结果意味着

at = "tw";

,指针 at 被分配了字符串文字 "tw" 中第一个字符的地址。这样一来,它就失去了原有的价值。由于这是动态分配的字符数组的地址,因此您正在泄漏该数组。

当您稍后分配给 at 现在指向的数组中的字符时,您正在为字符串文字中的某个字符分配一个新值。这会调用未定义的行为,并且程序立即挂起或崩溃可能是您执行此操作时可能发生的最好情况。 (在许多平台上,您正在写入只读内存。)

稍后,您将 at 传递给 delete[] (以及 不是删除,因为您调用了new[],而不是new)。这样做时,您将字符串文字的地址传递给它,而不是分配的字符数组。当然,这会弄乱堆管理器。 (VC 的运行时库在调试模式下捕获此情况。)

另一方面,std::strcpy 将字符串逐个字符地从一个数组复制到另一个数组。不会更改指针,只会复制内存片段。之后指向目标数组的指针仍然指向目标数组,只是该数组中的数据发生了变化。

让我补充一下:作为 C++ 初学者,您应该使用 std::string,而不是 C 字符串。它为您完成了所有脏活,并且具有合理的语义。

Because a char* isn't a string. It's just a pointer to some character, with the convention that there might be more characters to follow and that after the last one there is a '\0'.

A string literal in C (and thus in C++) like "abc" is just an array of characters, with the compiler silently adding a '\0'. When you assign an array to a pointer, the array silently converts a pointer to the first element. The result is that

at = "tw";

means, the pointer at is assigned the address of the first character in the string literal "tw". By this, it will lose its old value. Since this was the address of a dynamically allocated character array, you are leaking this array.

When you later assign to a character in the array at now points to, you are assigning a new value to some character in the string literal. That's invoking undefined behavior and the program hanging or crashing immediately is probably the best that could happen to you when you do this. (On many platforms you're writing to read-only memory doing so.)

Later you pass at to delete[] (and not delete, since you called new[], not new). In doing so, you pass it the address of the string literal, instead of the allocated character array. This will, of course, mess up the heap manager. (VC's runtime library catches this in Debug mode.)

std::strcpy, on the other hand, copies a string character by character from one array to another array. No pointers will be changed, only pieces of memory are copied. The pointer to the target array still points to the target array afterwards, only the data in that array has changed.

Let me add this: As a beginner in C++, you should use std::string, rather than C strings. That does all the dirty work for you and has sane semantics.

几度春秋 2024-08-15 04:26:06

需要理解三件事:

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;
}

There are 3 things to understand:

1) char *at; is just a pointer variable.
A pointer variable simply means that it holds a memory address.

2) new char[3] returns the starting address of the memory allocated on the heap.

3) "hello" returns the address of the string literal.

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.

A note about modifying read only memory:

Also you should never be modifying a string literal. I.e. this should never be done:

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

The memory for string literals must be read only and if you change it, the results are undefined by the C++ language.

Since you're using C++:

Since you're using C++ please consider using the std::string type instead.

#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;
}
不爱素颜 2024-08-15 04:26:06

请不要忘记使用。

delete []

每当您使用 [] 分配某些内容时,

Do not forget to use

delete []

whenever you are allocating something with [].

荒芜了季节 2024-08-15 04:26:06

指针保存一个地址。指针的 = 运算符会更改所保存的地址。

at = "tw";

使 at 指向数组“tw”(编译器创建的用于保存字符 tw 的数组),它不再指向您用 new 创建的数组。文件中创建。

at[2] = '\0';

将 NULL 添加到编译器数组的末尾。

A pointer holds an address. The = operator for a pointer changes the address held.

at = "tw";

Makes at point to the array "tw" (an array created by the compiler to hold the characters tw), it no longer points to the array you created with new. created in the file.

at[2] = '\0';

Adds a NULL to the end of the complier array.

尸血腥色 2024-08-15 04:26:06

在第一个示例中,您正在更改 at 的值,在第二个示例中,您正在更改 at 指向的值。将 char * 分配给双引号字符串会将其分配给静态 const 指针。

特别是,在第一个示例中,现在指向内存中的不同位置。

In the first example you are chaning the value at, in the second you are changing the value of what at points to. Assigning a char * to a double quoted string assigns it to a static const pointer.

In particular, in the first example at now points a different location in memory.

酒与心事 2024-08-15 04:26:06

在第一个示例中,您分配了一些内存并使用“at”变量指向它。当您这样做时,

at = "tw"

您实际上将 char * 重新指向常量字符串。这会导致你泄漏内存。当您继续删除“at”时,您正在尝试删除堆栈内存。

strcpy 遍历每个字符并将它们的值复制到您分配的新内存中。这也称为深层复制。

In your first example you are allocating some memory and pointing to it with the "at" variable. When you do

at = "tw"

you are effectively re-pointing the char * to a constant character string. This causes you to leak memory. When you go on to delete "at" you are attempting to delete stack memory.

strcpy goes through each character and copies their values to the new memory you allocate. This is also known as a deep copy.

浅语花开 2024-08-15 04:26:06

在第一个示例中,您导致了内存泄漏。

您的变量 at 是指向内存地址的指针,而不是字符串本身。当您将“tw”的地址分配给指针时,您就丢失了通过new获得的原始地址。 at 现在指向您未使用 new 分配的地址,因此您无法删除它。

如果您将指针视为整数,它可能会更有意义。为了讨论起见,我分配了任意数字作为地址。

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!)

In the first example, you have caused a memory leak.

Your variable at is a pointer to a memory address, not the string itself. When you assign the address of "tw" to the pointer, you have lost the original address that you got with new. at now points to an address that you did not allocate with new, so you cannot delete it.

If you think of pointers as integers, it will probably make more sense. I've assigned arbitrary numbers as addresses for the sake of discussion.

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!)
梨涡 2024-08-15 04:26:06

您犯了两件事:使指针指向不同的东西(这就是赋值的作用)并将一些数据复制到指针指向的位置。

at = "tw";

此代码使 at 指向在只读内存中某处创建的文字“tw”。尝试写入它是一种未定义的行为。

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

这段代码为三个字符分配内存,并使at指向这部分内存(第1行),然后将一些数据复制到at指向的内存。

请记住,使用 new[] 分配的内存应该使用 delete[] 来释放,而不是 delete

我建议您了解有关指针的更多信息。 此讨论 涵盖了这一点。

You mistake two things: making pointer point to something different (this is what assignment does) and copying some data to a place pointed by pointer.

at = "tw";

this code makes at point to a literal "tw" created somewhere in read-only memory. Trying to write to it is an undefined behaviour.

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

this code allocates memory for three chars and makes at point to this part of memory (line 1) and then copies some data to memory pointed by at.

And remember, that memory allocated with new[] should be deallocated with delete[], not delete

I advice you to learn more about pointers. This discussion covers this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文