C语言进制转换程序无限重复输出同一结果问题求助
问题描述
课程作业要求:通过命令行读取输入文件,忽略@开头的注释行,实现进制转换功能。编写的C程序运行时,第一个数字能正确转换,但之后无限重复输出第一个结果,行号持续递增,请求修复建议。
我的代码
#include <stdio.h> #include <math.h> #include <string.h> #include <ctype.h> void data_line(char line[]) { int input_base; char value[35]; int output_base; sscanf(line, "%d %s %d", &input_base, value, &output_base); int n = strlen(value); int decimal = 0; for (int i = n - 1; i >= 0; i--) { if (value[i] >= '0' && value[i] <= '9') { decimal += pow(input_base, n - i - 1) * (value[i] - '0'); } else { value[i] = tolower(value[i]); decimal += pow(input_base, n - i - 1) * (value[i] - 'a' + 10); } } char output[35]; int k = 0; while (decimal > 0) { int rem = decimal % output_base; if (rem >= 10) output[k] = ('A' + rem - 10); else output[k] = ('0' + rem); k++; decimal = decimal / output_base; } if (k == 0) { printf("0\n"); } else { for (int i = k - 1; i >= 0; i--) printf("%c", output[i]); printf("\n"); } } int main(int argc, char * argv[]) { FILE * fp = fopen(argv[1], "r"); char line[100]; int line_no = 1; while (fscanf(fp, "%[^\n]%*c", line) != EOF) { if (line[0] >= '0' && line[0] <= '9') { printf("%d: ", line_no); data_line(line); } line_no++; } fclose(fp); }
输入文件示例(input.txt)
@ a first example 8 70 4 2 011100 16 7 0 21 11 3A 10
程序错误输出
2: 320 3: 320 4: 320 5: 320 6: 320 7: 320 8: 320 9: 320 10: 320 ...(无限重复)
期望输出
2: 320 4: 1C 5: 0 6: 43
问题原因及修复方案
1. 死循环核心原因:fscanf格式错误
fscanf(fp, "%[^\n]%*c", line) 中,%[^\n]仅匹配非换行符的字符,遇到空行时(只有换行符),该格式匹配失败,fscanf返回0而非EOF,循环条件!=EOF依然成立,但line内容未被更新,导致一直重复处理第一行有效数据,line_no持续递增。
修复:改用fgets读取整行,更可靠:
while (fgets(line, sizeof(line), fp) != NULL) { // 移除末尾换行符 line[strcspn(line, "\n")] = '\0'; // 后续逻辑不变 }
2. pow函数的精度误差
pow(input_base, n - i - 1)是浮点数运算,可能出现精度偏差(如pow(8,1)返回7.999999,转int后变为7),导致十进制值计算错误。
修复:用整数循环计算幂次,避免浮点数误差:
long long decimal = 0; long long power = 1; int n = strlen(value); for (int i = n - 1; i >= 0; i--) { int digit; if (isdigit(value[i])) { digit = value[i] - '0'; } else { digit = tolower(value[i]) - 'a' + 10; } decimal += digit * power; power *= input_base; }
3. 其他细节优化
- 注释行判断:原代码仅判断数字开头的行,改为直接跳过
@开头的行,同时过滤空行/格式错误的行:
if (line[0] == '@') { line_no++; continue; } // 仅解析格式正确的数据行 int input_base, output_base; char value[35]; if (sscanf(line, "%d %s %d", &input_base, value, &output_base) == 3) { printf("%d: ", line_no); data_line(input_base, value, output_base); }
- 修改
data_line函数参数,直接接收解析后的进制和数值,避免重复调用sscanf。 - 用
long long存储十进制值,避免大进制转换时溢出。
修复后的完整代码
#include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> void data_line(int input_base, const char *value, int output_base) { long long decimal = 0; long long power = 1; int n = strlen(value); for (int i = n - 1; i >= 0; i--) { int digit; if (isdigit(value[i])) { digit = value[i] - '0'; } else { digit = tolower(value[i]) - 'a' + 10; } decimal += digit * power; power *= input_base; } char output[35]; int k = 0; if (decimal == 0) { printf("0\n"); return; } while (decimal > 0) { int rem = decimal % output_base; output[k] = rem >= 10 ? ('A' + rem - 10) : ('0' + rem); k++; decimal /= output_base; } for (int i = k - 1; i >= 0; i--) printf("%c", output[i]); printf("\n"); } int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage: %s <input_file>\n", argv[0]); return 1; } FILE *fp = fopen(argv[1], "r"); if (!fp) { perror("Failed to open file"); return 1; } char line[100]; int line_no = 1; while (fgets(line, sizeof(line), fp) != NULL) { line[strcspn(line, "\n")] = '\0'; if (line[0] == '@') { line_no++; continue; } int input_base, output_base; char value[35]; if (sscanf(line, "%d %s %d", &input_base, value, &output_base) == 3) { printf("%d: ", line_no); data_line(input_base, value, output_base); } line_no++; } fclose(fp); return 0; }
测试后输出与期望完全一致。
内容的提问来源于stack exchange,提问作者rootof TREE
相关产品推荐
相关产品推荐

