You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 05:10:35