我试图使用getline从stdin读取两行连续的输入。这个最小的代码会导致分段错误,我不知道为什么:
int main() {
char *ln1 = NULL;
char *ln2 = NULL;
size_t lnsz1;
size_t lnsz2;
getline(&ln1,&lnsz1,stdin);
getline(&ln2,&lnsz2,stdin);
}
有人能解释我做错了什么吗?
发布于 2020-10-04 15:06:19
我在评论中说过,将大小设置为零(以及指向空指针的指针)应该修复观察到的崩溃。
隐藏在背景中的是一个假设,即导致崩溃的getline()
的具体实现有些错误。如果在分配空间时使用size参数,因为指针为null,则可能会出现错误。这在某种程度上是不可能的,但问题并没有给出哪个平台会导致崩溃的信息。
getline()
的POSIX规范规定:
ssize_t getline(char **restrict lineptr, size_t *restrict n, FILE *restrict stream);
… 应用程序应确保*lineptr
是可以传递给free()
函数的有效参数。如果*n
为非零,则应用程序应确保*lineptr
要么指向大小至少为*n
字节的对象,要么为空指针。 如果*lineptr
是空指针,或者*lineptr
指向的对象大小不足,则应像由malloc()
分配对象或重新分配对象一样,分别由realloc()
重新分配对象,使对象足够大以容纳要写入的字符,包括终止NUL,*n
应设置为新的大小。如果分配了对象,或者重新分配操作移动了对象,则将更新*lineptr
以指向新对象或新位置。 … 成功完成后,getline()
和getdelim()
函数将返回写入缓冲区的字节数,如果在EOF之前遇到一个分隔符字符,则包括分隔符字符,但不包括终止NUL字符。如果设置了流的文件结束指示符,或者没有读取字符,并且流位于文件末尾,则应设置流的文件结束指示符,并返回-1。如果发生错误,将设置流的错误指示符,函数将返回-1并设置errno
以指示错误。
问题中的代码并不是不言而喻地滥用了这些规则。应用程序确保*lineptr
是一个空指针--这是一个可以传递给free()
的值。*n
的值是什么并不重要,因为*lineptr
是一个空指针。
实验的一种方法是尝试在未初始化的变量(lnsz1
和lnsz2
)中打印值,但这种实验可以说是在调用未定义的行为。另一种方法是将变量初始化为一些大值--例如SIZE_MAX
或SIZE_MAX / 2
(其中SIZE_MAX
在C11 中定义,而不是在C标准的早期版本中定义)或其他类似的充气值。当然,您还应该使用0
的值进行测试,一些测试可以使用其他小值进行,比如1
、8
、16
等。所有这些测试都是在指针设置为空指针的情况下进行的。如果可以使用内存分配包来调用malloc()
(或realloc()
)的调试版本,则可以记录请求的内存大小。如果第二次调用发生崩溃,则在第一次调用getline()
后打印getline()
值可能会获得一些信息。
然而,这样的调查几乎不值得这么做。将指针和大小设置为零应该可以解决这个问题。如果没有,还有更多的事情要调查。然而,这不太可能是问题所在。
//#define _XOPEN_SOURCE 700 // Explicitly request POSIX support
#include <stdio.h>
int main(void)
{
char *ln1 = NULL;
char *ln2 = NULL;
size_t lnsz1 = 0;
size_t lnsz2 = 0;
ssize_t len1 = -1;
ssize_t len2 = -1;
if ((len1 = getline(&ln1, &lnsz1, stdin)) != -1)
{
printf("%zd (%zu: %p) [%s]\n", len1, lnsz1, (void *)ln1, ln1);
if ((len2 = getline(&ln2, &lnsz2, stdin)) != -1)
printf("%zd (%zu: %p) [%s]\n", len2, lnsz2, (void *)ln2, ln2);
}
free(ln1);
free(ln2);
return 0;
}
注意,当getline()
检测到错误或文件结束时,它特别返回-1
而不是EOF
。在大多数系统上,这两个值是相同的,但是C标准只要求EOF
是负的-它不要求它是-1
。我无法确定0
的返回值对getline()
有效的任何情况。
https://stackoverflow.com/questions/64194282
复制