我希望有一个函数接收字符串作为参数并更改字符串的符号
char *strChanger(char *str)
。
我试图像这样实现它:
char *strChanger(char *str) {
if(str[0] != '\0') {
str[0] = 'a';
}
return str;
}
在程序中它应该看起来像char *newstr = strChanger("hi");
但是当我尝试更改字符串中的字符时,程序会崩溃。
我做了一些实验并发现:
// Works fine
char str[] = "hi";
str[0] = 'a';
// Crashes
char *str = "hi";
str[0] = 'a';
我不明白其中的区别。为什么第二个代码块不起作用?
答案 0 :(得分:3)
因为修改字符串文字是undefined behavior - 在您的情况下会导致程序崩溃。
在第二个示例中,您传递字符串文字direclty并尝试对其进行更改。用char *newstr = strChanger("hi")
来表达。
实际上char *str = "hi";
基本上使str
指向字符串文字。更具体地说,string literal is an array被转换为指向第一个元素的指针,然后被分配给str
。然后你试图修改它 - 这是未定义的行为。
在第一种情况下,它的副本是可修改的,你可以对它进行更改,然后传递它并且它可以工作。您正在声明一个char数组并使用字符串文字的内容对其进行初始化。
如果您已定义POSIX "strdup"
,那么您可以执行此操作
char *newstr = strChanger(strdup("hi"));
但是再次在strChanger
内部,您需要检查传递的值 - strdup
可能会返回NULL
,以防它无法分配内存并为您提供复制的字符串。在使用这样的某个时刻后,你将不得不释放记忆 - free(newstr)
。
来自字符串文字
下的标准6.4.5p7如果这些数组的元素具有适当的值,则未指定这些数组是否相同。 如果程序试图修改此类数组,则行为未定义。
初始化下的6.7.9p14
字符类型数组可以由字符串文字或UTF-8字符串文字初始化,可选择用大括号括起来。 字符串文字的连续字节(如果有空间或数组大小未知,则包括终止空字符)初始化数组的元素。