我是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指出这一点 - 在此强制实施强制限制以防止危险的缓冲区溢出
答案 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
}