当前位置: 首页 > news >正文

C语言运行时候出现栈溢出、段错误(Segmentation fault)、异常码解决?

将下面源代码的MAX_KENNWERTE 值修改成1000就报错了?

报出fail section错误,意思是错误段。

原因是:

最可能的两个原因:

  1. 栈爆了(Stack overflow)
  • 你在 main 里一次性在栈上放了 6 个大数组:
    • Kennwert newarr/oldarr/merged(3份)
    • Kennlinien newarrien/oldarrien/mergedien(3份)
  • 以当前结构体大小粗算:
    • sizeof(Kennwert) ≈ 264 字节
    • sizeof(Kennlinien) ≈ 520 字节
    • MAX_KENNWERTE=1000 时,栈上内存 ≈ 31000264 + 31000520 ≈ 2.35 MB
  • Windows/MSVC 默认主线程栈大小常见为 1MB,1000 会溢出,256(约 0.6MB)还能勉强过。
  • 解决:
    • 把这些大数组改成堆分配(malloc/calloc),或做成 static(放到全局/BSS),或提高栈大小(不推荐作为首选)。
    • 示例(推荐堆):

      c

      Kennwert*   newarr     = calloc(MAX_KENNWERTE, sizeof(*newarr));
      Kennlinien* newarrien  = calloc(MAX_KENNWERTE, sizeof(*newarrien));
      Kennwert*   oldarr     = calloc(MAX_KENNWERTE, sizeof(*oldarr));
      Kennlinien* oldarrien  = calloc(MAX_KENNWERTE, sizeof(*oldarrien));
      Kennwert*   merged     = calloc(MAX_KENNWERTE, sizeof(*merged));
      Kennlinien* mergedien  = calloc(MAX_KENNWERTE, sizeof(*mergedien));
      if (!newarr || !newarrien || !oldarr || !oldarrien || !merged || !mergedien) { /* 处理内存不足 */ }
      ...
      free(newarr); free(newarrien); free(oldarr); free(oldarrien); free(merged); free(mergedien);
      
    • 或临时把数组前加 static 关键字,移到静态区(不占栈)

      c

      static Kennwert   newarr[MAX_KENNWERTE];
      static Kennlinien newarrien[MAX_KENNWERTE];
      ...
      
      注意这会占用可执行映像/全局内存,不一定适合嵌入式。
  1. 越界访问(addnamesub/subnamesub 按“遇到 name[0]==0 就停”的错误遍历)
  • 你在 write_bin 中对 merged/mergedien 调用了 subnamesub,但这两个数组只有前 n/m 个元素被填充,后面是未初始化的栈/堆内存,未必恰好 name[0]==0。你的循环会越界跑飞,数组越大越容易触发崩溃(1000 更容易出错)。
  • 修正:传入计数 n、m,严格按计数遍历;不要用 name[0]==0 当终止条件。写完文件再恢复内存内容。

    c

    static void addnamesub(Kennwert karr[], int n, Kennlinien karrien[], int m) {for (int i=0; i<n; ++i)for (int j=0; j<MAX_NAME_LEN && karr[i].name[j]; ++j)karr[i].name[j] = (char)((unsigned char)karr[i].name[j] + (j + 5));for (int i=0; i<m; ++i)for (int j=0; j<MAX_NAME_LEN && karrien[i].name[j]; ++j)karrien[i].name[j] = (char)((unsigned char)karrien[i].name[j] + (j + 5));
    }
    static void subnamesub(Kennwert karr[], int n, Kennlinien karrien[], int m) {for (int i=0; i<n; ++i)for (int j=0; j<MAX_NAME_LEN && karr[i].name[j]; ++j)karr[i].name[j] = (char)((unsigned char)karr[i].name[j] - (j + 5));for (int i=0; i<m; ++i)for (int j=0; j<MAX_NAME_LEN && karrien[i].name[j]; ++j)karrien[i].name[j] = (char)((unsigned char)karrien[i].name[j] - (j + 5));
    }
    
    同时改调用处:

    c

    // read_bin 成功读取后再解码
    addnamesub(karr, n, karrien, m);// write_bin 写前编码、写后恢复
    static int write_bin(const char* fname, Kennwert karr[], int n, Kennlinien karrien[], int m) {subnamesub(karr, n, karrien, m);FILE* fp = fopen(fname, "wb");if (!fp) { addnamesub(karr, n, karrien, m); return 0; }fwrite(&n, sizeof(int), 1, fp);fwrite(&m, sizeof(int), 1, fp);if (n>0) fwrite(karr, sizeof(Kennwert), n, fp);if (m>0) fwrite(karrien, sizeof(Kennlinien), m, fp);fclose(fp);addnamesub(karr, n, karrien, m);return 1;
    }

