getc()和getchar()是定义良好的函数吗?

getc()和getchar()是定义良好的函数吗?,c,C,我这样编写源代码,然后使用vs2017在windows控制台应用程序上按顺序按下s,enter,s,enter。Console向我显示按键时输入和打印的内容。结果的外观类似于s,enter,enter,space,s,s,enter,space,s。我是否以错误的方式使用了该函数 问题1。我按了s,按顺序输入,但为什么输出会反转? 问题2。在输出的第三行和第六行,为什么会有像 s不是s?。解释输出 函数的参数可以按照编译器选择的任何顺序求值 原始代码如下所示(与修订后的代码相比,缺少printf

我这样编写源代码,然后使用vs2017在windows控制台应用程序上按顺序按下
s
enter
s
enter
。Console向我显示按键时输入和打印的内容。结果的外观类似于
s
enter
enter
space
s
s
enter
space
s
。我是否以错误的方式使用了该函数

问题1。我按了
s
按顺序输入
,但为什么输出会反转?
问题2。在输出的第三行和第六行,为什么会有像
 s
不是
s
?。

解释输出 函数的参数可以按照编译器选择的任何顺序求值

原始代码如下所示(与修订后的代码相比,缺少
printf(“\n”);
):

你在问题中的“输出”极难阅读和解释。但是,我可以合理地确定,您显示的内容包括您的输入和程序的输出。 你说你输入了两次。您从问题中获得的输出是:

printf("%c %c", getc(stdin), getc(stdin));
rewind(stdin);
printf("%c %c", getchar(), getchar());
第一个
s
和后面的换行符就是您键入的内容。空白行在那里,因为换行符是由<代码> GETC(STDIN)读取的,它首先出现在参数列表中,然后是格式字符串中的空白,以及<>代码> GEC(STDIN)读取的“<代码> S/<代码> >,它出现在参数列表中的第二个。您的编译器似乎从右向左计算参数,但您不应该依赖于此

现在我们遇到了一个问题;在第二个
s
后面有一个新行,这不是我写这个答案时显示的代码的原因。此后,您添加了
printf(“\n”)这解释了您看到的输出

除此之外,第三个
s
后面跟着一个换行符,这就是您键入的内容。而且,空白行是从换行符,然后空间和<>代码> s>代码>是输出的其余部分,在这之后也可能有一个换行符。 JFTR,当我运行您的代码时(从
getc73.c
编译的程序
getc73
),我看到:

$
是我的提示;第一个
s
是我键入的;然后打印换行、空白和
s
(末尾没有换行);然后第三行的第二个
s
是我的下一个
s
并返回,然后是换行符和空白
s
。由于末尾没有换行符,我的提示会在第四个
s
之后立即出现。我点击return在行首打印另一个提示符

为什么
倒带(stdin)
是不可行的 无法在终端设备上成功执行
fseek()
调用。他们没有任何存储空间,所以你不能像那样四处走动。
rewind()
功能有效地:

$ getc73
s

 ss

 s$
$
因此,
revind(stdin)
调用无法回放,但无法向您报告,因为它不返回任何值。这没有好处;这也没什么坏处。如果它起作用,您就不需要输入两次信息

如果标准输入是一个文件而不是一个终端,那么倒带将成功-磁盘是可查找的

改进的格式 如果您使用的是POSIX系统,我建议您使用POSIX的一项功能,它允许您多次打印相同的参数:

void rewind(FILE *fp)
{
    fseek(fp, 0, SEEK_SET);
}
上面只有
s
的行就是我键入的;其他行显示换行符在字母
s
之前打印

这在VS2017中可能不适用-Windows上的手册强烈建议它不适用。您最好的选择可能是使用:

s
[
] 10 [s] 115
s
[
] 10 [s] 115

选择一种好的格式来展示你所看到的是一种艺术形式。不要忘记在(most)
printf()的末尾包含换行符。
格式化字符串。显然,如果要逐段建立一行输出,您不希望在中间格式的末尾有换行符,但是大多数
printf()
语句应该在格式的末尾有一个换行符。

使用
%d
打印不应该产生
s
或空白作为输出。显示真实代码!问题很可能是函数参数的求值顺序取决于编译器。它甚至不必是自一致的-对
printf
的两个调用可能以不同的顺序计算参数;这是一个不可查找的设备。使用
%c
调试诸如换行符和空格之类的字符很困难。在上下文中,使用
%d
将是一个好主意,尽管您可能需要在每个格式字符串的末尾换行。当然,这会改变输出。函数参数的求值顺序没有定义。另外:
getc()
可以是一个宏,在没有插入序列点(如此处)的情况下调用时可能会导致问题。顺便提一下,我关于“如果没有事先输入”的评论就是为什么我们希望看到MCVE()(或MRE或现在使用的任何名称)或SSCCE()。如果您在显示的代码周围有
#include
intmain(void){
return 0;}
,我就不需要对“如果没有事先输入”进行警告。“我想这意味着您没有在格式字符串的末尾显示\n。”您是对的。对不起我的粗心。。。我编辑了我的帖子,你的答案给了我很好的理解。注意,你可以在stdin上使用
ungetc
(倒带1个字符)你是对的,@M.M,但这不是一个搜索操作-你传递给
ungetc()
的字符不必是你读过的字符(使用
getc()
或任何其他输入原语),尽管最常见的用法确实是这样做。标准
void rewind(FILE *fp)
{
    fseek(fp, 0, SEEK_SET);
}
#include <stdio.h>

int main(void)
{
    printf("[%1$c] %1$d [%2$c] %2$d\n", getc(stdin), getc(stdin));
    printf("[%1$c] %1$d [%2$c] %2$d\n", getchar(), getchar());
    return 0;
}
s
[
] 10 [s] 115
s
[
] 10 [s] 115
#include <stdio.h>

int main(void)
{
    printf("%d %d\n", getc(stdin), getc(stdin));
    printf("%d %d\n", getchar(), getchar());
    return 0;
}
s
10 115
s
10 115