char * str =“STRING”和char str =“STRING”之间的区别?
编写一个简单的函数来从string中删除一个特定的字符时,我遇到了这个奇怪的问题:
void str_remove_chars( char *str, char to_remove) { if(str && to_remove) { char *ptr = str; char *cur = str; while(*ptr != '\0') { if(*ptr != to_remove) { if(ptr != cur) { cur[0] = ptr[0]; } cur++; } ptr++; } cur[0] = '\0'; } } int main() { setbuf(stdout, NULL); { char test[] = "string test"; // stack allocation? printf("Test: %s\n", test); str_remove_chars(test, ' '); // works printf("After: %s\n",test); } { char *test = "string test"; // non-writable? printf("Test: %s\n", test); str_remove_chars(test, ' '); // crash!! printf("After: %s\n",test); } return 0; }
我没有得到的是为什么第二次testing失败? 对我来说,它看起来像第一个符号char *ptr = "string";
相当于这个: char ptr[] = "string";
。
不是这样吗?
这两个声明是不一样的。
char ptr[] = "string";
声明一个大小为7
的char数组,并用字符初始化它
s
, t
, r
, i
, n
, g
和\0
。 你可以修改这个数组的内容。
char *ptr = "string";
将ptr
声明为char指针,并用只读的string文字 "string"
地址初始化它。 修改string文字是未定义的行为 。 你所看到的(seg fault)是未定义行为的一种performanceforms。
严格来说, char *ptr
的声明只能保证你有一个指向字符types的指针。 string形成编译应用程序的代码段的一部分并不less见,这些代码段将被某些操作系统设置为只读。 问题在于,事实上,当你预先定义的string(它是可写的)的性质时,事实上,你从来没有明确地为这个string创build内存。 一些编译器和操作系统的实现可能会让你做你想做的事情。
另一方面,根据定义, char test[]
的声明实际上在这种情况下为堆栈上的整个字符数组分配了可读写的内存。
char *test = "string test";
是错误的,它应该是const char*
。 这个代码编译仅仅是因为后向兼容性的原因。 const char*
指向的内存是一个只读内存,每当你尝试写入内存时,它都会调用未定义的行为。 另一方面, char test[] = "string test"
在堆栈上创build一个可写的字符数组。 这就像你可以写的任何其他的regualr局部variables一样。
就目前我所记得的
char ptr[] = "string";
在堆栈上创build一个"string"
的副本 ,所以这个是可变的。
表格
char *ptr = "string";
只是向后兼容
const char *ptr = "string";
而且你不允许(根据未定义的行为)修改它的内容。 编译器可能会将这些string放在内存的只读部分。
很好的答案@codaddict。
此外, sizeof(ptr)
将为不同的声明提供不同的结果。
第一个数组声明将返回包含终止空字符的数组长度。
第二个, char* ptr = "a long text...";
将返回一个指针的长度,通常是4或8。
char *str = strdup("test"); str[0] = 'r';
是正确的代码,并创build一个可变的string。 str在堆中分配了一个内存,值“test”填充在内存中。