另外几条会让“1000 更容易出错”的隐患(建议一并修):

  • main 里把 nold、mold 初始化为 0(否则 binin 为 NULL 时未定义行为):

    c

    int nold = 0, mold = 0;
    
  • read_bin 同时校验并截断 m,且在 fread 全部成功后再解码:

    c

    if (r1!=1 || r2!=1 || n<0 || m<0) { fclose(fp); return (TwoInts){0,0}; }
    if (n > maxn) n = maxn;
    if (m > maxn) m = maxn;
    if (n>0 && fread(karr, sizeof(Kennwert), n, fp) != (size_t)n) { fclose(fp); return (TwoInts){0,0}; }
    if (m>0 && fread(karrien, sizeof(Kennlinien), m, fp) != (size_t)m) { fclose(fp); return (TwoInts){0,0}; }
    addnamesub(karr, n, karrien, m);
    
  • 解析 Kennlinie 的 test_wertp 时限制 idx,避免越界:

    c

    int idx = 0;
    for (char* tok = strtok(valbuf, ";"); tok && idx < MAX_ARRAY_LEN; tok = strtok(NULL, ";")) {karrien[m].test_wertp[idx++] = atof(tok);
    }
    

总结

  • 直接把 MAX_KENNWERTE 提到 1000 会因为“大的栈数组”+“错误的遍历越界”而更容易崩溃。把大数组移到堆或静态区,并修正 add/sub-name 的遍历方式,基本就能解决你遇到的报错。若仍有问题,提供具体的崩溃信息(栈溢出、段错误、异常码)。

