【问题标题】:Boolean expressions on CC 上的布尔表达式
【发布时间】:2016-08-31 03:37:24
【问题描述】:

创建一个简单的 C 函数来防止用户输入除 1 到 9 之间的数字以外的任何内容。不应接受任何其他输入,包括字母符号和任何小于 1 和大于 9 的数字。 到目前为止,它非常简单。但是,代码应该检查输入的字符不是符号或字母的部分没有按照我希望的方式工作。

int validateUserInput(){
    printf("%s\n", "Please enter a number from 1 to 9: ");

    char value = getchar();
    int numValue = value;
    char temp;

    int digitCounter = 0;

    while((temp = getchar()) != '\n'){
        digitCounter++;
    }
    //if there is more than 1 digit.
    if(digitCounter>0){
        printf("%s\n","Input too long!");
        return validateUserInput();
    }
    // if the char entered is not between 1 and 9
    // this part is giving me a hard time.
    else if(numValue < 49 || numValue > 57){
        printf("%s\n", "Imput is not within the valid parameters");
        return validateUserInput();
    }
    return numValue;
}

【问题讨论】:

  • 不要使用 49 和 57;使用'1''9'。 (这是“输入”或“输入”的拼写错误吗?)最好说“输入 1 到 9 之间的单个数字”之类的内容,清楚地表明范围。我什至可以展示你拒绝的价值。
  • 您希望函数返回 ASCII 码还是数字本身?如果是后者,则需要返回numValue - '0';
  • &lt;ctype.h&gt;isdigit( ch )&lt;string.h&gt;strlen( str ),你可以用它来解决你的问题。

标签: c ascii


【解决方案1】:

在使用输入例程进行输入时,还有几点需要注意。如果用户需要取消输入怎么办? (例如,在 Windows 上按 ctrl+dctrl+z)正如您所写,无法取消循环。 (虽然这适用于您仅强制输入 1-9 的目的,但它无法取消)如果您捕获 EOF,则您提供了两种方式,一种取消方式,以及一种在调用函数(例如通过检查 EOF 的返回)

虽然递归有它的位置,但请注意,每个递归本身都是一个单独的函数调用,需要一个单独的堆栈,以及函数调用的所有其他陷阱。很多时候,通过简单的goto 语句可以避免这种情况。 glibc 经常使用goto(例如,检查qsortgetdelim 的来源等。)在您的情况下,单个goto 标签可以完全消除递归的需要。例如,您可以在满足所有条件的同时执行以下类似操作:

int validateuserinput()
{
    int c, extra, tmp;

    getinput:;  /* a simple goto can avoid recursion completely */
    extra = 0;
    printf ("Please enter a number from 1 to 9: ");
    /* prompt/loop while chars not between 1 and 9 */
    for (c = getchar(); (c < '1' || '9' < c ); c = getchar()) {
        if (c == '\n') {    /* no digits in input */
            fprintf (stderr, "error: invalid input.\n");
            goto getinput;
        }
        else if (c == EOF) {  /* trap EOF */
            fprintf (stderr, "\nerror: input canceled.\n");
            return c;
        }
    }
    /* empty input buffer -- increment extra count */
    for (tmp = getchar(); tmp != '\n' && tmp != EOF; tmp = getchar())
        extra++;

    if (extra) { /* if extra chars -- input too long */
        fprintf (stderr, "error: input too long.\n");
        goto getinput;
    }

    return c - '0';  /* return integer value instead of ASCII value */
}

(只是一种风格说明,C 通常避免使用 camelCase 变量名而支持小写,这只是一般性,完全取决于您)

您可以使用以下一小段代码检查功能(并响应取消):

#include <stdio.h>

int validateuserinput();

int main (void) {

    int n;

    if ((n = validateuserinput()) != EOF)
        printf ("\n valid input : %d\n", n);

    return 0;
}

使用/输出示例

测试只接受 1-9 的输入:

$ ./bin/inputhandler
Please enter a number from 1 to 9: Hello World!
error: invalid input.
Please enter a number from 1 to 9: ?
error: invalid input.
Please enter a number from 1 to 9: 0
error: invalid input.
Please enter a number from 1 to 9: 23
error: input too long.
Please enter a number from 1 to 9: 6

 valid input : 6

测试输入取消(例如 ctrl+d 或 Windows 上的 ctrl+z

$ ./bin/inputhandler
Please enter a number from 1 to 9:
error: input canceled.

虽然使用递归并没有错,但问“这是否需要从递归函数开始?” 有时答案是肯定的,但通常有简单的答案避免额外开销的方法。 (注意: 一些递归的开销很小,因此在您的情况下这不是一个重要的考虑因素,但如果您无意中调用了一个旋转一百万次的递归函数,它很快就会成为一个问题)

查看所有答案,如果您有任何问题,请告诉我们。

【讨论】:

  • 我想最好使用for(;;)循环而不是getinput:并将goto getinput替换为continue
  • 是的,这是可能的,但我不确定它一定会改善什么。您基本上将getchar() 移动到现有for 上方,将for 变成if,将底部extra 包裹在else 中,然后将所有这些包裹在for(;;) 中移动循环下方的EOF,同时还包括在初始getchar() 之后的EOF 检查。如果您想先检查数字,您可以反转 if 逻辑,但这种逻辑有点混乱。无论哪种方式都可以。
  • for(;;) 表示无限循环,因此读者会从一开始就知道这一点。所以它肯定会提高可读性。不需要其他更改。
  • 我想我只需要看一个例子。您仍然需要处理上面的extra 循环,并在无限循环 中出现多个数字时清空输入缓冲区。在每次读取时,您都需要检查EOF 或冒着未定义的行为再次在设置了错误条件的流上调用getchar。我在想什么?控制何时显示提示以及所需的错误消息完全是另一回事。
【解决方案2】:

您只设置一次 numValue - 对于第一个 getchar() - 看起来您希望在每个 getchar() 之后设置它。

【讨论】:

    【解决方案3】:
     while((temp = getchar()) != '\n'){
            digitCounter++;
        }
    

    可能

     while((temp = getchar()) != '\n'){
            if (temp < 49 || temp > 57 || ++digitCounter>0)
                return validateUserInput();
        }
    

    我认为这种方式很简单

    【讨论】:

    • 假设用户第一次输入 567 并换行。此代码将在循环外读取 5;它会在你的循环中读取 6 并对函数进行递归调用,然后它会读取 7 和换行符,并对生活感到满意。不过,用户可能会对为什么输入 567 时使用的数字是 7 感到困惑。
    猜你喜欢
    • 1970-01-01
    • 2012-08-26
    • 2010-10-17
    • 2011-05-11
    • 1970-01-01
    • 2010-09-21
    • 2017-02-05
    • 2013-08-04
    • 2012-05-17
    相关资源
    最近更新 更多