C语言中如何获取未知长度字符串用于进制转换函数
问题分析与解决方案
一、彻底放弃gets(),改用安全的动态输入方法
gets()是C标准已废弃的函数,它无法限制输入长度,必然引发缓冲区溢出,绝对不能用于处理未知长度的输入。推荐两种安全方案:
1. 使用POSIX标准的getline()(Linux/macOS适用)
getline()会自动根据输入长度动态分配内存,无需手动预设缓冲区大小,使用后记得用free()释放内存。示例代码:
#include <stdio.h> #include <stdlib.h> long int base_b_to_10(char* B, long int base); int main() { long int base; char *input_str = NULL; size_t buf_size = 0; // 输入进制 printf("请输入进制(2-36):"); scanf("%ld", &base); // 清除scanf留下的换行符,避免getline直接读取空行 getchar(); // 输入待转换的数 printf("请输入%d进制数:", base); ssize_t read_len = getline(&input_str, &buf_size, stdin); if (read_len == -1) { perror("读取输入失败"); return 1; } // 去掉末尾的换行符(如果存在) if (input_str[read_len - 1] == '\n') { input_str[read_len - 1] = '\0'; } // 调用转换函数 long int result = base_b_to_10(input_str, base); printf("转换结果:%ld\n", result); // 释放动态分配的内存 free(input_str); return 0; }
2. 手动实现动态扩容的输入函数(跨平台兼容)
如果需要兼容Windows等不支持getline()的环境,可以自己实现动态读取逻辑:初始分配一块内存,当输入超过当前容量时,用realloc()翻倍扩容:
#include <stdio.h> #include <stdlib.h> #include <string.h> long int base_b_to_10(char* B, long int base); char* dynamic_gets() { size_t capacity = 16; // 初始容量 char *str = malloc(capacity * sizeof(char)); if (!str) return NULL; size_t len = 0; int c; // 逐字符读取,直到换行或EOF while ((c = getchar()) != '\n' && c != EOF) { if (len + 1 >= capacity) { // 扩容为原来的2倍 capacity *= 2; char *new_str = realloc(str, capacity * sizeof(char)); if (!new_str) { free(str); return NULL; } str = new_str; } str[len++] = c; } str[len] = '\0'; // 添加字符串结束符 return str; } // 主函数中调用示例: int main() { long int base; printf("请输入进制(2-36):"); scanf("%ld", &base); getchar(); // 清除换行 printf("请输入%d进制数:", base); char *input_str = dynamic_gets(); if (!input_str) { perror("内存分配失败"); return 1; } long int result = base_b_to_10(input_str, base); printf("转换结果:%ld\n", result); free(input_str); return 0; }
二、完善base_b_to_10函数的错误处理
你的转换函数直接使用strtol()但缺少错误检查,输入无效时会返回错误结果,建议添加判断逻辑:
#include <stdlib.h> #include <errno.h> long int base_b_to_10(char* B, long int base) { // 检查进制合法性(strtol支持2-36) if (base < 2 || base > 36) { errno = EINVAL; perror("进制非法"); return 0; } char *endptr; errno = 0; // 重置errno long int N = strtol(B, &endptr, base); // 检查转换错误:无有效数字、超出long范围 if (errno != 0 || endptr == B) { perror("转换失败"); return 0; } // 检查未转换的无效字符 if (*endptr != '\0') { fprintf(stderr, "警告:输入包含无效字符,已忽略后续部分\n"); } return N; }
三、编译器无输出的排查方案
如果程序运行后无输出,按以下步骤排查:
- 检查输出缓冲:若
printf()后无换行符\n,输出可能被缓冲,可添加fflush(stdout);强制刷新。 - 输入处理错误:
scanf("%ld", &base)后未清除换行符,导致后续读取函数直接获取空行,转换函数处理空字符串返回0且无提示。 - 内存分配失败:动态分配内存时
malloc()/realloc()返回NULL但未处理错误,程序直接崩溃或跳过后续逻辑。 - 进制输入非法:输入的进制不在2-36之间,
strtol()返回0且无错误提示,看起来像无输出。 - 未初始化变量:确保所有指针和变量已正确初始化,避免未定义行为导致程序异常。
内容的提问来源于stack exchange,提问作者Fadi EID
相关产品推荐
相关产品推荐

