【问题标题】:Using boolean flag to detect input error, C使用布尔标志检测输入错误,C
【发布时间】:2014-09-03 07:45:18
【问题描述】:

我正在尝试创建一个布尔标志,当输入无效的输入代码时将输出错误消息。这是课堂作业,我只是在学习 C,所以请原谅格式并通知我是否可以改进。除了在输入或输出变量不正确时输出错误消息外,我的代码一切都成功了。我相信这是代码的布尔检查部分的错误。诊断会很棒。

此代码将:

  • 请求和来源货币、目标货币和来源金额
  • 如果输入变量不正确,输出目的货币金额或错误信息

参数:

  • 来源和目的地货币必须是加元 ($)、日元 (Y) 或欧元 (E)
  • 必须使用布尔标志

提前致谢。

# include <stdio.h>

int main() {

    char $ = $; 
    char Y = Y;
    char E = E;

    char in_currency, out_currency;

    char flag = 1;
    char new_line;

    float in_value;
    float out_value;

    //Calculation variables

    printf("Enter the source currency: ");
    scanf("%c%c", &in_currency, &new_line);

    printf("Enter the destination currency: ");
    scanf("%c%c", &out_currency, &new_line);

    if ( ( in_currency || out_currency ) != ( '$' || 'Y' || 'E' ) )
        flag = 0;

    printf("Enter the value: ");
    scanf("%f%c", &in_value, &new_line);

    //Calculations

    if (flag) {
        printf("%c%.2f = %c%.2f \n", in_currency, in_value, out_currency, out_value);
    }
    else {
        printf("There was an error with the input. \n");
    }

    return 0;
}

【问题讨论】:

  • in_currency || out_currency ) != ( '$' || 'Y' || 'E' ) 你不能这样检查 jn 并且 p.s 你的 char $ char E char Y 没用
  • $ 在 C 中不是有效的变量名。变量名必须以字母或下划线开头,并且只能包含字母、数字或下划线。
  • 这些语句:char $ = $; char Y = Y; char E = E; 通过使用它们自己的未初始化值初始化变量来调用未定义的行为(或者,至少没有取得任何有用的结果)。变量 $ 在标准 C 中无效;您可能会找到一个允许它的 C 编译器(特别是如果您在 VMS 上工作)。可悲的是,这不是一个好的开始。其余代码不使用变量这一事实是另一个问题。您可以简单地删除它们。
  • 请注意,如果用户输入“源货币”作为 GPB,new_line 变量将不会包含换行符。使用" %c" (space, percent, c) 作为格式字符串可能会做得更好;它会跳过前导空格(空格、制表符、换行符),然后是一个字符。对目标货币重复;它将跳过您期望的换行符,然后读取下一个非空白字符。 "%f%c" 格式没有什么意义;它不能保证你会读到一个换行符(而且你不会检查它)。
  • @Barmar 这是 GCC 和 MSVC 的扩展 stackoverflow.com/questions/7926394/in-variable-name

标签: c if-statement char boolean flags


【解决方案1】:

感谢 @JonathanLeffler 的优秀 cmets。

我相信这可能是由于你的 if 语句的逻辑顺序

 if ( ( in_currency || out_currency ) != ( '$' || 'Y' || 'E' ) )
    flag = 0;

你的意图如下

 if ( 
  (in_currency == '$' ||  in_currency == 'Y' ||  in_currency == 'E')
  || 
  ( out_currency == '$' ||  out_currency == 'Y' ||  out_currency == 'E') 
  ) flag = 0;

这是由于您的原始行的评估方式。 ( in_currency || out_currency )

注意C++ standard(第 6.8.4.1 节)状态

如果表达式比较不等于 0,则执行子语句。

和打字一样 ( in_currency != 0 || out_currency =!0) 请注意,测试单个值将始终针对非零值进行测试,有时被认为是“真”值。

简而言之,if 语句的第一部分将始终返回 true,因为两个测试(非零字符值)都等于 true。

可以将其视为(in is not zero OR out is not zero),因为两个值都不为零,两个测试相等为真,变为 (true OR true) - 显然这又是真的。

if 语句的后半部分略有不同

 ( '$' || 'Y' || 'E' ) 

这也将等同于存在( true OR true Or True ),因此始终等同于 true 例如:

( '$' != 0 || 'Y' != 0 || 'E' != 0) 

最后,这分解为您的代码阅读:

 if ((in_currency != 0 || out_currency =! 0) != ( '$' != 0 || 'Y' != 0 || 'E' != 0)) 

 if ((true || true) != ( true || true || true)) 
 if ((true) != (true))

显然,这将总是等同于 false,因为 true 永远不等于 true(除非某些通用常量发生变化 ;-)

结果是你的标志总是假的。 - 总是

我给你的行来替换它,而是分别测试每个可能的案例场景并比较结果。

你可以这样理解

  if 
      in_currency **is equal to** '$' *or*  
      in_currency **is equal to** 'Y' *or*
      in_currency **is equal to** 'E'
    or 
      out_currency **is equal to** '$' *or*  
      out_currency **is equal to** 'Y' *or*
      out_currency **is equal to** 'E'
 then flag = 0;

[编辑]

用户 Turboc 在下面回答说您可能希望在这两个语句之间使用 && (and) 而不是 。(请原谅我将这些信息放在这里,但是我还不能对答案发表评论)

这取决于您打算如何评估您的语句 - 如果您希望标志等于 false (0),如果货币是上述任何一种,用于输出或输入,那么情况并非如此)。

