简体   繁体   English

C无限做while循环

[英]C infinite do while loop

This is a simple program for a class that prompts the user for the length of his or her shower in minutes (as a positive integer, re-prompting as needed) and then prints the equivalent number of bottles of water (as an integer). 这是一个简单的课程程序,可提示用户以分钟为单位的淋浴时间(正整数,根据需要重新提示),然后打印等量的水(整数)。

It assumes the shower uses 1.5 gallons of water per minute (192 oz) and a plastic bottle size of 16 oz 假定淋浴器每分钟使用1.5加仑水(192盎司),塑料瓶尺寸为16盎司

My do-while loop successfully rejects negative numbers and 0, however, if I input text such as "foo" when prompted for the length of a shower in minutes, the program runs into an infinite loop, forever running the loop and printing "How long is your shower(in minutes)?:" 我的do-while循环成功拒绝了负数和0,但是,如果在几分钟后提示输入淋浴时间,如果我输入“ foo”之类的文本,程序将进入无限循环,永远运行循环并打印“ How你的淋浴多久(以分钟为单位)?:”

Any ideas how to refine the while condition to avoid this? 任何想法如何完善while条件以避免这种情况?

#include <stdio.h>

int min_to_bottles(int *n);

int main(void)
{
    int minutes;
    int bottles;
    do
    {
        printf("How long is your shower(in minutes)?:");
        scanf("%i", &minutes);
    }
    while (minutes < 1);

    bottles = min_to_bottles(&minutes);

    printf("Equivalent of bottles used per shower is: %i\n", bottles);

}

int min_to_bottles(int *n)
{
    int bottles;
    int oz = 192 * *n;
    bottles = oz/16;
    return bottles;
}

Always check the return value of scanf() : 始终检查scanf()的返回值:

int result;
do {
    printf("How long is your shower(in minutes)?:");
    result = scanf("%d", &minutes);
    if(result != 1) 
        break;
} while (minutes < 1);

A shorter version (if only one scan is needed): 较短的版本(如果仅需要一次扫描):

printf("How long is your shower(in minutes)?:");

while ((scanf("%d", &minutes) == 1) && (minutes < 1))
    ;

There is no need to use a pointer as parameter in int min_to_bottles(int *n); int min_to_bottles(int *n);不需要使用指针作为参数int min_to_bottles(int *n); :

#include <stdio.h>

int min_to_bottles(int n)
{
    return (192 * n) / 16;
}

int main(void)
{
    int minutes = 0;
    int bottles = 0;

    printf("How long is your shower(in minutes)?: ");

    while ((scanf("%d", &minutes) == 1) && (minutes < 1 || minutes > 100))
        printf("Enter a number between 1 and 100 : ");

    // if(minutes == 0) here means invalid data was entered.
    //    so a check could be done before continuing.

    bottles = min_to_bottles(minutes);

    printf("Equivalent of bottles used per shower is: %d\n", bottles);

    return 0;
}

Initializing minutes to 0 will avoid calculating the bottles with an undefined value in case scanf() failed (by entering text for example). minutes初始化为0将避免在scanf()失败的情况下scanf()例如通过输入文本scanf()使用不确定的值来计算bottles

When you enter in text, it doesn't match the %i format specifier, so the text gets stuck in the input buffer and it keeps trying to read the same thing. 当您输入文本时,它与%i格式说明符不匹配,因此文本会卡在输入缓冲区中,并且会继续尝试读取同一内容。

You need to flush the buffer if you didn't get a good match. 如果没有很好的匹配,则需要刷新缓冲区。 You'll know if that the case by checking the return value of scanf , which returns the number of patters successfully matched. 通过检查scanf的返回值(返回成功匹配的模式数量),您将知道情况是否如此。

int minutes = 0;
while (minutes < 1)
{
    printf("How long is your shower(in minutes)?:");
    int count = scanf("%i", &minutes);
    if (count < 1) {
        scanf("%*s");   // The * tells scanf to read the input but not assign it to anything
    }
}

Do not use scanf("%i",...) . 不要使用scanf("%i",...)

The main problem is that bad input that did not convert to a number remains in stdin until another function reads it. 主要问题是直到另一个函数读取它之前,没有转换为数字的错误输入仍保留stdin As code did not check the return value of scanf() , the value of minutes is not known to be good and do ... while (minutes < 1); 由于代码没有检查scanf()的返回值,因此minutes的值不佳,并且do ... while (minutes < 1); can easily repeated loop. 可以轻松地重复循环。

Solution: Read a line of input, convert to number, valid number: 解决方案:读取一行输入,转换为数字,有效数字:


To handle unexpected user input begin by reading a line of input 要处理意外的用户输入,请先读取一行输入

char buf[80];
if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EOF();

Then parse the buffer for the number. 然后解析该缓冲区的数字。

errno = 0;
char *endptr;
long num == strtol(buf, &endptr, 0);

// detect overflow and no conversiosn
if (errno || buf == endptr) Handle_BadInput();

// Ignore trailing white-space
while (isspace((unsigned char) *endptr) endptr++;

if (*endptr) Handle_BadInput();

Validate the number. 验证号码。

#define SHOWER_TIME_MIN (1 /* minute */)
#define SHOWER_TIME_MAX (60 /* minute */)
if (num < SHOWER_TIME_MIN || num > SHOWER_TIME_MAX) Handle_BadInput();

Put this all in a helper function 全部放到一个辅助函数中

Example How to test input is sane 示例如何测试输入是否正常

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM