我对使用 puts()
、gets()
、putchar()
和 getchar()
在代码中同时使用。
当我运行以下代码时,它正在执行所有步骤: 获取输入,打印输出,再次获取输入,打印输出。
#include <stdio.h>
int main() {
char ch[34];
gets(ch);
puts(ch);
char g;
g = getchar();
putchar(g);
}
输出:
Priyanka
Priyanka
J
J
但是,当我使用这段代码时: 它只做了两步: 获取输入,打印输入,然后一行。我不明白为什么它会这样。
代码:
#include <stdio.h>
int main() {
char g;
g = getchar();
putchar(g);
char ch[34];
gets(ch);
puts(ch);
getch();
}
输出:
P
P
最佳答案
代码中存在一些问题,输入机制比您想象的更复杂:
- 不应使用
gets()
读取输入:此函数无法安全使用,因为它不会接收有关目标数组大小的信息,因此任何足够长的输入行都将导致缓冲区溢出。它已从 C 标准中删除。您应该使用fgets()
来代替并处理缓冲区末尾的换行符。 g
应具有int
类型,以容纳getc()
返回的所有值,即所有unsigned 类型的值char
(在大多数当前系统中为0
到255
)和特殊负值EOF
(通常为 -1)。
这是修改后的版本:
#include <stdio.h>
int main() {
char ch[34];
if (fgets(ch, sizeof ch, stdin))
fputs(ch, stdout);
int g = getchar();
if (g != EOF)
putchar(g);
return 0;
}
输出:
Priyanka
Priyanka
J
J
关于控制台响应程序输入请求的行为,它是实现定义的,但通常涉及 2 层缓冲:
- FILE 流包实现了一种缓冲方案,其中数据以 block 的形式从系统读取或写入系统。此缓冲可以使用
setvbuf()
进行控制。有 3 种设置可用:无缓冲(这是stderr
的默认设置)、行缓冲(通常是附加到stdin
和stdout
时的默认设置)字符设备)并使用可自定义的 block 大小进行完全缓冲(常见大小为 512 和 4096)。 - 当您调用
getchar()
或更一般的getc(stream)
时,如果流缓冲区中有可用字节,则返回该字节,并且流位置会递增,否则会向系统发出填充缓冲区的请求。 - 如果流附加到文件,则填充缓冲区会执行
read
系统调用或等效调用,除非到达文件末尾或出现读取错误,否则该调用会成功。 - 如果流附加到字符设备,例如终端或虚拟 tty(如图形显示器上的终端窗口),则涉及另一层缓冲,设备驱动程序从输入设备读取输入并处理一些按键以特殊方式,例如 Backspace 删除前一个字符,光标移动键在输入行内移动,Ctrl-D (unix) 或 Ctrl-Z (windows) 表示文件结束。这一层缓冲可以通过 tcsetattr() 系统调用或其他系统特定的 API 进行控制。文本编辑器等交互式应用程序通常会禁用此功能并直接从输入设备检索原始输入。
- 用户键入的按键由终端处理以形成输入行,当用户键入 Enter 时发送回 C 流 API(被翻译为系统特定的行尾)序列),流函数执行另一组转换(即:在旧系统上将
CR
/LF
转换为'\n'
),并且字节行存储在流缓冲区中。当getc()
最终有机会返回第一个可用字节时,整行已经由用户键入并输入,并且正在流或设备缓冲区中等待。
在这两个程序中,getchar()
不会返回从 stdin
读取的下一个字节,直到从终端读取整行并将其存储在流缓冲区中。在第一个程序中,当程序退出时,该行的其余部分将被忽略,但在第二个程序中,该行的其余部分可供后续 gets()
读取。如果您输入 J 并 Enter,则读取的行为 J\n
并且 getchar()
返回 'J'
,留下换行符[在输入流中结束,然后 gets()
将读取换行符并返回一个空行。
关于c - 程序中同时使用puts()、gets()、getchar()、putchar()函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66327828/