源代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_KENNWERTE 10240      // 最大支持的Kennwert数据项数
#define MAX_KENNWERTE_2 10240   // 最大支持的Kennwert数据项数
#define MAX_NAME_LEN  128      // Kennwert中Name字段的最大长度
#define MAX_ARRAY_LEN  32      // 最大数组长度typedef struct {int n;int m;
} TwoInts;
// 描述一个 Kennwert,包含名称和一个数值
typedef struct {char name[MAX_NAME_LEN];double test_wertp;char Umrechnungsformel[MAX_NAME_LEN];
} Kennwert;
typedef struct {char name[MAX_NAME_LEN];double test_wertp[MAX_ARRAY_LEN];char Umrechnungsformel[MAX_NAME_LEN];double anzahl_stuetzstellen_x;
} Kennlinien;/*** 去除字符串s左右的空白字符(如空格、换行等)* 返回结果的起始地址*/
static char* trim(char* s) {char* end;// 跳过前导空白while(isspace((unsigned char)*s)) s++;if(*s == 0) return s;        // 空字符串直接返回// 找到尾部非空白的字符end = s + strlen(s) - 1;while(end > s && isspace((unsigned char)*end)) end--;*(end+1) = 0;                // 结尾加上串结束符return s;
}/*** 从给定XML字符串(xml)中,查找<tag>标签的内容,放入buf。查找从xml起始处。* 返回找到内容后下一个字符的指针;如果未找到返回NULL。* buf用于输出,长度为bufsize。* 这个函数的作用是定位如 <Name>xxx</Name> 里的xxx内容。*/
static const char* get_tag_text(const char* xml, const char* tag, char* buf, size_t bufsize) {char stag[64], etag[64];snprintf(stag, sizeof(stag), "<%s>", tag);        // <标签名> 这个是打印标签的名称么?snprintf(etag, sizeof(etag), "</%s>", tag);       // </标签名>const char* ps = strstr(xml, stag);               // 找第一个开始标签const char* pe = ps ? strstr(ps, etag) : NULL;    // 找结束标签if(ps && pe) {ps += strlen(stag);                           // 内容实际位置 去除标签头size_t len = pe-ps;if(len >= bufsize) len = bufsize-1;           // 安全拷贝strncpy(buf, ps, len);// 拷贝字符串buf[len] = 0;return pe + strlen(etag);                     // 返回下一个位置及结束的</Name>位置 删除标签尾部}if(buf && bufsize) buf[0]=0;                      // 没找到返回空串return NULL;
}/*** 在整个xml内容中查找每一个 <Kennwert> ... </Kennwert> 段落,并提取* <Name> 和 <test_wertp> 字段。存入karr数组,返回Kennwert实际数目。*/
static TwoInts parse_kennwerte(const char* xml, Kennwert karr[], Kennlinien karrien[], int maxn) {int n = 0;int m = 0;TwoInts ret;                   // Kennlinien的计数器const char* p = xml;               // 查找指针:每次都从上一次的</Kennwert>后继续找char kbuf[2048];                   // 临时保存单个 <Kennwert> ... </Kennwert> 内容while((p = strstr(p, "<Kennwert>")) && n < maxn) {const char* pend = strstr(p, "</Kennwert>");// 找到配套的结束标签位置if(!pend) break;               // 未找到配套的结束标签,终止size_t klen = pend - p + strlen("</Kennwert>");if(klen >= sizeof(kbuf)) klen = sizeof(kbuf)-1;   // 防止越界strncpy(kbuf, p, klen); kbuf[klen] = 0;           // 拷贝本次Kennwert片段// 提取 <Name>xxx</Name> 和 <test_wertp>xxx</test_wertp>char name[MAX_NAME_LEN] = "", valbuf[64] = "";char formel[MAX_NAME_LEN] = "", formelbuf[64] = "";get_tag_text(kbuf, "Name", name, sizeof(name));get_tag_text(kbuf, "Umrechnungsformel", formelbuf, sizeof(formelbuf));get_tag_text(kbuf, "test_wertp", valbuf, sizeof(valbuf));if(strlen(name)>0) {strncpy(karr[n].name, trim(name), MAX_NAME_LEN-1);    // 去左右空白, 拷贝karr[n].name[MAX_NAME_LEN-1]=0;karr[n].test_wertp = (strlen(valbuf)>0) ? atof(valbuf) : 0.0;   // 转为double// int a =atof("0x15"); // 这里的atof是将字符串转为doublestrncpy(karr[n].Umrechnungsformel, trim(formelbuf), MAX_NAME_LEN-1);karr[n].Umrechnungsformel[MAX_NAME_LEN-1]=0; // 去左右空白++n;                   // 下一个Kennwert}p = pend + strlen("</Kennwert>");      // 移动到下一个Kennwert的搜索起点}p =xml;while((p = strstr(p, "<Kennlinie>")) && m < maxn) {const char* pend = strstr(p, "</Kennlinie>");// 找到配套的结束标签位置if(!pend) break;               // 未找到配套的结束标签,终止size_t klen = pend - p + strlen("</Kennlinie>");if(klen >= sizeof(kbuf)) klen = sizeof(kbuf)-1;   // 防止越界strncpy(kbuf, p, klen); kbuf[klen] = 0;           // 拷贝本次Kennwert片段// 提取 <Name>xxx</Name> 和 <test_wertp>xxx</test_wertp>char name[MAX_NAME_LEN] = "", valbuf[64] = "";char formel[MAX_NAME_LEN] = "", formelbuf[64] = "";char anzahl_stuetzstellen_x[64] = "", valbuf2[64] = "";get_tag_text(kbuf, "Name", name, sizeof(name));get_tag_text(kbuf, "test_wertp", valbuf, sizeof(valbuf));get_tag_text(kbuf, "Umrechnungsformel", formelbuf, sizeof(formelbuf));get_tag_text(kbuf, "anzahl_stuetzstellen_x", valbuf2, sizeof(valbuf2));if(strlen(name)>0) {strncpy(karrien[m].name, trim(name), MAX_NAME_LEN-1);    // 去左右空白, 拷贝karrien[m].name[MAX_NAME_LEN-1]=0;char *array2dou = strtok(valbuf, ";");int idx = 0;while (array2dou != NULL){karrien[m].test_wertp[idx++] = (strlen(array2dou)>0) ? atof(array2dou) : 0.0;   // 转为doublearray2dou = strtok(NULL, ";");// 之后都传NULL}strncpy(karrien[m].Umrechnungsformel, trim(formelbuf), MAX_NAME_LEN-1);karrien[m].Umrechnungsformel[MAX_NAME_LEN-1]=0; // 去左右空白karrien[m].anzahl_stuetzstellen_x = (strlen(valbuf2)>0) ? atof(valbuf2) : 0.0;   // 转为double++m;                   // 下一个Kennwert}p = pend + strlen("</Kennlinie>");      // 移动到下一个Kennwert的搜索起点}ret.n = n;                   // 返回实际读取的Kennwert数量ret.m = m;                   // 返回实际读取的Kennlinien数量return ret;
}/*** 读取整个文本文件到一个malloc分配的缓冲区* 返回buffer指针。psz可获取文件长度* 调用者用完后须 free(buffer)*/
static char* readfile(const char* fname, size_t* psz) {FILE* fp = fopen(fname, "rb");if(!fp) return NULL;fseek(fp, 0, SEEK_END);//文件尾size_t sz = ftell(fp);//获取文件的大小fseek(fp, 0, SEEK_SET);//文件首char* buf = (char*)malloc(sz+1);//多一个字节存放\0if(!buf) { fclose(fp); return NULL;}fread(buf, 1, sz, fp); buf[sz]=0;//读取内容并加\0fclose(fp);if (psz) *psz = sz;return buf;
}static int addnamesub(Kennwert karr[], Kennlinien karrien[])
{int dex = 0;while (karr[dex].name[0] != '\0'){int dexstr =0;while (karr[dex].name[dexstr] != '\0'){karr[dex].name[dexstr] = karr[dex].name[dexstr] + (dexstr + 5);dexstr++;}dex++;}dex = 0;while (karrien[dex].name[0] != '\0'){int dexstr =0;while (karrien[dex].name[dexstr] != '\0'){karrien[dex].name[dexstr] = karrien[dex].name[dexstr] + (dexstr + 5);dexstr++;}dex++;}return 0;
}
static int subnamesub(Kennwert karr[], Kennlinien karrien[])
{int dex = 0;while (karr[dex].name[0] != '\0'){int dexstr =0;while (karr[dex].name[dexstr] != '\0'){karr[dex].name[dexstr] = karr[dex].name[dexstr] - (dexstr + 5);dexstr++;}dex++;}dex = 0;while (karrien[dex].name[0] != '\0'){int dexstr =0;while (karrien[dex].name[dexstr] != '\0'){karrien[dex].name[dexstr] = karrien[dex].name[dexstr] - (dexstr + 5);dexstr++;}dex++;}  return 0;
}/*** 读取旧的二进制(Kennwert)文件到karr里,返回read到的记录数。* 文件不存在或内容异常返回0。*/
static TwoInts read_bin(const char* fname, Kennwert karr[], Kennlinien karrien[],int maxn) {TwoInts ret={0,0};FILE* fp = fopen(fname, "rb");if (!fp) return ret;//(TwoInts){0, 0};int n = 0, m =0, r3,r4;// r1 = fread(&n, sizeof(int), 1, fp);   // 先读数量// r2 = fread(&m, sizeof(int), 1, fp);if( fread(&n, sizeof(int), 1, fp)!=1 ||fread(&m, sizeof(int), 1, fp)!=1 ||n > maxn) n = n>maxn ? maxn : 0;r3 = n>0 ? fread(karr, sizeof(Kennwert), n, fp) : 0; // 再读内容r4 = m>0 ? fread(karrien, sizeof(Kennlinien), m, fp) : 0; // 再读fclose(fp);addnamesub(karr, karrien);if (r3==n) ret.n = n;if (r4==m) ret.m = m;               // 返回实际读取的数量return ret;                        // 成功读取就返回n,否则返回0
}/*** 写入Kennwert数组到二进制文件 fname, 共n条* 文件格式: 先int写n, 然后n个Kennwert结构体* 写成功则返回1,否则返回0*/
static int write_bin(const char* fname, Kennwert karr[], int n, Kennlinien karrien[], int m) {subnamesub(karr, karrien);FILE* fp = fopen(fname, "wb");if (!fp) return 0;fwrite(&n, sizeof(int), 1, fp);fwrite(&m, sizeof(int), 1, fp);if(n>0) fwrite(karr, sizeof(Kennwert), n, fp);if(m>0) fwrite(karrien, sizeof(Kennlinien), m, fp);fclose(fp);return 1;
}/*** 在karr[0..n-1]中查找name,若找到返回下标,否则返回-1* 用于判重,防止合并重复*/
static int find_by_name(const Kennwert karr[], int n, const char* name) {for(int i=0; i<n; ++i)if(strcmp(karr[i].name, name)==0)return i;return -1;
}
static int find_by_nameien(const Kennlinien karr[], int n, const char* name) {for(int i=0; i<n; ++i)if(strcmp(karr[i].name, name)==0)return i;return -1;
}/*** 合并两个Kennwert数组:newarr为新(优先级高),oldarr为旧。* merged数组先放全部newarr内容,然后再放oldarr中newarr没有的项。* 返回合并后实际数量,不会超过mergedmax。*/
static int merge_kennwerte(Kennwert oldarr[], int nold,Kennwert newarr[], int nnew,Kennwert merged[], int mergedmax) {int n=0;// 先拷贝所有新的for(int i=0; i<nnew && n<mergedmax; ++i)merged[n++] = newarr[i];// 再加上旧的但新里没有的for(int i=0; i<nold && n<mergedmax; ++i){int a =find_by_name(newarr, nnew, oldarr[i].name);if(find_by_name(newarr, nnew, oldarr[i].name) < 0)merged[n++] = oldarr[i];}return n;
}
static int merge_kennwerteien(const Kennlinien oldarr[], int nold,const Kennlinien newarr[], int nnew,Kennlinien merged[], int mergedmax) {int n=0;// 先拷贝所有新的for(int i=0; i<nnew && n<mergedmax; ++i)merged[n++] = newarr[i];// 再加上旧的但新里没有的for(int i=0; i<nold && n<mergedmax; ++i){int a =find_by_nameien(newarr, nnew, oldarr[i].name);if(find_by_nameien(newarr, nnew, oldarr[i].name) < 0)merged[n++] = oldarr[i];}return n;
}
int main(int argc, char** argv) {// 文件名配置。实际工作中建议用命令行参数,这里演示直接写死char xmlfile1[32] = "Rte_App_Cfile2Xml.xml";const char* xmlfile = xmlfile1;              // xml文件名// char binin1[32] ="olddata1.bin";const char* binin = NULL;//binin1;                    // 旧二进制数据文件(如有)//  const char* binin = binin1;                    // 旧二进制数据文件(如有)char binout1[32] = "newdata1.bin";const char* binout = binout1;                // 新的二进制文件名/* STEP1: 读取xml文件内容并解析 */size_t xmlsz;char* xmlbuf = readfile(xmlfile, &xmlsz);if(!xmlbuf) { puts("Error: cannot read XML file."); return 2;}static Kennwert newarr[MAX_KENNWERTE];static Kennlinien newarrien[MAX_KENNWERTE];TwoInts retnm = parse_kennwerte(xmlbuf, newarr, newarrien, MAX_KENNWERTE);int nnew = retnm.n; // 实际读取的Kennwert数量int mnew = retnm.m; // 实际读取的Kennlinien数量free(xmlbuf);                       // 释放xml缓冲区printf("读取到%d条Kennwert记录.\n", nnew);printf("读取到%d条Kennlinie记录.\n", mnew);/* STEP2: 读取旧bin文件,若有 */static Kennwert oldarr[MAX_KENNWERTE];static Kennlinien oldarrien[MAX_KENNWERTE];TwoInts nmold;int nold = 0, mold = 0;if(binin){nmold = read_bin(binin, oldarr, oldarrien,MAX_KENNWERTE);nold = nmold.n; // 实际读取的Kennwert数量mold = nmold.m;}// 实际读取的Kennlinien数量/* STEP3: 合并,优先用新数据,再添加老数据中未覆盖的 */ static Kennwert merged[MAX_KENNWERTE];static Kennlinien mergedien[MAX_KENNWERTE];int nmerged = merge_kennwerte(oldarr, nold, newarr, nnew, merged, MAX_KENNWERTE);int mmerged = merge_kennwerteien(oldarrien, mold, newarrien, mnew, mergedien, MAX_KENNWERTE);/* STEP4: 写入到新的bin文件 */if(!write_bin(binout, merged, nmerged, mergedien, mmerged)) {puts("Error: failed to write bin.");return 3;}printf("合并完成!新文件%s,Kennwert=%d,Kennlinie=%d。\n", binout, nmerged, mmerged);return 0;
}

