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

时间:2017-06-10 22:15:48

标签: c string

以下代码昨天编译好了一段时间,开始在一点上发出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;
}

2 个答案:

答案 0 :(得分:4)

你的猜测是完全正确的:

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

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

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

答案 1 :(得分:1)

基本上,当您想要从C

中的函数接收字符串时,您有两种方法
  1. 调用者分配缓冲区(静态或动态)并将其作为指针和大小传递给被调用者。 Callee将数据写入缓冲区。如果它适合,它将成功作为状态返回。如果不合适,则返回错误。在这种情况下,您可以决定缓冲区是否未触及,或者它包含适合大小的所有数据。您可以选择更适合您的方式,只需为将来的用户(包括您将来)正确记录。
  2. Callee动态分配缓冲区,填充缓冲区并返回指向缓冲区的指针。调用者必须释放内存以避免内存泄漏。
  3. 在您的情况下,zeckendorf()函数可以确定字符串需要多少内存。第一个Fibonacci数小于参数的索引确定结果的长度。添加1以终止零,您知道需要分配多少内存。

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

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

    char *ans = NULL;
    
    maxfib(n, &index, &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库函数使用第一种或第三种方法。