我想创建一个在控制台中输入字符的函数,但是问题是有时当我输入'a'时,它被视为空字符,并且程序要求我重新输入一个字符。 这是功能:
char readChar()
{
char character;
character = getchar();
character = toupper(character);
while(getchar() != '\n' && getchar() != '\0');
return character;
}
答案 0 :(得分:3)
将大量评论转换为答案。
1。请注意,getchar()
returns an int
,而不是char
。而且您的循环还需要考虑EOF而不是空字节,尽管检测空字节可能还可以。
我对麻烦的最好猜测是,有时您执行scanf("%d", &i)
或类似的操作,然后调用此函数-但scanf()
doesn't read the newline,因此您的函数读取以前的I / O操作留下的换行符。但是如果没有MCVE(Minimal, Complete, and Verifiable Example),我们无法证明我的假设是正确的。
2。同样,“吃剩下的每一行”循环在每次迭代中应该只调用一次getchar()
。你叫了两次。一种选择是使用:
int readChar(void)
{
int c;
while ((c = getchar()) != EOF && isspace(c))
;
if (c == EOF)
return EOF;
int junk;
while ((junk = getchar()) != '\n' && junk != EOF /* && junk != '\0' */)
;
return toupper(c);
}
这会吃掉空格,直到得到一个非空格字符,然后读取下一个换行符之前的所有垃圾字符。这将解决我的假设情况。当心EOF-始终考虑EOF。
Voltini基于阅读有关scanf()
而不是换行的问答,提出了一个解决方案:
char readChar() { char character; scanf(" %c", &character); getchar(); //I just added this line character = toupper(character); return character; }
3。这通常是工作的好方法。请注意,它仍未处理EOF-您始终需要担心EOF。如果用户键入getchar()
和 newline ,则scanf()
之后的a
会读取换行符,但是如果用户键入a-z
然后输入 newline 。您必须决定要执行的操作–字符吞噬循环通常是个好主意,而不是单个getchar()
调用:
int c;
while ((c = getchar()) != EOF && c != '\n')
;
针对以下内容的评论:
请说明处理EOF的重要性。
4。如果您不询问,则不一定会了解它!输入和输出(I / O)尤其是输入很麻烦。用户不输入您要求他们输入的内容。它们在您告诉他们键入的内容之前或之后添加空格;您希望输入类似good
之类的缩写,然后输入supercalifragilisticexpialidocious
。有时情况会出错,并且没有更多数据可读取-状态称为EOF或“文件结尾”。
5。在没有检查的char character; scanf(" %c", &character);
函数中,如果没有输入(用户输入Unix上的^ D或Windows上的^ Z,或者数据文件结束),则不知道要输入什么值。变量-它是准随机变量(不确定),使用它会调用undefined behaviour。那很糟。此外,在问题代码中,您具有此循环,如果用户指示EOF,该循环将永远不会结束。
while (getchar() != '\n' && getchar() != '\0') // Should handle EOF!
;
6。而且,更复杂的是,如果普通字符是无符号类型,则分配字符并测试EOF总是会失败,并且如果普通字符是有符号类型,您将在有效字符上检测到EOF(通常为ÿ-小拉丁文) Unicode和8859-1或8859-15代码集中带有小写字母的字母y)。这就是为什么我的代码使用int c的原因;用于字符输入。因此,如您所见(我希望),有充分的理由说明为什么您必须始终注意EOF。它可以在您不期望的时候发生,但是因此您的代码不应陷入无限循环。
我不确定在代码中如何以及在何处实现此目标。
7。这有两个部分。一个在readChar()
函数中,该函数需要返回一个int
而不是一个char
(出于同样的原因,getchar()
返回一个int
而不是一个{ char
),或需要其他接口,例如:
bool readChar(char *cp)
{
int c;
while ((c = getchar()) != EOF && isspace(c))
;
if (c == EOF)
return false;
*cp = toupper(c);
while ((c = getchar()) != '\n' && c != EOF /* && c != '\0' */)
;
return true;
}
以便您可以致电:
if (readChar(&character))
{
…process valid input…
}
else
{
…EOF or other major problems — abandon hope all ye who enter here…
}
使用正确检测EOF的功能,即可修复您的调用代码,以便处理来自readChar()
的EOF(错误指示)。
请注意,空循环体由在行上缩进的分号表示。这就是K&R(The C Programming Language-1988年的Kernighan和Ritchie)编写具有空主体的循环的方法,因此您发现它得到了广泛的使用。
随着时间的流逝,您会发现用C语言编写的大量代码都用于错误处理。
答案 1 :(得分:1)
不要像while(getchar() != '\n' && getchar() != '\0');
@Jonathan Leffler
要从用户输入的行中读取单个字符和第一个字符:
文本流是由行组成的有序字符序列,每一行 由零个或多个字符加上一个换行符结尾。是否 最后一行要求终止换行符是实现定义的。 C11dr§7.21.22
使用getchar()
。它返回int
或unsigned char
范围内的EOF
。
阅读其余的行。
示例代码,有点像OP的代码。
int readChar_and_make_uppercase() {
int ch = getchar();
if (ch != '\n' && ch != EOF) {
// read rest of line and throw it away
int dummy;
while ((dummy = getchar()) != '\n' && dummy != EOF) {
;
}
}
return toupper(ch);
}
答案 2 :(得分:0)
显然,我忘了照顾存储在缓冲区中的换行符(如果我错了,请纠正我)。
char readChar()
{
char character;
scanf(" %c", &character);
getchar(); //I just added this line
character = toupper(character);
return character;
}