strtok分段错误

时间:2012-01-22 00:00:56

标签: c segmentation-fault strtok

我试图理解为什么以下代码片段会产生分段错误:

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");
}

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

7 个答案:

答案 0 :(得分:20)

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

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

警告:继续进行挖掘。

字符串文字"this is a test"char[15]类型的表达式(长度为14,终止'\0'为1)。在大多数情况下,包括这个表达式,这样的表达式被隐式转换为指向类型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");
}

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

答案 1 :(得分:2)

正如您所说,您无法修改字符串文字,这是strtok的作用。你必须这样做

char str[] = "this is a test";
tokenize(str);

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

答案 2 :(得分:2)

有一个很好的理由,试图标记化编译时常量字符串会导致分段错误:常量字符串在只读内存中。

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

答案 3 :(得分:1)

我相信你会被殴打......但是“strtok()”本质上是不安全的,容易受到违规行为的影响。

在这里,答案几乎肯定是使用字符串常量。

请改为尝试:

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

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

int main(void)
{
  char buff[80];
  strcpy (buff, "this is a test");
  tokenize(buff);
}

答案 4 :(得分:1)

Strok修改其第一个参数以便对其进行标记。因此,您不能将它传递给文字字符串,因为它的类型为const char *且无法修改,因此未定义的行为。您必须将字符串文字复制到可以修改的char数组中。

答案 5 :(得分:1)

您想通过“创建的内容...... ......内部是char的数组?

"this is a test"内部是char数组的事实根本不会改变任何内容。它仍然是一个字符串文字(所有字符串文字都是不可修改的char数组)。您的strtok仍尝试对字符串文字进行标记。这就是崩溃的原因。

答案 6 :(得分:0)

我只是在尝试使用printf在它变为NULL后打印令牌(cmd)时遇到了Segmentation Fault错误。