使用 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 或换行符。一遇到spacefscanf
returns。
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 进入那个主字符串。)
我是 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 或换行符。一遇到spacefscanf
returns。
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'
andc[1] = '[=17=]'
, so arec[2]
-c[49]
just wasted?
你是对的,没有使用空终止符之后的数据。 "Wasted" 太消极了——通过用户输入,你不知道最终是否会遇到一个更长的单词。因为在 C 中动态分配需要一些小心,所以分配 "enogh for most cases" 在 C 中是一种很好的做法。不过,您应该在读取时强制执行硬限制,以防止缓冲区溢出:
fscanf(fp, "%49s", s)
如果您有 50 个字符的数组,"wasted" 内存问题会变得更加严重。大多数单词将比 50 个字符短得多。在这里,额外的内存最终可能会伤害你。不过,阅读一行多 48 个字符是可以的。
(保存 "compact" 字符数组的策略是有一个 运行 字符数组,它是所有字符串的串联,包括它们的终止符。单词数组是一个数组piointers 进入那个主字符串。)