【问题标题】:Accessing pointer from array of pointer inside a struct results in segmentation fault从结构内的指针数组访问指针会导致分段错误
【发布时间】:2018-02-20 20:03:04
【问题描述】:

我在尝试从cart_t 中的**addr 变量访问item_t 指针的成员时遇到困难。 cart_t的定义如下:

typedef struct cart_struct {
    item_t **addr;
    int ptr;
    float total;
} cart_t;

我已使用以下代码初始化并添加项目到**addr

cart_t *cart_append_item(cart_t *cart, item_t *item) {
    if (cart == NULL || item == NULL)
        return NULL;

    item_t **new = (item_t**) malloc(sizeof(item_t*) * (cart->ptr + 1));

    if (new == NULL) {
        return NULL;
    }

    int i;
    for (i=0; i<cart->ptr; i++) {
        new[i] = cart->addr[i];
    }

    new[i+1] = item;

    if (cart->addr != NULL) {
        free(cart->addr);
    }

    cart->addr = new;

    cart->ptr += 1;
    printf("price %f, quantity %d, total %f\n", new[cart->ptr]->price, new[cart->ptr]->quantity, new[cart->ptr]->price * new[cart->ptr]->quantity); // this works.
    //printf("total_prev %f\n", cart->total);
    cart->total += item->price * item->quantity;
    //printf("total %f\n", cart->total);

    return cart;
}

正如您在上面的代码中看到的,调试printf 确实有效。但是当我稍后尝试在cart.addr[n] 上执行此操作时,会导致分段错误:

// cart_t canteen_cart
// item_t *item_current
...
if (cart_append_item(&canteen_cart, item_current) == NULL) {
    // error. clean up
}
...
printf("[TEST] price %f, quantity %d, total %f\n", canteen_cart.addr[canteen_cart.ptr-1]->price, canteen_cart.addr[canteen_cart.ptr-1]->quantity, canteen_cart.addr[canteen_cart.ptr-1]->price * canteen_cart.addr[canteen_cart.ptr-1]->quantity); // segmentation fault
...

谢谢!


int main() 的片段:

int main() {
    cart_t canteen_cart;
    canteen_cart.addr = NULL;
    canteen_cart.ptr = 0;
    canteen_cart.total = 0.0f;

    item_t *item_current = NULL;

    ...
    a hundred of lines later of user input thingy
    ...

    if (state == STATE_CHECKOUT) {
        printf("[TEST] %d\n", canteen_cart.addr == NULL); // returns 0
        printf("[TEST] %d\n", canteen_cart.ptr > 0); // returns 1, there are some items in the array
        printf("price %f, quantity %d, total %f\n", canteen_cart.addr[canteen_cart.ptr-1]->price, canteen_cart.addr[canteen_cart.ptr-1]->quantity, canteen_cart.addr[canteen_cart.ptr-1]->price * canteen_cart.addr[canteen_cart.ptr-1]->quantity);
    print_view_checkout(&canteen_cart); // SEGMENTATION FAULT HERE
    }

    cart_free_items(&canteen_cart); // free cart and all the members within it.

    return 0;

}

【问题讨论】:

  • 看来你可能需要了解一下realloc
  • 至于你的问题,变量canteen_cart是什么时候在哪里定义的?它是如何初始化的?您能创建一个Minimal, Complete, and Verifiable Example 并展示给我们看吗?
  • 我正在考虑使用realloc,但我继续使用malloc-free 对...
  • realloc 将为您移动列表的内容,因此您不必像现在这样循环复制内容。
  • 为什么?因为现在你可能实际上有 undefined behavior 通过在复制中取消引用 null 或未初始化的指针。如果您使用realloc,则不会发生某些事情。 realloc 的(潜在)复制可能比您的循环更优化。

标签: c list pointers memory-management segmentation-fault


【解决方案1】:

现在我们可以看到您如何初始化canteen_cart,从cart_append_item 函数中取出这 行:

new[i+1] = item;

在第一次调用cart_append_item 函数时,cart-&gt;ptr 的值(它的名字确实很糟糕)是0。这意味着循环不会迭代,i 的值将为零。这意味着您实际上正在执行new[1] = item,其中new 仅具有索引0 的单个元素的空间。这种写越界当然会导致undefined behavior,使您的整个程序格式错误并且无效。并且容易崩溃。

对于每次对cart_append_item 的连续调用,您也会继续写越界。

简单的解决方案?请改用new[cart-&gt;ptr] = item


那么关于我的realloc 评论,如果使用realloc,您可以使函数变得更短更简单:

cart_t *cart_append_item(cart_t *cart, item_t *item) {
    if (cart == NULL || item == NULL)
        return NULL;

    item_t **new_items = realloc(cart->addr, sizeof *cart->addr * cart->ptr + 1);
    if (new_items == NULL) {
        return NULL;
    }

    cart->addr = new_items;

    // Add the new item
    cart->addr[cart->ptr++] = item;

    cart->total += item->price * item->quantity;

    return cart;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-08
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 2020-12-11
    • 2018-07-12
    相关资源
    最近更新 更多