使用 fscanf 的额外内存会发生什么?

What happens with extra memory using fscanf?

我是 C 的新手,我有几个关于 fscanf 的问题。我写了一个简单的程序来读取文件的内容并将其吐回命令行:

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char* argv[1])
{
    if (argc != 2)
    {
        printf("Usage: fscanf txt\n");
        return 1;
    }

    char* txt = argv[1];

    FILE* fp = fopen(txt, "r");
    if (fp == NULL)
    {
        printf("Could not open %s.\n", txt);
        return 2;
    }

    char s[50];

    while (fscanf(fp, "%49s", s) == 1)
        printf("%s\n", s);

    return 0;
}

假设我的文本文件的内容只是 "C is cool.",它将输出:

C
is
cool. 

所以我这里有两个问题:

1) fscanf 是否假定占位符 "%s" 将是单个单词(仅字符数组)?根据这个程序的输出,spaces 和换行符似乎提示函数到 return。但是,如果我想阅读整段内容怎么办?我会改用 fread() 吗?

2) 更重要的是,我想知道数组中所有未使用的 space 会发生什么。在第一次迭代中,我认为 s[0] = "C"s[1] = "[=15=]",所以 s[2] - s[49] 只是浪费了吗?

编辑:while (fscanf(fp, "%**49**s", s) == 1) - 感谢@M Oehm 指出这一点 - 在这里强制执行强限制以防止危险的缓冲区溢出

您使用说明符 %s,它将读取数据并将其存储在数组 s 中,直到遇到 space 或换行符。一遇到spacefscanfreturns。

I think c[0] = "C" and c[1] = "[=18=]", so are c[2] - c[49] just wasted?

是的,s[0]='C's[1]='[=15=]' 并且您可能无法对数组的大小做任何事情。

如果要将完整的字符串 "C is cool" 存储在数组中,请使用 fgets.

#define len 1000

char s[len]; 
while(fgets(s,len,fp)!=NULL) {
  //your code
} 

1) Does fscanf assume that the placeholder "%s" will be a single word (an array of chars only)? According to this program's output, spaces and line breaks seem to prompt the function to return. But what if I wanted to read a whole paragraph? Would I use fread() instead?

%s 说明符读取由白色 space 分隔的单个单词。 scanf 函数族非常粗鲁;例如,它们通常不区分换行符和 space。

一行到下一个换行符。没有段落的概念,但您可以将空白行之间的任何内容视为段落。读取文本行的函数是fgets,所以你可以读取行直到找到一个空行。 (注意,fgets 在末尾保留换行符。)

fread是读取二进制数据的函数。它对阅读结构化文本没有用。 (但它可以用来一次读取整个文本文件的内容。)

2) More importantly I'm wondering what happens with all of the unused space in the array. On the first iteration, I think c[0] = 'C' and c[1] = '[=17=]', so are c[2] - c[49] just wasted?

你是对的,没有使用空终止符之后的数据。 "Wasted" 太消极了——通过用户输入,你不知道最终是否会遇到一个更长的单词。因为在 C 中动态分配需要一些小心,所以分配 "enogh for most cases" 在 C 中是一种很好的做法。不过,您应该在读取时强制执行硬限制,以防止缓冲区溢出:

fscanf(fp, "%49s", s)

如果您有 50 个字符的数组,"wasted" 内存问题会变得更加严重。大多数单词将比 50 个字符短得多。在这里,额外的内存最终可能会伤害你。不过,阅读一行多 48 个字符是可以的。

(保存 "compact" 字符数组的策略是有一个 运行 字符数组,它是所有字符串的串联,包括它们的终止符。单词数组是一个数组piointers 进入那个主字符串。)