Oma*_*mar 10 c++ arrays string char strcpy
当你去删除指针时,第一个例子不起作用.当我添加null终止符时,程序要么挂起,要么没有它我得到:
Debug Assertion Failed Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) 来自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;
Run Code Online (Sandbox Code Playgroud)
那么当我使用双引号而不是strcpy时会发生什么?它们都会完美地完成字符串,调试器不会显示任何不同的内容.
unw*_*ind 14
当你这样做
char *at = ...;
at = "hello";
Run Code Online (Sandbox Code Playgroud)
您基本上用new[]静态常量字符串的地址覆盖指针值(即,为您分配的内存的地址).这意味着当您稍后删除该内存时,您将传递delete之前未返回的指针new.
这是一件坏事.
在C和C++中,对指针的赋值通常不会对指向的内存执行任何操作,它们会更改指针本身.如果你习惯于字符串更像是"一等公民"的语言,这可能会让人感到困惑.
此外,delete[]如果您使用,您应该使用new[].
sbi*_*sbi 12
因为a char*不是字符串.它只是一个指向某个角色的指针,其惯例是可能有更多的角色要遵循,而在最后一个角色之后有一个角色'\0'.
C中的字符串文字(因此在C++中)就像"abc"是一个字符数组,编译器默默地添加一个'\0'.将数组分配给指针时,该数组会以静默方式将指针转换为第一个元素.结果是
at = "tw";
Run Code Online (Sandbox Code Playgroud)
意味着,指针at被赋予字符串文字中第一个字符的地址"tw".这样,它就会失去旧的价值.由于这是动态分配的字符数组的地址,因此您正在泄漏此数组.
当您稍后分配给at现在指向的数组中的字符时,您将为字符串文字中的某个字符分配新值.这是调用未定义的行为,程序挂起或立即崩溃可能是您执行此操作时可能发生的最佳情况.(在许多平台上,您正在写入只读内存.)
后来你传递at给delete[](而不是delete,因为你打电话new[],而不是new).在这样做时,您传递字符串文字的地址,而不是分配的字符数组.当然,这会弄乱堆管理器.(VC的运行时库在调试模式下捕获它.)
std::strcpy另一方面,将字符串中的字符串从一个数组复制到另一个数组.不会更改任何指针,只会复制内存块.之后指向目标数组的指针仍然指向目标数组,只有该数组中的数据已更改.
让我补充一点:作为C++的初学者,你应该使用std::string而不是C字符串.这为你做了所有肮脏的工作,并且具有理智的语义.
有三件事要理解:
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.
Run Code Online (Sandbox Code Playgroud)
关于修改只读内存的注意事项:
此外,您永远不应该修改字符串文字.也就是说,永远不应该这样做:
char *at = "hello";
at[2] = '\0';
Run Code Online (Sandbox Code Playgroud)
字符串文字的内存必须是只读的,如果更改它,结果将由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;
}
Run Code Online (Sandbox Code Playgroud)