【问题标题】:Segmentation Fault in CC中的分段错误
【发布时间】:2014-02-22 02:43:34
【问题描述】:

我正在尝试生成一个将值“val”附加到数组“ia”末尾的代码,但是我不断遇到分段错误。谁能帮我指出错误的来源可能来自哪里?

下面是我为任务 4 编写的测试代码。

intarr_result_t intarr_push( intarr_t* ia, int val )
{


    if (ia ==0)
    {
        return INTARR_BADARRAY;
    }

    //making space for newarr
    ia = realloc(ia, (ia->len + 1) * sizeof(intarr_t));

    //copying data from ia and val to newarr
    ia->data[ia->len - 1] = val;

    //ia = newarr;
    if (ia == 0)
    {
        return INTARR_BADALLOC;
    }
    else
    {
        return INTARR_OK;
    }


}

使用以下自定义头文件:

/* Structure type that encapsulates our safe int array. */
typedef struct {
  int* data;
  unsigned int len;
} intarr_t;

/* A type for returning status codes */
typedef enum {
  INTARR_OK,
  INTARR_BADARRAY,
  INTARR_BADINDEX,
  INTARR_BADALLOC,
  INTARR_NOTFOUND
} intarr_result_t;

/* TASK 4 */

// Append val to the end of ia (allocating space for it). If
// successful, return INTARR_OK, otherwise return
// INTARR_BADALLOC. If ia is null, return INTARR_BADARRAY.
intarr_result_t intarr_push( intarr_t* ia, int val );

// If the array is not empty, remove the value with the highest index
// from the array, and, if i is non-null, set *i to the removed value,
// then return INTARR_OK. If the array is empty, leave *i unmodified
// and return INTARR_BADINDEX. If ia is null, return INTARR_BADARRAY.
intarr_result_t intarr_pop( intarr_t* ia, int* i );

【问题讨论】:

  • 在分配给ia->data之前,您从未初始化ia。
  • 您对ia->data 的分配也是错误的。你不能创建这样的数组,你必须调用malloc() 然后设置每个元素。
  • 有效ia = realloc(<undefined value>, (<undefined value> + 1) * sizeof(intarr_t));。
  • 你需要回到书本上,学习如何在 C 中使用数组和指针。
  • 对不起,我忘了提到我在之前的任务中使用了 malloc to ia,我认为这与此有关……我更新了我的代码,使它看起来更接近我的目标提交到班级的服务器。

标签: c arrays segmentation-fault


【解决方案1】:

问题是你reallocia,而应该重新分配ia->data。 ia 本身的大小是恒定的,即sizeof(intarr_t)。正确的代码应该是:

ia->data = realloc(ia->data, (ia->len + 1) * sizeof(*ia->data));
/* ... */
if (ia->data == 0)
/* ... */
++ia->len;

【讨论】:

    【解决方案2】:

    你可以试试这个

    /* Structure type that encapsulates our safe int array. */
    typedef struct {
      int len;
      int data[];
    } intarr_t;
    
    intarr_result_t intarr_push(intarr_t** ia, int val )
    {
        intarr_t *tmp = *ia;
        if (tmp ==0)
        {
            return INTARR_BADARRAY;
        }
    
        tmp = realloc(tmp, sizeof(intarr_t) + sizeof(int) * (tmp->len + 1));
        if (!tmp) return INTARR_BADALLOC;
    
        /* copying data from ia and val to newarr */
        tmp->data[tmp->len++] = val;
        *ia = tmp;
    
       return INTARR_OK;
    }
    
    int main(void)
    {
        intarr_result_t res;
        intarr_t *arr = malloc(sizeof(intarr_t));
    
        if (!arr) return 1;
        res = intarr_push(&arr, 10);
        /* TODO: Something with result */
        res = intarr_push(&arr, 20);
        /* .... */
        return 0;
     }
    

    【讨论】:

    • 在每次推送时有意更改数组对象地址,使得在不同对象或线程之间共享此类变量变得困难。
    • “realloc 函数返回一个指向新对象的指针(它可能与指向旧对象的指针具有相同的值),如果无法分配新对象,则返回一个空指针。”这就是标准对 realloc 的规定,如果你想使用它,那么你必须期望地址发生变化,程序才能可靠地工作。
    • 我的意思是,如果我有两个对象,每个对象都存储自己指向数组的指针,并且其中一个对象决定推送一个值,而 realloc 返回不同的地址,那么第二个对象将包含无效指针这最终会导致问题。另一方面,重新分配 data 成员不会改变数组对象本身的地址。
    • @mike.dld 是的,这听起来是个好主意,嗯...我不知道为什么我把它弄得这么复杂:-p
    • 顺便说一句,如果想要报告错误而不丢失旧数据,在重新分配期间使用临时变量实际上是一个好主意:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    相关资源
    最近更新 更多