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

命令行表达式计算器开发遇无限循环问题求助

我来帮你搞定这个无限循环的问题,顺便聊聊输入处理的最优方案~

问题根源:指针越界+错误的内存释放

先拆解你代码里导致无限循环的核心问题:

  • buf指针没有重置:你在处理字符时做了buf += n和buf++,导致处理完一行后,buf指针已经跳到了\n甚至更后面的位置。下一次fgets读取新行时,buf还是停在这个偏移位置,*buf != '\n'的条件永远成立,直接陷入死循环。
  • 错误的链表释放:你用free(head)只释放了头节点,整个链表的其他节点会造成内存泄漏,而且下次循环时head还残留着旧地址,逻辑会混乱。
  • 输入判断不完整:没有考虑输入超长被截断后没有\n的情况,也没支持小数输入(比如12.5这种)。
输入处理的最优选择:fgets其实很合适

你不用换输入函数,fgets是处理行输入的安全选项——它能限制读取长度,避免缓冲区溢出,完全适配你“像Shell一样读一行算一行”的需求,只要正确管理指针位置就行。

修正后的代码及关键改动

下面是调整后的完整代码,我标注了核心改动点:

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#define MAX 100

struct n{
 double value;
 char op;
 struct n *next;
};

void print_list(struct n *head);
void add_item(struct n **ptr, double *data);
void free_all(struct n *head);
void f(double x);

int main() {
 struct n *head = NULL;
 char *buf = malloc(MAX * sizeof (*buf));
 char *buf_start = buf; // 保存缓冲区初始地址,用于每次重置
 int n;
 double num;

 for(;;) {
    head = NULL; // 处理新行前重置链表头
    printf("> "); // 加个提示符,更像Shell交互
    if(fgets(buf_start, MAX, stdin) == NULL) {
        free_all(head);
        free(buf_start);
        return 0;
    }
    buf = buf_start; // 每次处理新行,把buf指针重置到起始位置
    // 同时判断是否到字符串末尾(应对输入超长截断的情况)
    while (*buf != '\n' && *buf != '\0') {
        // 支持小数输入,加入对'.'的判断
        if (isdigit(*buf) || *buf == '.') {
            sscanf(buf, "%lf%n", &num, &n);
            add_item(&head, &num);
            buf += n;
        } else {
            // 这里后续可以扩展处理运算符,比如保存到节点的op字段
            buf++;
        }
    }
    printf("当前链表存储的数字:");
    print_list(head);
    printf("\n");
    free_all(head); // 正确释放整个链表,避免内存泄漏
 }
 free(buf_start); // 程序结束前释放缓冲区
 return 0;
}

// 调整递归顺序,让数字正向输出(原代码是反向输出)
void print_list(struct n *head) {
 if (head != NULL) {
    print_list(head->next);
    f(head->value);
 }
}

void add_item(struct n **ptr, double *data) {
 struct n *item = malloc(sizeof *item);
 item->value = *data;
 item->next = *ptr;
 item->op = '\0'; // 初始化为空,后续处理运算符时再赋值
 *ptr = item;
}

void free_all(struct n *head) {
 struct n *tmp;
 while (head != NULL) {
 tmp = head;
 head = head->next;
 free(tmp);
 }
}

void f(double x) {
 double i, r = modf(x, &i);
 if(fabs(r)<.00001) printf("%.f ",i);
 else printf("%f ",x);
}

关键改动说明:

  • 新增buf_start保存缓冲区初始地址,每次处理新行时重置buf指针,彻底解决无限循环问题
  • 处理输入时增加*buf != '\0'判断,覆盖输入超长被截断的场景
  • 每次循环前重置head = NULL,避免链表残留上一次的数据
  • 把free(head)替换为free_all(head),正确释放整个链表
  • 调整print_list的递归顺序,让数字按输入顺序正向输出
  • 支持小数输入,增加对.的判断
  • 加入Shell风格的提示符> ,提升交互体验
额外优化建议
  • 如果要处理运算符,可以在else分支里判断+-*/^()等字符,把运算符保存到链表节点的op字段
  • 递归实现的print_list在链表过长时可能栈溢出,建议改成迭代版本:
    void print_list(struct n *head) {
        struct n *current = head;
        while (current != NULL) {
            f(current->value);
            current = current->next;
        }
    }
    

内容的提问来源于stack exchange,提问作者Michaelangelo Meucci

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:29:37