但是,如果您希望声明正确,只要货币是上述货币之一,您可以使用以下

  if 
      in_currency **is equal to** '$' *or*  
      in_currency **is equal to** 'Y' *or*
      in_currency **is equal to** 'E'
    and 
      out_currency **is equal to** '$' *or*  
      out_currency **is equal to** 'Y' *or*
      out_currency **is equal to** 'E'
 then flag = 1;

但是,如果是这种情况,您可能希望确定哪个答案更有效地解决您的问题。

【讨论】:

  • 我想投票(如果你编辑,我仍然可以),但你对if ((in || out) != ('A' || 'B' || 'C')) 的翻译对我不起作用。我同意 100% 原件坏了(但我会回到你对它是如何坏的描述 - 尼特也可以在那里挑选)。原文的意思可能是:如果in 不是“A”或“B”或“C”之一,或者如果out 不是“A”或“B”之一或'C',然后将 flag 设置为 0。 您的翻译缺少否定。我想你需要更像if ((in != 'A' &amp;&amp; in != 'B' &amp;&amp; in != 'C') || (out != 'A' &amp;&amp; out != 'B' &amp;&amp; out != 'C')) flag = 0; 的东西。
  • 您对(in_currency || out_currency) 的分析与输入(in_currency == true || out_currency == true) 相同,我也很担心。更精确的表征是(in_currency != 0 || out_currency != 0)。之所以出现差异,是因为true 是通过&lt;stdbool.h&gt; 定义为1。只有in_currency 为 1 或 out_currency 为 1,您的翻译才会生成 true;但是,如果in_currency 是任何非零值或out_currency 是任何非零值,则原始代码会生成 true ——它只会在两个变量都为 0 时生成 false。请非常小心!
  • @JonathanLeffler ,我很欣赏建设性的批评。对于您的第一点,我同意我的措辞有点复杂。至于你的第二个,这实际上是我自己的误解——但这就是我不阅读标准的结果。我一定会尽快更正它。
【解决方案2】:

将一些 cmets 和其他注释转换为答案

这些语句:char $ = $; char Y = Y; char E = E; 通过使用它们自己的未初始化值初始化变量来调用未定义的行为(或者,至少没有取得任何有用的结果)。变量 $ 在标准 C 中无效;您可能会找到一个允许它的 C 编译器(特别是如果您在 VMS 上工作)。可悲的是,这不是一个好的开始。其余代码不使用变量这一事实是另一个问题。您可以简单地删除它们。

请注意,如果用户输入“源货币”作为 GPB,new_line 变量将不会包含换行符。使用" %c" (space, percent, 'c') 作为格式字符串可能会更好;它会跳过(可选)前导空格(空格、制表符、换行符),然后是一个字符。对目标货币重复;它将跳过您期望的换行符,然后读取下一个非空白字符。 "%f%c" 格式没有什么意义;它不能保证你会读到换行符(而且你不会检查它)。

此外,正如其他人也指出的那样,条件:

if ( ( in_currency || out_currency ) != ( '$' || 'Y' || 'E' ) )

不做你想让它做的事情。由于 C 的工作方式,!= 的 RHS 评估为真(因为 '$' 不为零),并且它的 LHS 评估为真,除非 in_currencyout_currency 都为零,这是非常不太可能(很多人不知道如何在键盘上输入 ASCII NUL——也就是零字节或'\0')。

正如我在评论中指出的那样:

原文的意思可能是:_如果in_currency 不是'$''Y''E' 之一,或者如果out_currency 不是'$''Y' 之一或'E',然后将 flag 设置为 0。

你需要更多类似的东西

if (( in_currency != '$' &&  in_currency != 'Y' &&  in_currency != 'E') ||
    (out_currency != '$' && out_currency != 'Y' && out_currency != 'E'))
    flag = 0;

我看到一个版本的条件写成:

if (( in_currency != '$' ||  in_currency != 'Y' ||  in_currency != 'E' ) ||
    (out_currency != '$' || out_currency != 'Y' || out_currency != 'E' ))
    flag = 0;

这不能正常工作。想一想:假设in_currency 是 Y(日元)。术语 in_currency != '$' 将为真(因为值为 Y),因此整体条件将为真(不评估任何进一步的术语)并且 flag 将设置为零。如果你用&amp;&amp; 分隔in_currency 术语,那么in_currency != '$' 为真,但in_currency != 'Y' 为假,所以条件的(in_currency != '$' &amp;&amp; in_currency != 'Y' &amp;&amp; in_currency != 'E') 部分为假——这很好,因为货币代码是有效的。然后它会继续评估out_currency 条款(也包括&amp;&amp;),并且如果out_currency 值正确,也会通过。

请注意,(a != v1 || a != v2) 形式的条件(其中相同的变量 a 与两个不同的值 v1v2 进行比较)始终是同义词。请注意,在这方面,常见的英语用法有点滑;您必须非常小心和挑剔才能使条件正确。您还需要了解德摩根定理 (q.v.)。

您的代码还存在其他问题。例如,您的错误消息不是很丰富。在您有足够的信息知道数据无效后,您需要用户继续输入数据。您需要确保您的代码能够处理用户选择从欧元转换为欧元的情况(或者,更一般地说,输入相同的货币代码两次)。

编写好的代码在一定程度上是一种了解用户如何破坏您的最佳意图并在问题发生之前避免麻烦的练习。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-29
    • 2018-04-30
    • 1970-01-01
    • 1970-01-01
    • 2017-01-12
    • 2022-11-16
    • 1970-01-01
    相关资源
    最近更新 更多