fscanf是否分配内存并在字符串末尾放置一个NUL字节?

时间:2015-04-07 04:17:34

标签: c scanf

如果我是对的,请执行以下操作:

char *line;

然后我必须分配一些内存并将其分配给线路,是吗?如果我是对的,问题如下:

在像

这样的行中
while (fscanf(fp,"%[^\n]", line) == 1) { ... } 

没有为行分配任何内存我仍然得到正确的行和正确的strlen计数在这些行上。

那么,fscanf是否会为我分配内存,它还会放置'\0'? 我在fscanf的规范中没有提到这两件事。

5 个答案:

答案 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。

并且,here is a longer explanationanother longer explanation

答案 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;),并始终测试malloccallocrealloc的失败。此外,使用所有警告和调试信息(gcc -Wall -Wextra -g)进行编译。它本可以给你一个有用的警告。

顺便说一下,我喜欢清除每个动态分配的内存,即使它不是很有用(因为行为更具确定性,使程序更容易调试)。

某些系统还有valgrind来帮助检测内存泄漏,缓冲区溢出等。

答案 3 :(得分:3)

line未初始化,并且不指向任何有效的内存位置,因此您看到的是未定义的行为。

在向其中写入内容之前,需要为指针分配内存。

PS:如果您尝试阅读整行,那么fgets()是更好的选择。请注意fgets()附带换行符。

答案 4 :(得分:2)

不。你只是幸运未定义的行为。完全有可能从现在开始一个小时,程序将是段错误而不是按预期运行,或者不同的编译器甚至不同机器上的相同编译器将生成一个行为不同的程序。你不能指望没有指明的事情发生,如果你这样做,你不能指望它是任何形式的可靠。