字符*str=”之间的差异;“字符串”;和char str[]=";字符串“;?
在编写一个简单函数以从字符串中删除特定字符时,我遇到了一个奇怪的问题:字符*str=”之间的差异;“字符串”;和char str[]=";字符串“;?,c,arrays,string,pointers,stack,C,Arrays,String,Pointers,Stack,在编写一个简单函数以从字符串中删除特定字符时,我遇到了一个奇怪的问题: 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)
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;
}
我不明白为什么第二次测试失败了?
在我看来,它就像第一个符号char*ptr=“string”
相当于这个:charptr[]=“string”代码>
不是吗?严格地说,char*ptr
的声明只保证指向字符类型的指针。字符串构成已编译应用程序的代码段的一部分并不罕见,某些操作系统会将其设置为只读。问题在于,您正在假设预定义字符串的性质(即它是可写的),而事实上,您自己从未为该字符串显式创建内存。编译器和操作系统的某些实现可能会允许您执行您尝试执行的操作
另一方面,根据定义,char test[]
的声明实际上为堆栈上的整个字符数组分配可读写内存。这两个声明不同
char ptr[]=“字符串”
声明大小为7
的字符数组,并使用字符
s
、t
、r
、i
、n
、g
和\0
对其进行初始化。允许您修改此数组的内容
char*ptr=“string”
将ptr
声明为字符指针,并使用只读的字符串literal地址“string”
对其进行初始化。修改字符串文字是一种未定义的行为。您所看到的(seg故障)是未定义行为的一种表现。据我记忆所及
char ptr[] = "string";
在堆栈上创建“string”
的副本,因此此副本是可变的
形式
char *ptr = "string";
只是向后兼容
const char *ptr = "string";
而且你不允许(就未定义的行为而言)修改它的内容。
编译器可以将这些字符串放在内存的只读部分。char*test=“string test”
错误,它应该是const char*
。这段代码编译只是因为向后兼容的原因。const char*
所指向的内存是只读内存,无论何时尝试写入,它都会调用未定义的行为。另一方面,chartest[]=“string test”
在堆栈上创建一个可写字符数组。这与您可以写入的任何其他常规局部变量一样。回答得好@codaddict
另外,sizeof(ptr)
将为不同的声明提供不同的结果
第一个是数组声明,它将返回数组的长度,包括终止的空字符
第二个,char*ptr=“长文本…”
将返回指针的长度,通常为4或8
char *str = strdup("test");
str[0] = 'r';
是正确的代码并创建可变字符串。str在堆中被分配了一个内存,值“test”填入其中。和sizeof(ptr)对于不同的声明也会给出不同的结果。第一个将返回数组的长度,包括终止的空字符。第二个将返回指针的长度,通常为4或8。第二个位置也可以更改ptr的内容。但是内容是指向文字的指针,而不是字符。+1,很好的答案。了解char*ptr=“string”代码>ptr可以指向其他对象,因此可以在指向的内容中进行“更改”,但是字符“string”
是一个文本,不能更改。性能问题也值得一提。每次变量进入作用域时,声明初始化的自动数组变量将填充整个数组内容。当变量进入作用域时,声明初始化的自动指针变量只需分配指针(单字写入)。如果字符串很长或者经常输入块(就像循环的每次迭代),那么差异可能非常显著@实际上,sizeof(ptr)
不是数组的长度,除非ptr
声明为字符数组。如果ptr
被定义为一个包含3个元素的整数数组,sizeof(ptr)
将返回每个元素的sizeof(int)
之和。我不会说这是错误的。您可能希望以后让test
指向一个可修改的字符串,并保留一个标志(在另一个变量中),指示是否已将其替换为可修改的内容。尽管如此,在大多数情况下,使用const
there.Hem可能是一种很好的做法。因此,每次执行该函数时,都会分配5个字节?关于此主题的非常好的文章:阅读: