【问题标题】:Nested Conditional Operators in C [duplicate]C中的嵌套条件运算符
【发布时间】:2013-06-27 09:07:42
【问题描述】:

我在使用 C 中的嵌套条件运算符时遇到了一点麻烦。

int is_correct() {

  char YN ;

  printf( "Y or N : " ) ;
  scanf( "%c", &YN ) ;
  YN = toupper( YN ) ;

  return ( YN == 'Y' )? 1 : ( YN == 'N' )? 0 : is_correct() ;
}     

我的印象是,如果输入了“Y”或“N”,最后一行代码将返回 1 或 0,如果输入了意外字符,则会再次调用自身。相反,无论输入如何,它都会不断地调用自己。

【问题讨论】:

  • 这可能不是问题,但我会在多条件中使用括号:return (YN == 'Y') ? 1 : ((YN == 'N') ? 0 : is_correct()) ;
  • 你为什么要编写愚蠢的代码并期望得到一个非愚蠢的答案?
  • @Mat:不,不是。只要条件包含在() 中,就像在 OP 的情况下一样,在解析这些条件运算符时就没有任何歧义。额外的() 完全没有必要。对于某些人来说,它们可能会提高可读性,而对于某些人来说,它们实际上可能会使情况变得更糟。事实上,() 周围的条件也是不必要的,但它们确实有助于阅读代码。至于额外的()...不,OP的版本非常好。
  • @Ed S:没必要,当然。但它使阅读更容易。 (void) 是表示 C 中没有参数的正确方法,而不是 ()
  • @camelccc:如果YNsigned char,那么对toupper() 的调用会调用UB。

标签: c


【解决方案1】:

可能扫描失败,您没有验证它。

您没有指定“连续”是否意味着“不停地阅读更多输入”,它当然应该这样做。

请注意,例如,toupper() 使用 int 类型的参数和结果,并且期望 unsigned char 类型的值您可能会在那里遇到未定义的行为。

这是ctype.h 函数的一个真正令人困惑的方面。如果数据来自文本 (char) 缓冲区,我倾向于在调用中转换为 unsigned char

添加printf() 调用以在最后一行之前打印出YN 的值。

【讨论】:

  • 如果c 不是unsigned charUB 就会发挥作用,这里可能就是这种情况。
  • scanf() 没有问题;问题是 %c 转换被指定为与您可能合理预期的方式不同。
【解决方案2】:

%c 转换不会读取您必须在单字符答案后键入的换行符。

一般来说,scanf() 造成的问题远远多于其价值。尝试使用getline()stdin 中的字符串读入字符串,然后使用sscanf() 从字符串中提取字符。

除其他外,getline() 允许您指定最大输入长度,因此您可以轻松避免字符串缓冲区溢出。

【讨论】:

  • fgets() 不久前被弃用并在 C11 中删除。你应该改用fgets_s()
  • 谢谢你,@busy_wait。将fgets() 替换为getline(),如stackoverflow.com/questions/16323185/… 中所述
  • 不正确。也许你正在考虑gets()。
  • @fizzer:你是对的,我的错。不过,fgets() 仍然不安全。
  • 不确定在 OP 在终端与用户交互的场景中有什么不安全的地方。
【解决方案3】:

scanf("%c",&YN) 中,在转换说明符%c 之前放置一个空格,就像scanf(" %c",&YN) 吃掉换行符(\n)

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

int is_correct(void) 
{
   char YN ;
   printf( "Y or N : " ) ;
   scanf(" %c",&YN);
   YN = toupper( YN );

   return  YN == 'Y' ? 1 :  YN == 'N' ? 0 : is_correct() ;
}     

int main()
{ 
    printf("%d",is_correct());
    return 0;
}

我已经测试过了。如果您只输入一个字符(不包括\n),工作正常!
以更有效的方式,您可以这样做;将第一个字符存储到char ch 中,然后使用循环while((YN = getchar()) != '\n') 吃掉所有其他字符,包括\n。例如:如果您输入ynabcd,第一个字符y 将作为Y 存储在ch 中,其余字符将被while( 循环吃掉。

int is_correct(void) 
{
   char YN ;
   printf( "Y or N : " ) ;
   scanf("%c",&YN);
   char ch = toupper( YN );
   while((YN = getchar()) != '\n')
    ; 
   return  ch == 'Y' ? 1 :  ch == 'N' ? 0 : is_correct() ;
}   

【讨论】:

  • 无论您使用getchar 还是scanf("%c") 都没有关系,问题是一样的:您只从输入缓冲区中读取1 个字符,但有两个:您输入的真正字符和 \n 因为您以 ENTER 结束输入。因此该函数将读取带有getchar 的字符,并看到还有一个字符并再次检查它的值。如果你输入超过 1 个字符,比如“ab”,你会得到 3 次“Y 或 N”,因为缓冲区中有 3 个字符。这就是为什么您会看到两次“Y 或 N”。
  • 但是当你使用scanf时,它不会在输入YN以外的字符时给出结果。但你的观点是有效的,主要问题是\n。跨度>
  • 要消除此问题,您只需在可能的重新调用之前从缓冲区中读取所有字符:将while (getchar() != '\n'); 放在 return 语句之前是一种解决方案。
  • @hacks btw 你是哪个 c 编译器?
猜你喜欢
  • 2014-01-09
  • 2015-03-12
  • 2010-12-27
  • 2019-11-14
  • 2021-05-27
  • 1970-01-01
  • 2021-12-19
  • 2014-08-15
  • 2011-06-13
相关资源
最近更新 更多