[英]How does fgets work in this program and how does it tie into the 'stream' concept?
我对一段代码的功能有困难,这段代码旨在说明输入的fgets()函数。 在我继续之前,我想确保我对I / O和流的理解是正确的,并且我并不完全偏离基础:
C中的输入和输出没有特定的可行功能来处理字符串。 特定于处理字符串的一个函数是'gets()'函数,该函数将接受超出char数组限制的输入以存储输入(从而使得除了向后兼容之外的所有操作都有效),并创建缓冲区溢出。
这提出了流的主题,据我所知,这是一个解释程序中I / O的模型。 流被认为是“流动的水”,程序使用的数据被传送到该流动的水上。 见链接:(也作为传送带)
在C语言中,标准输入和输出有3个预定义的ANSII流,如果使用Windows或DOS,则有2个额外的流,如下所示:
据我了解,为了使事情易于管理,可以将这些视为操作系统中存在的河流,程序使用I / O函数将数据放入其中,从中获取数据或更改方向流是流动的(例如读取或写入文件需要)。 永远不要想到流的“开始”或“结束”:这是由操作系统处理的。 您需要关注的是水取数据的位置,这是通过使用特定函数(如printf()
, puts()
, gets()
, fgets()
等)来调解的。
这是我的问题开始形成的地方。 现在我有兴趣了解fgets()
函数以及它如何与流相关联。 fgets()
使用'stdin'流(自然)并具有内置的故障保护(见下文),它不允许用户输入超过用于存储输入的数组。 这是fgets()
函数的概述,而不是它的原型(我不明白为什么人们需要声明它?):
char *fgets(char *str , int n , FILE *fp);
请注意fgets函数采用的三个参数:
p1是输入存储位置的地址(一个指针,它可能只是你使用的数组的名称,例如'buffer')
p2是要输入的字符的最大长度(我想这是我的问题!)
p3指定输入流,在此代码中为'stdin'(何时会有所不同?)
现在,我在下面的代码将允许您键入字符,直到您满心。 当您点击返回时,输入将以第二个参数减去1(MAXLEN -1)长度的行打印在屏幕上。 当您输入没有其他文本的退货时,程序将终止。
#include <stdio.h>
#define MAXLEN 10
int main(void)
{
char buffer[MAXLEN];
puts("Enter text a line at a time: enter a blank line to exit");
while(1)
{
fgets(buffer, MAXLEN, stdin); //Read comments below. Note 'buffer' is indeed a pointer: just to array's first element.
if(buffer[0] == '\n')
{
break;
}
puts(buffer);
}
return 0;
}
现在,这是我的问题:
1)这个程序是否允许我输入无限字符? 我没有看到使fgets()
比gets()
fgets()
更安全的机制,因为我存储输入的数组的大小有限(在这种情况下为256)。 我看到的唯一一件事是我的长串输入被解析成MAXLEN - 1个切片? 我没有看到fgets()
停止缓冲区溢出,而get()没有? 我没有在fgets()
的参数中看到故障安全存在的地方。
2)为什么程序以MAXLEN-1而不是MAXLEN的行打印输入?
3) fgets()
函数的第二个参数有什么意义? 当我运行程序时,我可以输入任意数量的字符。 MAXLEN正在做什么来防止缓冲区溢出? 根据我的猜测,当用户输入一个大的长字符串时,一旦用户点击返回,MAXLEN将字符串切换为MAXLEN大小的咬/字节(两者实际上都在这里工作)并将它们发送到数组。 我相信我在这里缺少一些重要的东西。
这是一个满口,但我对这个非常重要的主题缺乏把握使我的代码变弱。
问题1
实际上,您可以键入尽可能多的字符,因为命令行工具将允许您输入每个字符。 但是,您调用fgets()将只处理示例中的MAXLEN
,因为您告诉他这样做。
而且,fgets()内部没有安全检查。 你给fgets的第二个参数是“安全”参数。 尝试将你对fgets的调用更改为fgets(buffer, MAXLEN + 10, stdin);
然后键入超过MAXLEN
字符。 您的程序将崩溃,因为您正在访问未分配的内存。
问题2
当你调用fgets()时,它将读取MAXLEN - 1
字符,因为最后一个字符保留给字符代码\\0
,这通常意味着字符串的结尾
fgets()的第二个参数不是您要存储的字符数,而是缓冲区的最大容量。 而你总是要考虑字符串终止字符\\0
问题3
如果你之前不知道2回答,你将能够自己回答这个问题。 尝试使用此值。 并使用与缓冲区大小不同的值。
还有,你说
p3指定输入流,在此代码中为'stdin'(何时会有所不同?)
您可以使用fgets读取存储在计算机上的文件。 这是一个例子:
char buffer[20];
FILE *stream = fopen("myfile.txt", "r"); //Open the file "myfile.txt" in readonly mode
fgets(buffer, 20, stream); //Read the 19 first characters of the file "myfile.txt"
puts(buffer);
当你调用fgets()时,它允许你输入尽可能多的stdin ,所以一切都保留在stdin中。 似乎fgets()接受前9个字符,附加一个空字符,并将其分配给buffer
。 然后puts()显示buffer
然后创建换行符。
关键是它在一个while循环中 - 代码循环再次获取剩余的stdin并将其提供给fgets(),后者接下来的9个字符并重复。 Stdin还有“排队”的东西。
C中的输入和输出没有特定的可行功能来处理字符串。
输出字符串有几个函数,例如printf
和puts
。
字符串可以用fgets
或scanf
输入; 但是没有标准功能可以输入和分配内存。 您需要预先分配一些内存,然后将一些字符读入该内存。
你对河流的比喻并不好。 无论你是否从它们中取出物品,河流都会流动,但溪流不会。 一个更好的类比可能是在体育场大门的一线人。
C也有“线”的概念,线的末尾有'\\n'
字符。 在我的比喻中,让我们说换行符由一个矮个子代表。
当你做fgets(buf, 20, stdin)
,就像“让接下来的19个人进来,但如果你在这期间遇到一个矮个子,让他通过但不是其他任何人”。 然后fgets
函数通过将结尾字符串标记放在末尾,从这些0
到19
字符中创建一个字符串; 并且该字符串放在buf
。
请注意, fgets
的第二个参数是缓冲区大小 ,而不是要读取的字符数。
键入字符时,就像更多人加入队列一样。
如果少于19人而且没有fgets
,那么fgets
会等待更多人到达。 在标准C中,没有办法检查人们是否在没有阻塞的情况下等待他们是否等待他们。
默认情况下,C流是行缓冲的 。 在我的比喻中,这就像早先有一个“预检”门,而不是正门,所有到达的人都会进入握笔,直到一个矮人到来; 然后每个人从握笔和那个矮个子被送到正门。 可以使用setvbuf
关闭此功能。
永远不要想到流的“开始”或“结束”:这是由操作系统处理的。
这是你必须要担心的事情。 stdin
等在您输入main()
之前已经开始,但是其他流(例如,如果您想从硬盘驱动器上的文件中读取),则必须开始它们。
流可能会结束。 当流结束时, fgets
将返回NULL
。 你的程序必须处理这个。 在我的比喻中,门是关闭的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.