strtok分段错误

use*_*954 12 c strtok segmentation-fault

我试图理解为什么下面的代码片段给出了分段错误:

void tokenize(char* line)
{
   char* cmd = strtok(line," ");

   while (cmd != NULL)
   {
        printf ("%s\n",cmd);
        cmd = strtok(NULL, " ");
   } 
}

int main(void)
{
   tokenize("this is a test");
}
Run Code Online (Sandbox Code Playgroud)

我知道strtok()实际上并没有对字符串文字进行标记,但在这种情况下,line直接指向"this is a test"内部为数组的字符串char.是否有任何令牌化line而不将其复制到数组中?

Kei*_*son 21

问题是您正在尝试修改字符串文字.这样做会导致程序的行为未定义.

说你不允许修改字符串文字是一个过于简单化.说字符串文字const是不正确的; 他们不是.

警告:随后进行挖掘.

字符串文字"this is a test"的类型为表达式char[15](长度为14,终止时为1 '\0').在大多数情况下,包括这个,这样的表达式被隐式转换为指向数组的第一个元素的指针char*.

尝试修改由字符串文字引用的数组的行为是未定义的 - 不是因为它const(它不是),而是因为C标准明确指出它是未定义的.

有些编译器可能允许你逃避这一点.您的代码可能实际上修改了与文字对应的静态数组(这可能会在以后引起很大的混淆).

但是,大多数现代编译器都会将数组存储在只读存储器中 - 而不是物理ROM,而是存储在一个受虚拟内存系统修改的内存区域.尝试修改此类内存的结果通常是分段错误和程序崩溃.

那么为什么不是字符串文字const呢?既然你真的不应该尝试修改它们,那肯定会有意义 - 而C++确实会创建字符串文字const.原因是历史性的.该const关键字在1989 ANSI C标准引入之前不存在(尽管之前可能由某些编译器实现).因此,ANSI之前的程序可能如下所示:

#include <stdio.h>

print_string(s)
char *s;
{
    printf("%s\n", s);
}

main()
{
    print_string("Hello, world");
}
Run Code Online (Sandbox Code Playgroud)

没有办法强制执行print_string不允许修改指向的字符串的事实s.const在ANSI C中创建字符串文字会破坏现有代码,ANSI C委员会非常努力避免这样做.从那以后,没有很好的机会对语言进行这样的改变.(C++的设计者,主要是Bjarne Stroustrup,并不关心与C的向后兼容性.)

  • 下降投票者愿意解释吗? (2认同)

Set*_*gie 5

正如您所说,您无法修改字符串文字,但事实却是这样strtok。你必须做

char str[] = "this is a test";
tokenize(str);
Run Code Online (Sandbox Code Playgroud)

这将创建数组str并使用 对其进行初始化this is a test\0,并将指向它的指针传递给tokenize


Ada*_*cin 5

尝试标记编译时常量字符串会导致分段错误,这是有充分理由的:常量字符串位于只读内存中。

C 编译器将编译时常量字符串烘焙到可执行文件中,操作系统将它们加载到只读内存中(*nix ELF 文件中的 .rodata)。由于该内存被标记为只读,并且由于 strtok 写入您传递给其中的字符串,因此您会因写入只读内存而出现分段错误。