我在一段代码的功能上遇到了困难,该功能旨在说明用于输入的 fgets() 函数。在继续之前,我想确保我对 I/O 和流的理解是正确的,并且我并没有完全偏离基础:
C 中的输入和输出没有用于处理字符串的特定可行函数。专用于处理字符串的一个函数是“gets()”函数,它将接受超出 char 数组限制的输入来存储输入(因此对于除向后兼容性之外的所有内容都有效地非法),并创建缓冲区溢出。
这就引出了流的话题,据我所知,它是一个解释程序中 I/O 的模型。溪流被认为是“流动的水”,程序使用的数据在其上传送。查看链接:(也可作为传送带)
在 C 语言中,标准输入和输出有 3 个预定义的 ANSII 流,如果使用 windows 或 DOS,则有 2 个附加流,如下所示:
- 标准输入(键盘)
- 标准输出(屏幕)
- 标准错误(屏幕)
- stdprn(打印机)
- 标准辅助(串行端口)
据我了解,为了使事情易于管理,可以将它们视为操作系统中存在的河流,并且程序使用 I/O 函数将数据放入其中,从中取出数据,或改变位置的方向流正在流动(例如需要读取或写入文件)。永远不要考虑流的“开始”或“结束”:这是由操作系统处理的。您需要关心的是水将您的数据带到哪里,这是通过使用特定功能(例如printf()
、puts()
、gets()
、fgets()
等)来调节的。
这就是我的问题开始形成的地方。现在我有兴趣了解该fgets()
函数以及它如何与流相关联。fgets()
使用“stdin”流(自然)并具有内置的故障保护(见下文),不允许用户输入超过用于存储输入的数组。这是fgets()
函数的大纲,而不是它的原型(我不明白为什么需要声明它?):
char *fgets(char *str , int n , FILE *fp);
请注意 fgets 函数采用的三个参数:
p1 是存储输入的地址(一个指针,可能只是您使用的数组的名称,例如“缓冲区”)
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) 这个程序是否允许我输入 UNLIMITED 个字符?我看不到fgets()
比 更安全的机制gets()
,因为我存储输入的数组大小有限(在这种情况下为 256)。我看到发生的唯一一件事是我的长输入字符串被解析为 MAXLEN - 1 个切片?我没有看到什么fgets()
停止了gets()没有的缓冲区溢出?我在参数中看不到fgets()
故障安全存在的位置。
2) 为什么程序在 MAXLEN-1 行而不是 MAXLEN 行中打印输入?
3)函数的第二个参数有什么意义fgets()
?当我运行程序时,我可以输入任意数量的字符。MAXLEN 在做什么来防止缓冲区溢出?据我猜测,当用户输入一个大的长字符串时,一旦用户点击返回,MAXLEN 会将字符串切成 MAXLEN 大小的位/字节(两者实际上都在这里工作,哈哈)并将它们发送到数组。我确定我在这里遗漏了一些重要的东西。
那是满嘴的,但是我对这个非常重要的主题缺乏掌握使我的代码变弱了。