C语言 使用条件运算符计算后打印结果

emeijp43  于 2023-02-18  发布在  其他
关注(0)|答案(2)|浏览(153)

在执行下面的一小段代码时,每次我输入一个字符,输出都会重复,我不明白为什么。有人能给我解释一下为什么会这样吗?ps:刚刚开始我的c编程之旅。
如果我打印了一个字符,比如'a',我应该输出1,然后另一个提示符要求我再次输入一个字符,但是我得到了1,一个提示符,然后又是1,然后另一个提示符要求我输入一个字符。

#include <stdio.h>

int main()
{
  int usr_ch;
  for ( usr_ch = 0; (usr_ch != 'q');){
       printf("Enter a single character: (enter 'q' to stop)\n");
       usr_ch = getc(stdin);
       printf("%d\n", (usr_ch != 'q') ? 1 : 0));
  }
  return 0;
}
input: u
output:
Enter a single character: (enter 'q' to stop)
1
Enter a single character: (enter 'q' to stop)
1
Enter a single character: (enter 'q' to stop)
siotufzp

siotufzp1#

您已经有了一个很好的答案,解释了用户按ENTER键时生成的额外'\n'字符。从问题下面的注解继续,以及@AllanWard关于使用fgets()的注解,它可以提供将所有单个字符作为输入并在只按ENTER键时结束输入的功能。还有许多其他好处。
使用fgets()阅读行时,将输入读入缓冲区(字符数组或分配的内存块)。* 不要节省缓冲区大小... * fgets()读取并包括它填充的缓冲区中的尾随'\n'。这意味着消耗了整行输入,如果缓冲区大小足够,则包括尾随的'\n''\n'不会留在输入缓冲区(stdin)中未读取。这将避免您遇到的问题。
要访问数组中的第一个字符,你所需要做的就是去引用指针。(数组在访问时被转换成指向它的第一个元素的指针,C18标准-6.3.2.1(p3))。所以如果你声明char line[1024];来保存输入,只需引用*line就可以访问第一个字符。
使用fgets()避免了新的C程序员使用scanf()时遇到的所有陷阱,并且避免了'\n'未被读取的情况。(以及不是很新的C程序员)使用fgets()接受所有用户输入(或POSIX getline(),其行为方式相同,但也可以提供自动分配以处理任意长度的字符串)
除了接受输入之外,您还可以通过几个简单的测试确保用户只输入了一个可打印的字符。这允许您根据需要处理个别错误情况。使用fgets()并处理几个可预见错误情况的简短示例可以写成:

#include <stdio.h>
#include <ctype.h>

#define MAXC 1024     /* if you need a constant, #define one (or more) */

int main (void)
{
  char line[MAXC];    /* buffer to hold line */
  
  /* prompt and then read input into line */
  while (fputs ("Enter a single character: (enter alone to stop): ", stdout) &&
         fgets (line, MAXC, stdin)) {
    /* if ENTER alone, break */
    if (*line == '\n') {
      puts ("exiting");
      break;
    }
    /* if not a single-character, handle error */
    else if (line[1] != '\n') {
      fputs ("  error: more than 1 char entered.\n", stderr);
    }
    /* if printable character, output */
    else if (isprint ((unsigned char)*line)) {
      printf ("  you entered '%c'\n", *line);
    }
    else {  /* otherwise, handle error */
      fputs (" error: non-printable character generated.\n", stderr);
    }
  }
}

(**注:**这些只是你可以使用的分类测试的几个例子。你可以随意添加或删除。你甚至可以为不可打印的字符提供一个查找表,并输出一个表示,例如'\t',当一个字符被按下时,这完全取决于你。)

使用/输出示例

下面将练习所涵盖的每种错误情况('\t'字符用于不可打印字符),例如

$ ./bin/fgets-char
Enter a single character: (enter alone to stop): a
  you entered 'a'
Enter a single character: (enter alone to stop): b
  you entered 'b'
Enter a single character: (enter alone to stop): q
  you entered 'q'
Enter a single character: (enter alone to stop): Q
  you entered 'Q'
Enter a single character: (enter alone to stop):
 error: non-printable character generated.
Enter a single character: (enter alone to stop): foo
  error: more than 1 char entered.
Enter a single character: (enter alone to stop):
exiting

使用getc()fgetc()getchar()将单个字符作为输入绝对没有错,但是必须处理任何未读的附加字符(包括尾随的'\n')。那么如果用户连续按两次ENTER键,或者一只猫踩在键盘上产生500次按键?这就是fgets()可以提供帮助的地方。
另一种方法,不幸的是在不同操作系统之间不可移植,是将终端置于原始无缓冲(非规范)模式,在这种模式下输入立即被处理。对于Linux,您可以使用tcsetattr()。(您也可以使用setvbuf,请参阅man 3 setbuf在无缓冲,行缓冲或全缓冲输入之间切换)对于Windows,可以使用getch()
值得在您继续学习C语言时探索每一个。如果您有进一步的问题,请让我知道。

edqdpe6u

edqdpe6u2#

默认情况下,当您输入“u\n”时,stdin是面向行的,因此getc()将首先返回u,并在下一次调用中返回\n
在这种情况下,使用do-while-循环(或者在循环体末尾有一个break的for(;;))会更自然。然后读取循环中的一个字母,直到找到一个你喜欢的字母(即不是\n)。处理EOF是一个好主意。

#include <stdio.h>

int main() {
    int usr_ch;
    do {
        printf("Enter a single character: (enter 'q' to stop)\n");
        while((usr_ch = getc(stdin)) && usr_ch == '\n');
        printf("%d\n", usr_ch != 'q'));
    } while(usr_ch != 'q' && usr_ch != EOF);
}

以下是示例运行:

Enter a single character: (enter 'q' to stop)
a
1
Enter a single character: (enter 'q' to stop)
q
0

A您也可以只对一行使用fgets(),或使用scanf(" %c", &usr_ch)忽略前导白色。

相关问题