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

时间:2016-03-12 05:16:30

标签: c scanf

我是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;
}

让我们说我的文本文件的内容只是&#34; C很酷。&#34;,它将输出:

C
is
cool. 

所以我在这里有两个问题:

1)fscanf是否假设占位符"%s"将是一个单词(仅限字符数组)?根据这个程序的输出,空格和换行符似乎提示函数返回。但是,如果我想读一整段呢?我会改用fread()吗?

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

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

2 个答案:

答案 0 :(得分:3)

  

1)fscanf是否假设占位符“%s”是单个单词   (仅限一系列字符)?根据这个程序的输出,空格   和换行似乎提示函数返回。但是,如果我   想读一整段?我会改用fread()吗?

%s说明符读取由空格分隔的单个单词。 scanf系列函数非常隐蔽;例如,它们通常不区分换行符和空格。

一行是下一个换行符。没有段落的概念,但您可以考虑在空白行之间的任何内容。读取文本行的函数是fgets,因此您可以读取行,直到找到空行。 (fgets最后会保留换行符。)

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

  

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

你是对的,没有使用null ternimator之后的数据。 “浪费”太消极了 - 根据用户输入,您不知道最终是否会遇到更长的单词。因为动态分配在C中需要一些小心,所以在C中分配“enogh”是C中的一种goopd练习。但是,你应该在读取时强制执行硬限制,以防止缓冲区溢出:

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

如果你有一个包含50个字符的数组,那么“浪费”内存的问题会变得更加严重。大多数单词将比50个字符短得多。在这里,额外的记忆可能最终会伤害你。但是,读取一行的48个额外字符是可以的。

(保存“紧凑”字符数组的策略是拥有一个运行的字符数组,它是所有字符串的串联,包括它们的终结符。然后,字数组就是一个piointers到该主字符串的数组。)< / p>

答案 1 :(得分:0)

使用说明符%s,它将在数组s中读取和存储数据,直到遇到空格或换行符。一旦遇到空间fscanf返回。

  

我认为c [0] =“C”和c [1] =“\ 0”,所以c [2] - c [49]只是浪费了吗?

是的,s[0]='C's[1]='\0'您可能无法对阵列的大小做更多的事情。

如果您希望在数组中使用fgets存储完整的字符串"C is cool"

#define len 1000

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