C语言bool类型do-while循环异常:仅执行两次退出问题排查
问题描述
需要实现一个do-while循环:仅当输入4位数字时终止循环;输入纯字母、5位及以上数字,或混合内容时,循环持续运行并提示错误。当前代码无论输入是否符合条件,仅执行两次就退出,不符合预期。
原代码:
#include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> int main(int argc, char* argv[]) { ssize_t num; char guess[5], *red_alert="Wrong Input\n"; int numb; bool is_valid_input=false; // we will start with an assumption that its wrong do{ num=read(0, guess, sizeof(guess)); // read in the value from input; numb=atoi(guess); // converts our input to a number if (num == 0){// if num = 0, it means End-Of-File (EOF) break; } if (numb == 0 || numb > 9999){ /* if numb equals 0, then it means only alphabets were entered as input and if the value of numb is greater 9999, then a 5-digit number was entered as input. */ write(1,red_alert,strlen(red_alert)); /* will send wrong input message to stdout and retain the value assigned to "is_valid_input". */ } if (numb>= 1000 && numb <= 9999){// this means that a 4 digit input was entered. is_valid_input=true; /*This should be the only reason why the loop should end */ } } while(is_valid_input == false); return 0; }
问题排查
- 缺少字符串终止符:
read()读取原始字节不会自动添加'\0',atoi()处理无终止符的数组会触发未定义行为,可能得到意外数值,导致错误设置is_valid_input=true,提前退出循环。 - 未重置状态标记:
is_valid_input仅在初始化时设为false,若某次循环意外将其设为true,后续循环无法重置,直接退出。 - 输入缓冲区残留数据:当输入内容超过
guess数组长度时,剩余数据会留在缓冲区,下一次read()直接读取残留数据,导致逻辑异常。 - 判断逻辑不完整:混合数字和字母的输入(如"123a")会被
atoi()转换为123,既不满足错误条件也不满足终止条件,不会输出提示,不符合预期。 - 未处理读取错误:
read()返回-1表示读取错误,未处理会导致后续逻辑混乱。
正确实现方案
修正后的代码解决了上述问题:
#include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> #include <ctype.h> #define BUFFER_SIZE 6 // 预留空间存储输入内容+换行符+终止符 int main(int argc, char* argv[]) { ssize_t num; char guess[BUFFER_SIZE]; const char* red_alert = "Wrong Input\n"; do{ bool is_valid_input = false; // 每次循环重置状态 memset(guess, 0, sizeof(guess)); // 清空缓冲区 // 留1个字节位置存储终止符,避免越界 num = read(STDIN_FILENO, guess, sizeof(guess) - 1); // 处理EOF或读取错误 if (num <= 0){ break; } // 移除换行符并处理超长输入 if (guess[num - 1] == '\n'){ guess[num - 1] = '\0'; } else { // 清空缓冲区剩余数据,避免影响下一次输入 char c; while (read(STDIN_FILENO, &c, 1) > 0 && c != '\n'); guess[sizeof(guess)-1] = '\0'; } // 验证是否为纯数字 bool is_all_digits = true; for (int i = 0; guess[i] != '\0'; i++){ if (!isdigit(guess[i])){ is_all_digits = false; break; } } // 判断是否为4位纯数字 int numb = atoi(guess); if (is_all_digits && numb >= 1000 && numb <= 9999){ is_valid_input = true; } else { write(STDOUT_FILENO, red_alert, strlen(red_alert)); } } while(!is_valid_input); return 0; }
关键修正点
- 循环内重置
is_valid_input,确保每次循环从初始状态开始。 read()时预留字节存储终止符,避免atoi()的未定义行为。- 处理超长输入,清空缓冲区残留数据,避免干扰后续循环。
- 新增纯数字验证逻辑,严格判断输入格式,避免混合内容误判。
- 处理
read()返回的EOF和错误情况,增强鲁棒性。
内容的提问来源于stack exchange,提问作者Ajekwe Moses
相关产品推荐
相关产品推荐

