strtok – char数组与char指针
可能重复:
strtok不接受:char * str
使用strtok
函数时,使用char *
而不是char []
导致分段错误。
这运行正常:
char string[] = "hello world"; char *result = strtok(string, " ");
这会导致分段错误:
char *string = "hello world"; char *result = strtok(string, " ");
任何人都能解释导致这种行为差异的原因吗?
char string[] = "hello world";
此行将string
初始化为足够大的字符数组(在本例中为char[12]
)。 它将这些字符复制到您的本地数组中,就像您已经写出来一样
char string[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0' };
另一行:
char* string = "hello world";
不初始化本地数组,它只是初始化一个本地指针。 允许编译器将其设置为指向您不允许更改的数组的指针,就像代码一样
const char literal_string[] = "hello world"; char* string = (char*) literal_string;
C允许这个没有演员的原因主要是让古代代码继续编译。 您应该假装源代码中字符串文字的类型是const char[]
,它可以转换为const char*
,但绝不会将其转换为char*
。
在第二个例子中:
char *string = "hello world"; char *result = strtok(string, " ");
指针string
指向一个字符串文字,无法修改(如strtok()
希望的那样)。
你可以做一些事情:
char *string = strdup("hello world"); char *result = strtok(string, " ");
以便string
指向文字的可修改副本。
strtok
修改你传递给它的字符串(或尝试无论如何)。 在第一个代码中,您将已初始化的数组的地址传递给特定值 – 但由于它是一个正常的char数组,因此允许修改它。
在第二个代码中,您传递的是字符串文字的地址。 尝试修改字符串文字会产生未定义的行为。
在第二种情况( char *
)中,字符串位于只读存储器中。 正确类型的字符串常量是const char *
,如果您使用该类型来声明变量,那么当您尝试修改它时,编译器会收到警告。 由于历史原因,您可以使用字符串常量初始化char *
类型的变量,即使它们无法修改。 (有些编译器允许您关闭此历史许可证,例如使用gcc的-Wwrite-strings
。)
第一种情况创建一个(非常量)char数组,该数组足以容纳字符串并使用字符串的内容对其进行初始化。 第二种情况创建一个char指针并将其初始化为指向字符串文字,该文字可能存储在只读存储器中。
由于strtok想要修改你传递它的参数所指向的内存,后一种情况会导致未定义的行为(你传入一个指向(const)字符串文字的指针),所以它崩溃了它崩溃了
因为第二个声明一个指针(可以改变)到一个常量字符串……
因此,根据您的编译器/平台/ OS /内存映射…“hello world”字符串将存储为常量(在嵌入式系统中,它可能存储在ROM中)并尝试修改它将导致该错误。