http://www.dtcms.com/a/350200.html

相关文章:

  • 车灯最新测试标准测试设备太阳光模拟器
  • Kafka 在 6 大典型用例的落地实践架构、参数与避坑清单
  • 【Flink】运行模式
  • Rust Async 异步编程(五):async/.await
  • 怎么把iphone文件传输到windows电脑?分场景选方法
  • 【ansible】roles的介绍
  • 【完整源码+数据集+部署教程】化妆品实例分割系统源码和数据集:改进yolo11-DynamicConv
  • 【C#】.net framework 4.8非常久远的框架如何把日期格式/Date(1754548600000)/以及带T的2025-08-07T14:36:40时间格式转为统一的格式输出
  • 并发编程原理与实战(二十六)深入synchronized底层原理实现
  • 京东API分类接口实战指南:获取各类商品信息
  • Microsoft 365 中的 School Data Sync 功能深度解析:教育机构数字化管理的智能核心
  • Android音频学习(十五)——打开输出流
  • 如何用DeepSeek让Excel数据处理自动化:告别重复劳动的智能助手
  • 面试手写 Promise:链式 + 静态方法全实现
  • 扣子智能体商业化卡在哪?井云系统自动化交易+私域管理,闭环成交全流程拆解
  • 3491定期复盘代码实现设计模式的忌假应用
  • 使用Docker配置Redis Stack集群的步骤
  • React 19 与 Next.js:利用最新 React 功能
  • SQL性能调优
  • HTTP、HTTPS 与 WebSocket 详解
  • UDS诊断案例-新能源汽车电池管理系统(BMS)诊断
  • Git提交流程与最佳实践
  • debug kernel 的一些trace的方法
  • 嵌入式Linux内核编译与配置
  • GraphRAG
  • 掌握C++ std::invoke_result_t:类型安全的函数返回值提取利器
  • VSCode远程连接阿里云ECS服务器
  • ABB机器人焊接混合气节气阀
  • Chrome GPU 加速优化配置(前端 3D 可视化 / 数字孪生专用)
  • LangChain4J-(2)-高阶API与低阶API