【问题标题】:Do while can do this but I want to know why this is wrong做虽然可以做到这一点,但我想知道为什么这是错误的
【发布时间】:2021-11-23 21:14:38
【问题描述】:
#include <stdio.h>
#include <rpcndr.h>



int main() {
    boolean playAgain=1;
    char playInput;
    float num1,num2,answer;

    char operator;

    while (playAgain){
        printf("Enter First Number, operator, second number:");
        scanf("%f%c%f",&num1,&operator,&num2);

        switch (operator) {
            case '*':
                answer=(num1*num2);
                break;
            case '/':
                answer=(num1/num2);
                break;
            case '+':
                answer=num1+num2;
                break;
            case '-':
                answer=num1-num2;
                break;
            default:break;
        }
        printf("%f\n",answer);
        printf("Do You Want To Try It Again(y/n)?");
        scanf("%c",&playInput);
        if(playInput=='n'){
            playAgain=0;
        }
    }




}

Do while 可以做这个代码。但我想知道为什么这种方法会出错。 Scanf() 函数存在问题。 错误说: Clang-Tidy: 'scanf' 用于将字符串转换为浮点值,但函数不会报告转换错误;考虑改用“strtof”

【问题讨论】:

  • 不确定 100%,但问题可能是 scanf 中的密集(我的意思是卡住)格式说明符。在scanf(如"%f %c %f")和您的输入中的num1 / operator / num2 之间插入空格后尝试。
  • 您从 clang-tidy 收到的警告可能是由于没有检查 scanf 的返回值以查看它是否成功。
  • scanf("%c", &amp;playInput); 应该是 scanf(" %c", &amp;playInput); 加上空格。 scanf("%f%c%f", &amp;num1, &amp;operator, &amp;num2); 也应该是 scanf("%f %c%f", &amp;num1, &amp;operator, &amp;num2); 加上空格。
  • 为什么? scanf 转换在它无法转换的第一个字符处停止,通常(但不一定)是空格或换行符,并且该字符保留在输入缓冲区中。它将由 next scanf() 格式说明符读取。格式说明符 %d%s%f 会自动过滤这些前导空白字符,但 %c%[]%n 不会。您可以通过在 % 之前添加一个空格来指示 scanf 这样做。

标签: c generics compilation scanf clion


【解决方案1】:

有一些问题。

第一个scanf 不会检查数字中的语法错误,并且可能会在流中留下换行符并混淆第二个scanf

secondscanf可能不会从流中删除换行符,所以在第二次循环迭代中,firstscanf可能有问题。

虽然它可能可以修复/扭曲 scanf 做你想做的事,但我会遵循 clang 的警告并使用 strtof

这是重构为使用fgetsstrtof 的代码。有注释:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <rpcndr.h>

// lineget -- get a line from user with prompt
// RETURNS: pointer to buffer (NULL means EOF)
char *
lineget(char *buf,size_t len,const char *prompt)
{
    char *cp;

    // output prompt to user
    puts(prompt);
    fflush(stdout);

    do {
        // get an input line
        cp = fgets(buf,len,stdin);

        // got EOF
        if (cp == NULL)
            break;

        // strip newline
        buf[strcspn(buf,"\n")] = 0;
    } while (0);

    return cp;
}

int
main(void)
{
    float num1, num2, answer;
    char *cp;
    char buf[1000];
    int err;

    char operator;

    while (1) {
        cp = lineget(buf,sizeof(buf),
            "Enter First Number, operator, second number:");
        if (cp == NULL)
            break;

        // get the first number
        num1 = strtof(cp,&cp);

        // get the operator
        // NOTE: this could be a syntax error for the first number -- we'll
        // check that below in the switch
        operator = *cp;
        if (operator != 0)
            ++cp;

        // get second number and check for syntax error
        num2 = strtof(cp,&cp);
        if (*cp != 0) {
            printf("ERROR trailing '%s'\n",cp);
            continue;
        }

        err = 0;
        switch (operator) {
        case '*':
            answer = (num1 * num2);
            break;
        case '/':
            answer = (num1 / num2);
            break;
        case '+':
            answer = num1 + num2;
            break;
        case '-':
            answer = num1 - num2;
            break;
        default:
            err = 1;
            break;
        }

        // we got a bad operator (or syntax error in first number)
        if (err) {
            printf("ERROR unknown operator '%c'\n",operator);
            continue;
        }

        printf("%f\n", answer);

        cp = lineget(buf,sizeof(buf),"Do You Want To Try It Again(y/n)?");
        if (cp == NULL)
            break;
        if (buf[0] == 'n')
            break;
    }

    return 0;
}

更新:

上面的代码将检测到大多数错误。这是一个增强版本,它进行了更明确的检查:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <rpcndr.h>

