14

可能重复:
strtok 不接受:char *str

使用该strtok函数时,使用 achar *而不是 achar []会导致分段错误。

这运行正常:

char string[] = "hello world";
char *result = strtok(string, " ");

这会导致分段错误:

char *string = "hello world";
char *result = strtok(string, " ");

谁能解释导致这种行为差异的原因?

4

6 回答 6

34
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*.

于 2010-11-03T18:48:47.623 回答
14

在第二个例子中:

char *string = "hello world";
char *result = strtok(string, " ");

指针string指向一个字符串文字,它不能被修改(strtok()就像想要做的那样)。

您可以按照以下方式做一些事情:

char *string = strdup("hello world");
char *result = strtok(string, " ");

所以它string指向文字的可修改副本。

于 2010-11-03T18:43:45.050 回答
4

strtok修改您传递给它的字符串(或无论如何尝试)。在您的第一个代码中,您传递了一个已初始化为特定值的数组的地址——但由于它是一个普通的 char 数组,因此允许对其进行修改。

在第二个代码中,您传递的是字符串文字的地址。尝试修改字符串文字会产生未定义的行为。

于 2010-11-03T18:45:06.820 回答
3

在第二种情况 ( char *) 中,字符串位于只读内存中。字符串常量的正确类型是const char *,如果您使用该类型声明变量,当您尝试修改它时,编译器会警告您。由于历史原因,您可以使用字符串常量来初始化类型变量,char *即使它们不能被修改。(一些编译器允许你关闭这个历史性的许可证,例如使用 gcc 的-Wwrite-strings。)

于 2010-11-03T18:43:57.983 回答
0

第一种情况创建一个(非 const)char 数组,该数组大到足以容纳字符串并使用字符串的内容对其进行初始化。第二种情况创建一个 char 指针并将其初始化为指向可能存储在只读内存中的字符串文字。

由于 strtok 想要修改您传递的参数所指向的内存,后一种情况会导致未定义的行为(您正在传递一个指向 (const) 字符串文字的指针),因此它崩溃也就不足为奇了

于 2010-11-03T18:43:56.333 回答
0

因为第二个声明了一个指向常量字符串的指针(可以更改)......

因此,取决于您的编译器/平台/操作系统/内存映射......“hello world”字符串将作为常量存储(在嵌入式系统中,它可能存储在 ROM 中)并尝试修改它会导致该错误。

于 2010-11-03T18:44:24.807 回答