首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >中止陷阱:c中数组的6错误

中止陷阱:c中数组的6错误
EN

Stack Overflow用户
提问于 2017-06-10 22:15:47
回答 2查看 448关注 0票数 0

下面的代码昨天编译得很好,有一段时间开始给出abort trap: 6错误,然后又正常工作了一段时间,然后又开始给出同样的错误。我所查到的所有答案都涉及固定长度的字符串。我在编程方面不是很有经验,所以对于为什么会发生这种情况,我们表示感谢。(代码用于计算Zeckendorf表示。)

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

代码语言:javascript
复制
#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;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-06-10 23:24:14

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

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

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

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

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

代码语言:javascript
复制
char *ans = NULL;

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

代码语言:javascript
复制
if(ans==NULL) {
    ans=malloc(index+1);
}

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

在这两种情况下,都记得将终止\0写到缓冲区。

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

代码语言:javascript
复制
static char ans[20];

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

代码语言:javascript
复制
char *a,*b;
a=zeckendorf(10);
b=zeckendorf(15);
printf("%s\n",a);
printf("%s\n",b);

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

代码语言:javascript
复制
a=zeckendorf(10);
printf("%s\n",a);
b=zeckendorf(15);
printf("%s\n",b);

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

票数 1
EN

Stack Overflow用户

发布于 2017-06-10 22:21:41

你的猜测是非常正确的:

代码语言:javascript
复制
char *ans = "";  // I'm guessing the error is coming from here

这使得ans指向一个字符的只读数组,该数组的唯一元素是字符串终止符。试图附加到这将超出界限,并给您未定义的行为。

一种解决方案是对字符串进行动态分配内存,如果事先不知道大小,则需要重新分配来增加大小。如果您这样做,不要忘记为字符串终止符添加空间,并在完成之后添加到释放记忆

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44478579

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档