【问题标题】:Why does this code usually work but sometimes produce Segmentation Fault?为什么这段代码通常可以工作,但有时会产生分段错误?
【发布时间】:2019-07-12 20:29:22
【问题描述】:

这是我的代码

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/**************************************************
a is a pointer to an array of strings
b is a string
This function appends b to *a
n is the number of strings currently "held" by *a
**************************************************/
int append(char ***a, char *b, unsigned long n) {
    if (a && *a && **a) {
        char** tmp = realloc(*a, (n + 1) * sizeof(**a));
        if (tmp) {
            tmp[n] = b;
            *a = tmp;
            return 0;
        }
    }
    return -1;
}

void test() {
    char *words[7] = { "food", "is", "good", "to", "eat,", "like", "pizza" };
    char** a = malloc(1 * sizeof(*a));

    for (int i = 0; i < 7; i++) {
        append(&a, words[i], i);
        int j = 0; 
        while (j <= i) 
            printf("%s ", a[j++]); 
        printf("\n");
    }
}

int main() {
    test();
    return 0;
}

代码总是可以正常编译并且没有警告。并且可执行文件在大约 95% 的时间内按预期运行。但是大约 5% 的时间,我会遇到分段错误。我知道故障发生在a[j++],但我不明白为什么。

【问题讨论】:

  • 如果一切正常"sometimes",那么您肯定会调用Undefined Behavior....
  • @DavidC.Rankin 和分段错误使这个赌注成为一个明确的胜利:)
  • 好的,谢谢大家。那么我在哪里调用未定义的行为?
  • 请注意,成为3-Star Programmer 并不是恭维。您最好创建一个结构来保存指针数组,以及分配的大小和正在使用的大小。然后,您可以避免将数组的大小加一;这可能导致性能非常差(二次行为),因为在重新分配内存时会复制数据。但是,这并不是导致崩溃的直接原因。

标签: c pointers segmentation-fault


【解决方案1】:

看看这一行:

if (a && *a && **a)

当您为a 最初指向的一个元素设置malloc 空间时,您实际上从未初始化该内存。结果,**a 未初始化,因此读取它被视为未定义行为。在实践中,我怀疑有时分配给您的内存在某些情况下是空指针,但在其他情况下却不是,这导致了片状问题。

我实际上认为您甚至不需要检查 *a**a。只要指针a 本身不是空指针,您就可以修改它指向的指针(*a)。此外,这里实际上不需要知道*a 指向的数组的第一个元素是否为空(**a)。所以你可以把这个检查替换为

if (a)

我会更进一步,甚至不会为 a 分配初始数组,因为您实际上永远不会读取存储在那里的值。

其他要做的事情:函数append返回一个状态码,通知操作是成功还是失败。最好在调用append 时检查该值,以防万一失败。您可能还想将外部 if 语句更改为 assert 以便如果有人使用错误参数调用它,它会停止并报告违反先决条件而不是失败并返回错误代码。毕竟,如果问题是“你给我的论点不可能是正确的”,那就意味着代码中的某个地方存在逻辑错误。

希望这会有所帮助!

【讨论】:

  • 非常感谢@templatetypedef!我从不初始化那个内存。而且我认为您不需要为a 分配初始数组也是正确的。在将此标记为正确答案之前,请给我一些时间进行试验。再次感谢!
  • 再次感谢@templatetypedef。您的回答和“其他要做的事情”真的很有帮助。我还开始查看您网站上的内容,发现它非常有用且有趣。谢谢!
猜你喜欢
  • 1970-01-01
  • 2016-02-08
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 2017-12-04
  • 1970-01-01
相关资源
最近更新 更多