为什么使用 char** 会导致 char* 工作的段错误?

Why does using a char** cause a segfault where a char* works?

第 1 部分

int main(int argc, char **argv)
{
    int             fd;
    int             i;
    char            *line;

    if (!(fd = open(argv[1], O_RDWR | O_CREAT)))
    {
        printf("Error in open\n");
        return (0);
    }
    while ((i = get_next_line(fd, &line)) > 0)
    {
        printf("%i-%s\n",i, line);
        free(line);
    }
    printf("%i-%s",i, line);
    free(line);
}

第 2 部分

int main(int argc, char **argv)
{
    int             fd;
    int             i;
    char            **line;

    if (!(fd = open(argv[1], O_RDWR | O_CREAT)))
    {
        printf("Error in open\n");
        return (0);
    }
    while ((i = get_next_line(fd, line)) > 0)
    {
        printf("%i-%s\n",i, *line);
        free(*line);
    }
    printf("%i-%s",i, *line);
    free(*line);
}

Part 1 和Part 2 有什么区别吗,区别是一个使用**line,另一个只是*line。 根据我的理解,两者应该是一样的。

我正在使用它们来测试我自己的函数实现,该函数读取 return 1 行。

问题:

第 1 部分测试工作正常。 第 2 部分测试结果 分段错误

get_next_line() 的实现对两者保持不变。

在第一种情况下,使用 &line 将有效地址传递给 get_next_line。但在第二种情况下,使用 line 将未初始化的变量传递给函数。您没有显示 get_next_line 但我认为它会执行类似 *line = blah 的操作,如果传入的 line 值不是有效地址(从技术上讲,取消引用是未定义的行为,这当然会出现段错误一个未初始化的指针,因此它可能会出现段错误,但也可能表现出任何其他行为)。

另一种看待它的方式:

char            **line;
get_next_line(fd, line);
printf("%i-%s\n",i, *line);

第二种情况基本上就是这样做的。我们知道在 C 中函数参数是按值传递的。因此 get_next_line 无法更改调用者的 line 变量的值。所以当函数 returns 的值 line 是未定义的,因为它从未被初始化。因此,即使 get_next_line 不取消引用 lineprintf 仍会在取消引用 line 时导致未定义的行为,但此时它的值显然未定义。

将其与等效操作的第一种情况进行比较:

char            *line;
get_next_line(fd, &line);
printf("%i-%s\n",i, *line);

在这种情况下,get_next_line 能够有效地更改调用者的 line 变量,例如:

*line = malloc(MY_MAX_LINE_LENGTH);

因此,当函数退出时,调用者的 line 变量现在具有有效的内存地址,因此可以安全地取消引用。