【问题标题】:#include <string.h> -> Abort trap: 6?#include <string.h> -> 中止陷阱:6?
【发布时间】:2018-02-16 05:43:41
【问题描述】:

我正在学习 c 编程,但遇到了一些奇怪的事情。

我在搞乱 char 数组/字符串并使用不同的函数。所以我有了这个程序,

#include <stdio.h>
int main(){
    char a[] = {'H','e','y','a','\0'};
    strcat(a,"bro!");
    printf(a);
}

$ gcc -o test.o test.c -Wall
$ ./test.o
Heya bro!
$

按预期工作,但如果我添加

#include <string.h>

一开始,我就明白了

$ gcc -o test.o test.c -Wall
$ ./test.o
Abort: trap 6
$

【问题讨论】:

  • 使用.o 扩展名调用您的可执行文件是一种惯例;用于目标文件,通常不是完整的程序。您的原始代码无法在 C99 或 C11 规则下干净地编译。您的 strcat() 调用调用未定义的行为;你写超出了你的数组的末尾。使用 UB,任何事情都是允许的——崩溃、看起来可以工作、重新格式化您的硬盘。
  • 未定义的行为,你在char a[] 后面吹了,你不幸第一次得到了你想要的结果。使a 足够大以适合串联的字符串数组。
  • 我对这两种不同的行为感到惊讶(我知道 UB 就是 UB),但大多数时候事情是确定性的。如果不包含string.h,编译器会发出对strcat 的调用。但是,如果您包含标头,则可能会发生这种情况,这里就是这种情况,发出的调用不是普通的strcat。在我的机器上,它调用__strcat_chk,它的行为不同并产生中止。

标签: c include string.h


【解决方案1】:

strcat 尝试追加字符,但数组的大小再次不足以容纳它们给您undefined behavior。(在您的情况下,未定义的行为会导致您看到的错误 - 它可能是万一一切正常。)因为strcat试图写超出数组a。而printf的第一个参数应该是格式说明符,如printf("%s",a);

char a[] = {'H','e','y','a','\0'};

这里 a 有 5 个元素。数组的大小是5。你需要一个更大的数组。

char a[9] = {'H','e','y','a','\0'};

如果您让数组容纳 9 个字符,那么它会起作用。

【讨论】:

  • 哦,所以 strcat() 不会为您要附加的字符提供额外的空间。我仍然很困惑为什么当我不包含 string.h 时它会起作用
  • 那只是运气不好。欣赏这些错误的例程何时不起作用,因为一旦您的项目变得更大并且发生奇怪的事情,它们就会很痛苦o.O
  • @PaulMyers 意识到 strcat 不“提供”任何东西,它只是将一个字符串附加到另一个现有字符串,不多也不少。如果没有足够的内存,你就不走运了。由确保有足够的内存。
【解决方案2】:

当您初始化数组并省略维度时,编译器会根据初始化器的数量推断维度。
所以,这句话:

char a[] = {'H','e','y','a','\0'};

等价于:

char a[5] = {'H','e','y','a','\0'};

strcat() 将源字符串的副本附加到目标字符串。它不检查目标缓冲区是否足够大以包含连接的结果字符串。如果目标不够大,无法容纳连接的结果字符串,则会导致未定义的行为,包括它可能执行不正确(崩溃或静默生成不正确的结果),或者它可能完全按照程序员的意图进行。

您应该指定足够大的缓冲区a 的大小以容纳连接的结果字符串。在您的程序中,源字符串bro! 大小为4strcat() 用源字符串的第一个字符覆盖目标null 字符,同时将它们连接起来,并且在形成的新字符串的末尾包含一个空字符。因此,在您的情况下,保存连接的结果字符串所需的最小大小是 9

a 声明为:

char a[9] = {'H','e','y','a','\0'};

应该可以正常工作。

正如 David 建议的(在 cmets 中)而不是 9,您可以采用一些合理大小的缓冲区,例如 5121024(例如 a[512]a[1024])。 它可以帮助您在一定程度上避免问题。但是,您需要注意代码中的缓冲区溢出问题。例如,您可以使用strncat(),它使您可以灵活地指定可以附加到目标字符串中的最大大小。
您可以将要附加的最大字符数指定为 -

(size of destination buffer) - (the length of the destination string) - 1

避免缓冲区溢出。

【讨论】:

  • char a[9] 将适用于当前目的,但内存很便宜。为什么不建议一个合理大小的分配,以提供更大的灵活性?事后你不能调整数组的大小。
  • @DavidBowling:在我的回答中,我已经提到 - “在你的情况下,保存连接的结果字符串所需的最小大小是 9”
  • 是的,我确实看到了。数组中使用的最小尺寸很常见,尤其是对于学习者而言;但这可能会导致麻烦,没有理由小气。我经常将char buffer[1024]char buffer[4096] 与用户输入缓冲区一起使用。这样做不会受到任何惩罚,它有助于避免某些类型的 I/O 问题。我发现提醒学习者可以慷慨分配是很好的,考虑合理的期望比考虑最低需求更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
  • 1970-01-01
  • 2014-12-13
  • 2017-05-11
相关资源
最近更新 更多