为什么使用char **会导致在char *有效的地方出现段错误?

Moh*_*pta 3 c pointers double-pointer

第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);
}
Run Code Online (Sandbox Code Playgroud)

第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);
}
Run Code Online (Sandbox Code Playgroud)

第1部分和第2部分之间是否有区别,它们之间的区别是一种用途,**line而另一种用途只是*line。据我了解,两者应该是相同的。

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

问题:

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

两者的实现get_next_line()保持相同。

kay*_*lum 7

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

另一种查看方式:

char            **line;
get_next_line(fd, line);
printf("%i-%s\n",i, *line);
Run Code Online (Sandbox Code Playgroud)

从本质上讲,这就是第二种情况。我们知道在C语言中,函数参数是通过值传递的。因此,没有任何方法get_next_line可以更改调用方line变量的值。因此,当函数返回值时,line由于从未初始化过,因此其值是不确定的。因此,即使get_next_line不取消引用,line在取消引用printf时仍会导致未定义的行为,line但此时的值显然是未定义的。

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

char            *line;
get_next_line(fd, &line);
printf("%i-%s\n",i, *line);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,get_next_line可以通过以下方式有效地更改调用方的line变量:

*line = malloc(MY_MAX_LINE_LENGTH);
Run Code Online (Sandbox Code Playgroud)

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