【问题标题】:Segmentation fault when trying to remove an element from an dynamic array of structs尝试从动态结构数组中删除元素时出现分段错误
【发布时间】:2023-02-07 10:53:11
【问题描述】:

我试图通过将每个结构向左移动然后将我的数组重新分配一个较小的大小来从结构的动态数组中删除一个元素。

我的问题是:*(p[i])=*(p[i]+1);(*p)[i]=(*p)[i+1]; 之间有什么区别,为什么第二个有效而第一个代码无效,从而导致分段错误。

void rm_event(struct events **p, int index, int qtty){
    for(int i=index; i<qtty-1; i++){
        *(p[i])=*(p[i]+1); // (*p)[i]=(*p)[i+1];
    }

    struct events *tmp;
    tmp=(struct events*)realloc(*p, sizeof(struct events)*(qtty-1));
    if(tmp!=NULL)
        *p=tmp;
}

【问题讨论】:

  • *(p[i])取消引用p的地址,偏移量为i(这是p之外的内存),而(*p)[i]取消引用p,然后用i偏移它。填写一些随机数,假设地址 10 上的 p 指向地址 30,i 为 5,*(p[i]) 将给出 *(10+5) = *15,而 (*p)[i] 给出 (*10)+5 给出 @ 987654338@ = 35:两个完全不同的地址。
  • 表达式 *(p[i])p[i][0] 相同。如果p 没有指向一个数组,那么你就会越界。 *(p[i]+1)p[i][1] 相同。
  • struct events **p, 可以以多种方式使用 - 在没有附加信息的情况下模棱两可。它可以是 1) 指向结构事件指针数组的第一个元素的指针,2) 指向结构事件数组的第一个元素的指针数组的第一个元素的指针,或 3) 指向指针的指针到结构事件数组的第一个元素。通常,在这种情况下,它是#3。在不同的情况下,不同的取消引用模式是正确的与未定义的行为。编译器无法分辨,您必须为您正在使用的语义获得正确的语法。
  • 与其尝试逐一复制结构,不如查看memmove() 来替换复杂的for() 正文……这项工作已经为您完成。

标签: c function for-loop dynamic


【解决方案1】:

作为struct **p,表达式(*p)[i]首先引用(*p),它是数组开头的(struct event *),然后用[i]加载索引i

(*p): (struct events *) 0x5555555592a0
(*p)[1]: (struct events *) 0x5555555592a4

相比之下,*(p[i]) 将尊重 p[i],这会在堆栈上 p 之后的地址 i * sizeof(*p) 字节处为您提供一个 (struct **),它没有指向任何合理的东西。然后你取消引用哪些段错误:

p: (struct events **) 0x7fffffffde68
&p[1]: (struct events **) 0x7fffffffde70

这是 memmove 实现,顺便说一句,你应该向调用者报告错误,否则他们不知道数组的正确大小:

void rm_event(struct events **p, size_t index, size_t len){
    memmove(&(*p)[index], &(*p)[index+1], (len - index - 1) * sizeof **p);

    struct events *tmp;
    tmp = realloc(*p, sizeof(struct events)*(len - 1));
    if(tmp)
        *p=tmp;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-08
    • 2018-06-29
    • 2019-05-12
    • 1970-01-01
    相关资源
    最近更新 更多