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

C语言循环多次获取用户输入异常:代码仅执行一次求排查

问题排查与修复方案

我帮你梳理下代码里的几个关键问题,这些问题组合起来导致程序只运行一次就结束,还有不少潜在的崩溃风险:

  • 未初始化的指针+过小的缓冲区
    你一开始定义了char *userInput;但没有给它分配内存空间,直接调用fgets(userInput, sizeof(int), stdin);相当于往随机内存地址写数据,这会直接触发未定义行为(程序崩溃或异常退出)。而且sizeof(int)通常只有4字节,缓冲区太小,连"quit"加换行符都放不下,会造成缓冲区溢出。

  • 循环逻辑顺序完全搞反了
    你在进入循环前先读了一次输入,然后进循环后立刻重新分配内存再读一次输入,这就导致第一次输入的内容完全被忽略了。而且循环里是先读新输入再处理,和你“输入不为quit就持续处理”的预期完全不符,这也是程序只运行一次就异常结束的核心原因之一。

  • 结构体指针数组没分配内存,直接访问空指针
    myStructArray是一个存储struct myStruct*的数组,但你没有给数组里的每个元素分配结构体内存,直接写myStructArray[i]->name相当于访问空指针,必然会触发崩溃。

  • fgets读取的换行符导致strcmp判断失效
    fgets会把用户输入时的换行符\n也读进缓冲区,比如用户输入"quit"回车,userInput里存的是"quit\n",和"quit"用strcmp比较永远不会相等,这会导致循环无法正常退出(不过前面的错误可能已经让程序提前终止了)。

  • 未定义变量input
    代码里atoi(input)的input根本没定义,应该是userInput才对。

  • 循环结束后越界访问数组
    最后你用for(int x=0;x<30;x++)遍历数组,但实际添加的元素只有i个,当x>=i时,访问未初始化的指针会导致崩溃。


下面是修复后的示例代码,我加了详细的注释说明改动点:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_ITEMS 30
#define INPUT_BUFFER_SIZE 100  // 设置足够大的输入缓冲区

// 假设全局变量的定义(根据你的代码补充)
typedef struct {
    char name[100];
    float sale;
} InventoryItem;
InventoryItem inventoryItem[MAX_ITEMS];
int deletion = 0;

void searchA(char *input) {
    // 这里是你的searchA函数实现
}

void createReport(){ 
    printf("Welcome to the report generator, type item's ID: "); 
    char userInput[INPUT_BUFFER_SIZE];  // 用固定大小缓冲区,避免动态分配的麻烦
    
    // 先定义结构体类型,方便后续使用
    typedef struct myStruct{ 
        char *name; 
        int id; 
        float sale; 
    } MyStruct; 
    MyStruct *myStructArray[MAX_ITEMS]; 
    int i = 0;

    // 读取第一次输入,先处理读取失败的情况
    if (fgets(userInput, INPUT_BUFFER_SIZE, stdin) == NULL) {
        printf("Failed to read input\n");
        return;
    }

    // 去掉fgets读取的换行符,确保和"quit"比较准确
    userInput[strcspn(userInput, "\n")] = '\0';

    // 循环逻辑:先判断输入是否为quit,不是就处理,再读下一次
    while(strcmp(userInput,"quit") != 0) { 
        // 处理当前输入
        searchA(userInput); 
        printf("Added to the report, add more or type 'quit' \n"); 

        // 给当前结构体指针分配内存
        myStructArray[i] = malloc(sizeof(MyStruct));
        if (myStructArray[i] == NULL) {
            perror("Failed to allocate memory for struct");
            break;
        }
        // 给name成员分配内存,要加1存字符串结束符
        myStructArray[i]->name = malloc(strlen(inventoryItem[deletion].name) + 1);
        if (myStructArray[i]->name == NULL) {
            perror("Failed to allocate memory for name");
            free(myStructArray[i]);  // 释放已经分配的结构体内存
            break;
        }

        // 复制数据到结构体
        strcpy(myStructArray[i]->name, inventoryItem[deletion].name); 
        myStructArray[i]->id = atoi(userInput);  // 修正为userInput
        myStructArray[i]->sale = inventoryItem[deletion].sale; 
        i++;

        // 检查是否超过数组最大容量
        if (i >= MAX_ITEMS) {
            printf("Report is full, cannot add more items\n");
            break;
        }

        // 读取下一次输入
        printf("Type item's ID or 'quit': ");
        if (fgets(userInput, INPUT_BUFFER_SIZE, stdin) == NULL) {
            break;
        }
        userInput[strcspn(userInput, "\n")] = '\0';
    } 

    // 遍历实际添加的元素(用i而不是固定30,避免越界)
    printf("\n--- Report Items ---\n");
    for(int x=0; x<i; x++) { 
        printf("%s (ID: %d, Sale: %.2f)\n", myStructArray[x]->name, myStructArray[x]->id, myStructArray[x]->sale); 
        // 记得释放内存,避免内存泄漏
        free(myStructArray[x]->name);
        free(myStructArray[x]);
    } 
}

修复后的代码主要做了这些优化:

  1. 用固定大小的输入缓冲区代替动态分配,简化内存管理,避免未初始化指针问题;
  2. 调整循环逻辑为「读取→判断→处理→再读取」,符合预期的持续输入流程;
  3. 给结构体和name成员分配内存,避免空指针访问;
  4. 用strcspn去掉换行符,确保strcmp能正确识别"quit";
  5. 修复未定义变量的问题;
  6. 遍历数组时使用实际添加的元素个数i,避免越界访问;
  7. 添加内存分配失败的错误处理,增强程序健壮性;
  8. 最后释放所有分配的内存,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 20:17:50