【问题标题】:Why does the following C program give a bus error?为什么下面的 C 程序会给出总线错误?
【发布时间】:2011-05-27 16:53:43
【问题描述】:

我认为这是第一个失败的 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;
}

【问题讨论】:

  • 下一次,不要不知所措:您可以使用任何调试器准确找出无效访问发生的位置。或者更好的是,使用 valgrind,它可以检测无效访问,即使它们不会使您的程序崩溃。
  • 那么,valgrind 是 gdb 功能的超集吗?我正在考虑是否最好在 gdb 或 valgrind 中进行速成课程。
  • valgrind 和 gdb 是互补的。 valgrind 是非交互式的,但在内存访问方面比 gdb 更加挑剔。
  • 对您的代码进行切向编辑:strsep 在功能上等同于 strtok,但具有更好的调用约定。这是一个非标准的 BSD 主义,但除了 Windows 之外的每个人都有,可惜 C99 发明了strtok_r 而不是捡起它。
  • strsep 在存在多个连续分隔符的情况下具有明显不同的语义。

标签: c strtok bus-error


【解决方案1】:

有2个问题:

  1. str 设为char[] 类型。 GCC 给出警告foo.cpp:5: warning: deprecated conversion from string constant to ‘char*’,表示这是一个有问题的行。

  2. 您的第二个 strtok() 调用应将 NULL 作为其第一个参数。请参阅docs

生成的工作代码是:

#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))。关于如何获得它的任何建议?
  • 他收到该警告是因为他将您的代码编译为 C++ 而不是 C。-Wwrite-strings 的道德等价物在 C++ 中默认启用。
【解决方案2】:

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

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

【讨论】:

  • 对不起,是的,我在随后的调用中使用了 NULL,但是当我将它修剪下来以便粘贴时,我错过了那部分。
【解决方案3】:

字符串文字应该分配给 const char*,因为修改它们是未定义的行为。我很确定 strtok 修改了它的论点,这可以解释你看到的坏事。

【讨论】:

  • 是的,你完全正确。 strtok() 修改其输入字符串
  • 你是对的:strtok 修改了它的第一个参数。由于遗留原因,支持将字符串文字分配给非常量 char*,但不应在新代码中完成。
  • 对于 GCC,我相信 -Wwrite-strings(不包含在 -Wall 中)会在您尝试执行此操作时收到编译器警告。当然,如果您的代码并非都是 const 正确的,那么您最终也可能会在这里收到一些虚假警告,例如当将字符串文字传递给您自己的函数时,该函数不会修改其参数,而是声明为 f(char *) 而不是 f(const char *)
  • @Jefromi - 它也不包含在-Wextra 中,这让我感到惊讶,尽管可能是出于您所说的原因。现在我必须更改我的默认警告级别...
  • 它不在-Wall 也不在-Wextra 中,因为要使字符串文字的所有使用都正确,尤其是在旧代码中,这可能是一个巨大的工作量,而且您实际发现错误的几率非常低。
猜你喜欢
  • 2022-11-16
  • 2020-04-27
  • 2011-09-27
  • 2011-03-25
  • 1970-01-01
  • 1970-01-01
  • 2014-03-31
  • 2021-05-26
相关资源
最近更新 更多