如果我是对的,请执行以下操作:
char *line;
然后我必须分配一些内存并将其分配给线路,是吗?如果我是对的,问题如下:
在像
这样的行中while (fscanf(fp,"%[^\n]", line) == 1) { ... }
没有为行分配任何内存我仍然得到正确的行和正确的strlen计数在这些行上。
那么,fscanf
是否会为我分配内存,它还会放置'\0'
?
我在fscanf
的规范中没有提到这两件事。
答案 0 :(得分:7)
如果您使用m
(某些较旧的POSIX前版本的a
)格式修饰符,POSIX scanf()
系列函数将分配内存。 注意:当fscanf
分配时,它需要一个char **
指针。 (见man scanf
)例如:
while(fscanf(fp,"%m[^\n]", &line) == 1) { ... }
我还建议使用newline
来使用"%m[^\n]%*c"
。我同意其他建议使用line-oriented
输入而不是fscanf
的建议。 (例如getline
- 见:Basile的回答)
答案 1 :(得分:5)
请参阅C FAQ:
问:我刚刚尝试了代码char *p; strcpy(p, "abc");
它有效。怎么样?为什么没有崩溃?
答:我猜你很幸运。未初始化的指针p随机指向的内存碰巧是你可写的,显然还没有用于任何重要的事情。另见问题11.35。
答案 2 :(得分:4)
要使用POSIX系统上的最新C库读取整个行,您应该使用getline(3)。它根据需要分配(并重新分配)保存行的缓冲区。请参阅手册页上的示例。
如果您的非POSIX系统没有getline
,您可能会使用fgets(3),但是您必须自己分配线路,测试您没有读取完整的换行终止线路,并重复。然后你需要在调用malloc
之前预先分配一些行缓冲区(使用例如fgets
)(如果某行不适合你可以realloc
并再次调用fgets
)。类似的东西:
//// UNTESTED CODE
size_t linsiz=64;
char* linbuf= malloc(linsiz);
if (!linbuf) { perror("malloc"); exit(EXIT_FAILURE); };
memset(linbuf, 0, sizeof(linbuf));
bool gotentireline= false;
char* linptr= linbuf;
do {
if (!fgets(linptr, linbuf+linsiz-linptr-1, stdin))
break;
if (strchr(linptr, '\n'))
gotentireline= true;
else {
size_t newlinsiz= 3*linsiz/2+16;
char* newlinbuf= malloc(newlinsiz);
int oldlen= strlen(linbuf);
if (!newlinbuf) { perror("malloc"); exit(EXIT_FAILURE); };
memset (newlinbuf, 0, newlinsiz); // might be not needed
strncpy(newlinbuf, linbuf, linsiz);
free (linbuf);
linbuf= newlinbuf;
linsiz= newlinsiz;
linptr= newlinbuf+oldlen;
);
} while(!gotentireline);
/// here, use the linbuf, and free it later
一般规则是始终初始化指针(例如,在您的情况下声明char *line=NULL;
),并始终测试malloc
,calloc
,realloc
的失败。此外,使用所有警告和调试信息(gcc -Wall -Wextra -g
)进行编译。它本可以给你一个有用的警告。
某些系统还有valgrind来帮助检测内存泄漏,缓冲区溢出等。
答案 3 :(得分:3)
line
未初始化,并且不指向任何有效的内存位置,因此您看到的是未定义的行为。
在向其中写入内容之前,需要为指针分配内存。
PS:如果您尝试阅读整行,那么fgets()
是更好的选择。请注意fgets()
附带换行符。
答案 4 :(得分:2)
不。你只是幸运未定义的行为。完全有可能从现在开始一个小时,程序将是段错误而不是按预期运行,或者不同的编译器甚至不同机器上的相同编译器将生成一个行为不同的程序。你不能指望没有指明的事情发生,如果你这样做,你不能指望它是任何形式的可靠。