// lineget -- get a line from user with prompt
// RETURNS: pointer to buffer (NULL means EOF)
char *
lineget(char *buf,size_t len,const char *prompt)
{
    char *cp;

    // output prompt to user
    puts(prompt);
    fflush(stdout);

    do {
        // get an input line
        cp = fgets(buf,len,stdin);

        // got EOF
        if (cp == NULL)
            break;

        // strip newline
        buf[strcspn(buf,"\n")] = 0;
    } while (0);

    return cp;
}

int
main(void)
{
    float num1, num2, answer;
    char *cp;
    char *bp;
    char buf[1000];
    int err;

    char operator;

    while (1) {
        bp = lineget(buf,sizeof(buf),
            "Enter First Number, operator, second number:");
        if (bp == NULL)
            break;

        // get the first number
        num1 = strtof(bp,&cp);

        // ensure we got at least a digit
        // NOTE: this will detect:
        //   ""
        //   "j"
        if (cp == bp) {
            printf("ERROR no first number specified\n");
            continue;
        }

        // get the operator
        // NOTE: this could be a syntax error for the first number -- we'll
        // check that below in the switch
        operator = *cp;

        // no operator specified
        if (operator == 0) {
            printf("ERROR no operator specified\n");
            continue;
        }

        // skip over the operator
        bp = ++cp;

        // get second number and check for syntax error
        num2 = strtof(bp,&cp);
        if (*cp != 0) {
            printf("ERROR trailing '%s'\n",cp);
            continue;
        }

        // we need at least one digit (e.g.):
        //   we want to reject: 23+ and ensure we have [at least] 23+0
        //   this will detect 23+k
        if (cp == bp) {
            printf("ERROR no second number specified\n");
            continue;
        }

        err = 0;
        switch (operator) {
        case '*':
            answer = (num1 * num2);
            break;
        case '/':
            answer = (num1 / num2);
            break;
        case '+':
            answer = num1 + num2;
            break;
        case '-':
            answer = num1 - num2;
            break;
        default:
            err = 1;
            break;
        }

        // we got a bad operator (or syntax error in first number)
        if (err) {
            printf("ERROR unknown operator '%c'\n",operator);
            continue;
        }

        printf("%f\n", answer);

        cp = lineget(buf,sizeof(buf),"Do You Want To Try It Again(y/n)?");
        if (cp == NULL)
            break;
        if (buf[0] == 'n')
            break;
    }

    return 0;
}

【讨论】:

    【解决方案2】:

    编辑: fflush 是未定义的行为,您可以使用 getchar() 清除缓冲区

    #include <stdio.h>
    
    
    void clear_input_buffer()
    {
        char tmp;
        do
        {
            tmp = getchar();
        } while (tmp != '\n' && tmp != EOF);
    }
    
    int main()
    {
        _Bool playAgain = 1;
        char playInput;
        float num1, num2, answer;
        char operator;
    
    
        while (playAgain)
        {
            printf("Enter First Number, operator, second number:");
            scanf("%f%c%f", &num1, &operator, & num2);
            clear_input_buffer();
            switch (operator)
            {
            case '*':
                answer = (num1 * num2);
                break;
            case '/':
                answer = (num1 / num2);
                break;
            case '+':
                answer = num1 + num2;
                break;
            case '-':
                answer = num1 - num2;
                break;
            default:
                break;
            }
            printf("%f\n", answer);
            printf("Do You Want To Try It Again(y/n)?");
            scanf("%c", &playInput);
            clear_input_buffer();
            if (playInput == 'n')
            {
                playAgain = 0;
            }
        }
    }
    

    旧: 您应该使用 fflush(stdin) (如果您的编译器支持它,它未由 c 标准定义)或不同的方法来清除输入缓冲区,否则 scanf 将在最后读取一个额外的 \n 导致它跳过其余的缓冲区中的数据

    #include <stdio.h>
    
    int main() {
        _Bool playAgain=1;
        char playInput;
        float num1,num2,answer;
    
        char operator;
    
        while (playAgain){
            printf("Enter First Number, operator, second number:");
            scanf("%f%c%f",&num1,&operator,&num2);
            fflush(stdin);
            switch (operator) {
                case '*':
                    answer=(num1*num2);
                    break;
                case '/':
                    answer=(num1/num2);
                    break;
                case '+':
                    answer=num1+num2;
                    break;
                case '-':
                    answer=num1-num2;
                    break;
                default:break;
            }
            printf("%f\n",answer);
            printf("Do You Want To Try It Again(y/n)?");
            scanf("%c",&playInput);
            fflush(stdin);
            if(playInput=='n'){
                playAgain=0;
            }
        }
    }
    

    【讨论】:

    • fflush(stdin) 是未定义的行为——它可能会崩溃或什么都不做。
    猜你喜欢
    • 1970-01-01
    • 2022-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-24
    • 1970-01-01
    • 1970-01-01
    • 2015-04-11
    相关资源
    最近更新 更多