为什么以下C程序会出现总线错误?

6

我认为是第一次调用strtok失败了。我写C已经有一段时间了,但现在有些不知所措。非常感谢。

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
  char *str = "one|two|three";

  char *tok = strtok(str, "|");

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

  return 0;
}

1
下次不要手足无措:您可以使用任何调试器精确定位无效访问发生的位置。或者更好的方法是使用valgrind,即使程序没有崩溃,它也可以检测到无效访问。 - John Zwinck
那么,Valgrind是否是GDB功能的超集?我正在尝试弄清楚是最好进行GDB还是Valgrind的速成课程。 - nc.
valgrind和gdb是互补的。valgrind是非交互式的,但在内存访问方面比gdb更加挑剔。 - zwol
关于你的代码,有一个旁观者的评论:strsep 在功能上等同于 strtok,但具有更好的调用约定。它是一个非标准的 BSD 特性,但除了 Windows 之外,每个人都有它,而 C99 发明了 strtok_r 而没有采用它,这真是遗憾。 - zwol
在存在多个连续分隔符的情况下,“strsep”具有明显不同的语义。 - R.. GitHub STOP HELPING ICE
3个回答

7

字符串字面值应该赋值给const char*,因为修改它们是未定义的行为。我非常确定strtok会修改它的参数,这可以解释你看到的问题。


1
是的,你说得完全正确。strtok()会修改它的输入字符串。 - SiegeX
2
你是正确的:strtok会修改它的第一个参数。将字符串字面值分配给非const char*是出于遗留原因而支持的,但在新代码中不应该这样做。 - John Zwinck
2
使用GCC编译器,我相信-Wwrite-strings(不包括在-Wall中)可以在您尝试进行此操作时获得编译器警告。当然,如果您的代码不是全部正确地使用了const,您可能也会得到一些虚假的警告,例如将字符串字面量传递给您自己的函数时,该函数不修改其参数但声明为f(char*)而不是f(const char*) - Cascabel
@Jefromi - -Wextra 也没有包括它,这让我感到惊讶,尽管可能是你所说的原因。现在我必须更改我的默认警告级别... - Chris Lutz
这不在-Wall-Wextra中,因为使所有字符串字面值的使用正确地使用const可能需要大量工作,特别是在旧代码中,并且您实际上找到错误的几率非常低。 - zwol

2
有2个问题:
1. 将 `str` 的类型更改为 `char[]`。GCC 给出了警告 `foo.cpp:5: warning: deprecated conversion from string constant to ‘char*’`,这表明这是有问题的一行代码。
2. 第二个 `strtok()` 调用应该将其第一个参数设置为 `NULL`。请参阅文档
最终的可运行代码如下:
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
  char str[] = "one|two|three";

  char *tok = strtok(str, "|");

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

  return 0;
}

输出

one
two
three

我实际上没有在GCC中收到那个警告; 它非常干净。 我刚刚尝试了-Wall,但仍然没有看到它(gcc版本4.2.1(Apple Inc. build 5664))。 如何获得它的任何建议? - nc.
他收到了那个警告,是因为他将你的代码编译为C++而不是C。在C++中,默认情况下启用了“-Wwrite-strings”的道德等效项。 - zwol

0

我不确定什么是“总线”错误,但循环内strtok()的第一个参数应该为NULL,如果您想继续解析相同的字符串。

否则,您将继续从相同字符串的开头开始,该字符串在第一次调用strtok()后已被修改。


抱歉,是的,我在后续调用中使用了NULL,但当我将其缩减以进行粘贴时,我错过了那部分。 - nc.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接