【问题标题】:Abort trap: 6 error with arrays in c中止陷阱:c 中的数组出现 6 个错误
【发布时间】:2017-06-11 07:24:14
【问题描述】:

以下代码昨天编译好一段时间,开始出现abort trap: 6 错误,然后又正常运行了一段时间,又开始出现同样的错误。我查找的所有答案都处理一些固定指定长度的字符串。我在编程方面不是很有经验,因此对于为什么会发生这种情况的任何帮助表示赞赏。 (代码用于计算Zeckendorf representation。)

如果我只是使用printf 来逐个打印数字而不是使用字符串,则代码可以正常工作。

#include <string.h>

// helper function to compute the largest fibonacci number <= n
// this works fine
void maxfib(int n, int *index, int *fib) {
    int fib1 = 0;
    int fib2 = 1;
    int new = fib1 + fib2;
    *index = 2;
    while (new <= n) {
        fib1 = fib2;
        fib2 = new;
        new = fib1 + fib2;
        (*index)++;
        if (new == n) {
            *fib = new;
        }
    }
    *fib = fib2;
    (*index)--;
}

char *zeckendorf(int n) {
    int index;
    int newindex;
    int fib;
    char *ans = "";  // I'm guessing the error is coming from here
    while (n > 0) {
        maxfib(n, &index, &fib);
        n -= fib;
        maxfib(n, &newindex, &fib);
        strcat(ans, "1");
        for (int j = index - 1; j > newindex; j--) {
            strcat(ans, "0");
        }
    }
    return ans;
}

【问题讨论】:

  • 请注意,循环中的if (new == n) { *fib = new; } 没有任何用处,除非您在赋值后添加break;
  • 谢谢。是的,我打算在添加 *fib = fib2; (*index)--; 后删除该部分

标签: c string


【解决方案1】:

你的猜测非常正确:

char *ans = "";  // I'm guessing the error is coming from here

这使得ans 指向一个只读 一个字符 数组,其唯一元素是字符串终止符。尝试附加到 this 会超出范围并给你未定义的行为

一个解决方案是dynamically allocate memory作为字符串,如果你事先不知道大小,那么你需要reallocate来增加大小。如果您这样做,请不要忘记为字符串终止符添加空格,并在完成后添加到free the memory

【讨论】:

  • 不重要的是哪个是 UB,但即使没有尝试越界访问,尝试修改字符串文字也是 UB。
  • 动态分配的替代方案是char ans[32] = "";,它为您提供了足够的空间来存储 64 位整数(您可以将 32 更改为 20 左右,但仍然可以)。
【解决方案2】:

基本上,当您想从 C 中的函数接收字符串时,有两种方法

  1. 调用方分配缓冲区(静态或动态)并将其作为指针和大小传递给被调用方。被调用者将数据写入缓冲区。如果合适,它将成功作为状态返回。如果不适合,则返回错误。您可以决定在这种情况下,要么缓冲区保持不变,要么它包含适合大小的所有数据。您可以选择更适合您的内容,只需为未来的用户(包括将来的您)正确记录它。
  2. 被调用者动态分配缓冲区,填充缓冲区并返回指向缓冲区的指针。调用者必须释放内存以避免内存泄漏。

在您的情况下,zeckendorf() 函数可以确定字符串需要多少内存。第一个斐波那契数小于参数的索引决定了结果的长度。添加 1 以终止零,您就知道需要分配多少内存。

因此,如果您选择第一种方法,则需要将额外的两个参数传递给zeckendorf() 函数:char *bufferint size,并写入ans 的缓冲区instead。你需要有一些标记来知道它是否是while() 循环的第一次迭代。如果是,则在maxfib(n, &amp;index, &amp;fib); 之后检查条件index+1&lt;=size。如果条件为真,您可以继续执行您的功能。如果没有,您可以立即返回错误。

对于第二种方法,将ans 初始化为:

char *ans = NULL;

maxfib(n, &amp;index, &amp;fib);之后添加:

if(ans==NULL) {
    ans=malloc(index+1);
}

然后像你一样继续。从函数返回ans。记住在调用者中调用free(),当不再需要结果以避免内存泄漏时。

在这两种情况下记得将终止符 \0 写入缓冲区。

还有第三种方法。您可以将 ans 声明为:

static char ans[20];

zeckendorf() 内。函数的行为应与第一种方法相同,但缓冲区及其大小已被硬编码。我建议#define BUFSIZE 20 并将变量声明为static char ans[BUFSIZE]; 并在检查可用大小时使用BUFSIZE。请注意,它仅适用于单线程环境。并且每次调用zeckendorf() 都会覆盖之前的结果。考虑以下代码。

char *a,*b;
a=zeckendorf(10);
b=zeckendorf(15);
printf("%s\n",a);
printf("%s\n",b);

zeckendorf() 函数总是返回相同的指针。所以ab 将指向同一个缓冲区,15 的字符串将被存储在其中。因此,您要么需要将结果存储在某处,要么按正确的顺序进行处理:

a=zeckendorf(10);
printf("%s\n",a);
b=zeckendorf(15);
printf("%s\n",b);

根据经验,大多数(如果不是全部)Linux 标准 C 库函数使用第一种或第三种方法。

【讨论】:

  • 谢谢,这很有帮助。
猜你喜欢
  • 1970-01-01
  • 2014-12-13
  • 2017-05-11
  • 2018-01-25
  • 1970-01-01
  • 2015-06-06
相关资源
最近更新 更多