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

C语言自定义strsub函数未加'\0'致字符串输出异常求助

C语言结构体字段输出异常排查(强制使用strsub函数)

问题背景

读取文件每行数据,通过自定义strsub函数拆分后存入结构体字符数组,再将结构体存入数组,但打印各字段时每个字段会输出后续所有内容,需排查并修复问题(必须保留strsub函数)。

核心错误点拆解

  • 结构体成员数组容量不足,导致终止符越界
    例如type[2]需要存储1个字符+1个'\0',但原代码中strsub(buf, train.type, 10, 11)试图读取2个字符,写入后sub[j] = '\0'会写到type[2],超出数组边界(仅索引0、1有效),破坏内存结构,导致字符串无法正确终止。
    类似的容量不匹配问题存在于多个结构体成员:

    • car[10]:需存10个字符+'\0',数组大小应改为11
    • length[3]:需存2个字符+'\0',原代码读取3个字符会溢出
    • horsepower[3]:同理,原代码读取3个字符溢出
    • numberInTrain[4]:原代码读取4个字符溢出
  • strsub的end参数取值错误
    原代码中end参数为包含式索引,导致读取字符数超过目标数组的可用容量(需留1位给'\0')。

  • while(!feof(fp))逻辑缺陷
    feof仅在读取操作失败后才置位,导致最后一次循环中fgets读取失败(已到文件末尾),但仍会执行拆分和存储操作,引入错误数据。

  • printArray函数声明错误
    原声明void printArray(struct trainCartrain[])中结构体名拼写错误,应为struct trainCar。

修复后的完整代码

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // 补充exit所需头文件
#define MAX 100
FILE *fp, *csit;

void strsub(char buf[], char sub[], int start, int end);
void printArray(struct trainCar arr[], int count); // 增加元素个数参数

struct trainCar {
    char car[11];          // 10个字符 + '\0'
    char type[2];          // 1个字符 + '\0'
    char weight[6];        // 5个字符 + '\0'
    char length[3];        // 2个字符 + '\0'
    char horsepower[3];    // 2个字符 + '\0'
    char numberInTrain[4]; // 3个字符 + '\0'
};

int main() {
    struct trainCar ar[7];
    struct trainCar train;
    int i = 0;
    char buf[MAX];

    if (!(fp = fopen("train.txt", "r"))) {
        printf("train.txt could not be opened for input.\n");
        exit(1);
    }
    if (!(csit = fopen("csit.txt", "w"))) {
        printf("csit.txt could not be opened for output.\n");
        exit(1);
    }

    // 用fgets返回值判断循环,替代feof逻辑
    while (fgets(buf, MAX, fp) != NULL) {
        // 移除每行末尾的换行符
        buf[strcspn(buf, "\n")] = '\0';
        
        // 调整end参数,确保读取字符数=数组容量-1
        strsub(buf, train.car, 0, 9);          // 10个字符
        strsub(buf, train.type, 10, 10);       // 1个字符
        strsub(buf, train.weight, 12, 16);     // 5个字符
        strsub(buf, train.length, 18, 19);     // 2个字符
        strsub(buf, train.horsepower, 21, 22); // 2个字符
        strsub(buf, train.numberInTrain, 24, 26); // 3个字符
        
        ar[i] = train;
        i++;
    }

    printArray(ar, i); // 传入实际存储的元素数量

    fclose(csit);
    fclose(fp);
    return 0;
}

void strsub(char buf[], char sub[], int start, int end) {
    int i, j;
    // 增加边界检查,防止buf索引越界
    if (start < 0 || end >= strlen(buf)) {
        sub[0] = '\0';
        return;
    }
    for (j = 0, i = start; i <= end; i++, j++) {
        sub[j] = buf[i];
    }
    sub[j] = '\0'; // 此时j的取值不会超过数组容量-1
}

void printArray(struct trainCar arr[], int count) {
    for (int k = 0; k < count; k++) {
        printf("车厢类型:%s\n", arr[k].car);
        printf("类型标识:%s\n", arr[k].type);
        printf("重量:%s\n", arr[k].weight);
        printf("长度:%s\n", arr[k].length);
        printf("马力:%s\n", arr[k].horsepower);
        printf("编组序号:%s\n\n", arr[k].numberInTrain);
    }
}

修复说明

  1. 调整所有结构体字符数组的大小,确保能容纳目标字符数+终止符'\0'。
  2. 修改strsub调用的end参数,使读取字符数等于数组容量-1,避免终止符越界。
  3. 用fgets(buf, MAX, fp) != NULL替代while(!feof(fp)),避免最后一次无效循环。
  4. 补充stdlib.h头文件,适配exit函数。
  5. 修复printArray函数的声明和实现,增加元素个数参数,避免固定遍历超出实际存储数量。
  6. 给strsub增加边界检查,防止对buf的越界访问。

验证结果

修复后每个字段会正确输出自身内容,不会带出后续字段数据,示例输出:

车厢类型:Boxcar    
类型标识:D
重量:44000
长度:55
马力:16
编组序号:45

车厢类型:Hopper    
类型标识:B
重量:23000
长度:62
马力:18
编组序号:33
...

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 00:50:15