繁体   English   中英

fgets如何在这个程序中运行,它如何与“流”概念相结合?

[英]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个额外的流,如下所示:

  • stdin(键盘)
  • 标准输出(屏幕)
  • stderr(屏幕)
  • stdprn(打印机)
  • stdaux(串口)

据我了解,为了使事情易于管理,可以将这些视为操作系统中存在的河流,程序使用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中的输入和输出没有特定的可行功能来处理字符串。

输出字符串有几个函数,例如printfputs

字符串可以用fgetsscanf输入; 但是没有标准功能可以输入和分配内存。 您需要预先分配一些内存,然后将一些字符读入该内存。


你对河流的比喻并不好。 无论你是否从它们中取出物品,河流都会流动,但溪流不会。 一个更好的类比可能是在体育场大门的一线人。

C也有“线”的概念,线的末尾有'\\n'字符。 在我的比喻中,让我们说换行符由一个矮个子代表。

当你做fgets(buf, 20, stdin) ,就像“让接下来的19个人进来,但如果你在这期间遇到一个矮个子,让他通过但不是其他任何人”。 然后fgets函数通过将结尾字符串标记放在末尾,从这些019字符中创建一个字符串; 并且该字符串放在buf

请注意, fgets的第二个参数是缓冲区大小 ,而不是要读取的字符数。

键入字符时,就像更多人加入队列一样。

如果少于19人而且没有fgets ,那么fgets会等待更多人到达。 在标准C中,没有办法检查人们是否在没有阻塞的情况下等待他们是否等待他们。

默认情况下,C流是行缓冲的 在我的比喻中,这就像早先有一个“预检”门,而不是正门,所有到达的人都会进入握笔,直到一个矮人到来; 然后每个人从握笔和那个矮个子被送到正门。 可以使用setvbuf关闭此功能。

永远不要想到流的“开始”或“结束”:这是由操作系统处理的。

这是你必须要担心的事情。 stdin等在您输入main()之前已经开始,但是其他流(例如,如果您想从硬盘驱动器上的文件中读取),则必须开始它们。

流可能会结束。 当流结束时, fgets将返回NULL 你的程序必须处理这个。 在我的比喻中,门是关闭的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM