C语言从标准输入读取指定长度字符串的代码优化求助
getString函数优化建议 你的代码目前功能是跑通的,主要问题集中在魔法值零散、逻辑块拆分不清晰、重复计算多、边界处理逻辑藏得太深这几个点,改完好读很多,还能顺便补上几个潜在的逻辑漏洞。
原代码可优化的核心问题
- 合法长度用
lengthOne/lengthTwo/maxLength命名,语义非常模糊,读代码的人没法第一时间反应过来这几个值是「合法输入长度集合」 - 重复调用
strlen(str)计算字符串长度,同一个循环里算好几次,既冗余也打断阅读逻辑 - 替换换行符、清空输入缓冲区残留内容的逻辑散落在do-while循环里,没有做语义拆分,读的时候要逐行捋才知道每块在干嘛
fgets读取长度传maxLength +2的逻辑没有注释,很容易让读代码的人困惑为什么分配了maxLength+1的空间,却要多读2个字节- 循环退出条件写得很长,三个长度判断堆在一起,没法一眼看出判断规则
malloc的返回值没有做校验,内存使用完也没有释放,虽然习题环境里大概率不会触发问题,但不符合C语言编码规范
优化后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> // 定义合法输入长度的常量,用明确的语义命名 #define VALID_LEN_13 13 #define VALID_LEN_15 15 #define VALID_LEN_16 16 #define BUF_SIZE (VALID_LEN_16 + 2) // 缓冲区大小说明:多留2字节,分别存fgets可能读入的换行符、字符串结束符\0,方便判断输入是否超长 /** * 读取用户输入,仅返回长度恰好为13/15/16的字符串 * 返回值为堆上分配的字符串指针,调用方使用后需要手动free释放 */ char *getString() { char *str = malloc(sizeof(char) * BUF_SIZE); if (str == NULL) { // 校验内存分配是否成功 fprintf(stderr, "内存分配失败\n"); exit(EXIT_FAILURE); } size_t input_len = 0; do { printf("请输入长度为%d、%d或%d的字符串:", VALID_LEN_13, VALID_LEN_15, VALID_LEN_16); fgets(str, BUF_SIZE, stdin); // 查找并替换fgets读入的末尾换行符 char *newline_pos = strchr(str, '\n'); if (newline_pos != NULL) { *newline_pos = '\0'; input_len = newline_pos - str; // 直接通过指针偏移算长度,不用重复遍历计算strlen } else { input_len = strlen(str); // 没读到换行说明输入超过缓冲区长度,清空标准输入里残留的内容,避免影响下次读取 int ch; while ((ch = getchar()) != '\n' && ch != EOF); } // 明确判断:输入长度不在三个合法值里就继续循环提示输入 } while (input_len != VALID_LEN_13 && input_len != VALID_LEN_15 && input_len != VALID_LEN_16); return str; } int main() { char *user_input = getString(); printf("输入的字符串内容:%s\n", user_input); printf("字符串长度为:%zu\n", strlen(user_input)); free(user_input); // 释放堆内存,避免内存泄漏 return 0; }
关键优化点说明
- 把零散的魔法值全部改成大写宏定义,命名直接对应语义,读代码的时候不用翻前面的变量赋值找对应数值
- 把原来遍历整个字符串找换行符的逻辑,换成用标准库
strchr函数直接定位换行,效率更高,逻辑也更直观 - 把输入长度提前存在
input_len变量里,不用在循环条件、判断逻辑里反复调用strlen做重复计算 - 把清空输入缓冲区的逻辑和「是否读到换行」的判断绑定在一起,逻辑更顺:只要fgets没读到换行,就说明输入超长有残留,直接清空,比原来判断
strlen>maxLength的逻辑更直观,也补上了原代码没处理EOF导致可能死循环的bug - 给函数加了标准注释,说明函数功能、返回值注意事项,关键逻辑点加了行内注释,不用靠猜理解代码意图
- 变量命名全部换成语义明确的名字,比如main函数里原来的
string改成user_input,一眼就知道是存用户输入的,删掉了lengthOne这类无意义的命名 - 补上了malloc返回值校验、使用完内存后free的规范写法
内容的提问来源于stack exchange,提问作者kbl
相关产品推荐
相关产品推荐

