不知道如何正确使用getchar函数/ C

时间:2018-11-03 00:10:21

标签: c loops input getchar

我想创建一个在控制台中输入字符的函数,但是问题是有时当我输入'a'时,它被视为空字符,并且程序要求我重新输入一个字符。 这是功能:

char readChar()
  {
    char character;
    character = getchar();
    character = toupper(character);
    while(getchar() != '\n' && getchar() != '\0');
    return character;
  }

3 个答案:

答案 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

  1. 使用getchar()。它返回intunsigned char范围内的EOF

  2. 阅读其余的

示例代码,有点像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;
}
相关问题