C++结构体嵌套结构体数组内字符串填充异常问题求助
问题排查与修复方案
让我们一步步拆解你代码里的问题,这些都是导致那个奇怪软件异常的元凶:
核心错误点汇总
- 错误的
memset调用破坏了指针和C++对象的内部结构 - 循环中访问了未初始化的数组元素
- 使用了过时的C++头文件
- 混用C的内存分配函数(
malloc)和C++对象,导致对象未正确构造
1. 致命的memset误用
你代码里的这两行memset是崩溃的主要原因:
memset(f_array, 0, sizeof(f_array)); memset(f_array->td, 0, sizeof(f_array->td));
- 第一行:
f_array是指针,sizeof(f_array)是4或8字节(取决于系统位数),远小于FASTARRAY结构体的大小。这会直接把f_array内部的td指针清零,后续访问f_array->td[x]就是在访问空指针,必然触发崩溃。 - 第二行:同样,
sizeof(f_array->td)是指针的大小,不是你分配的MAX_TOKENS * sizeof(token_det)内存块的大小。更严重的是,token_det里包含std::string——这是C++的非POD(普通旧数据)类型,memset会直接覆盖它的内部管理数据(比如堆内存指针、字符串长度),导致后续的append操作完全失控,触发未定义行为。
2. 循环中的未初始化访问
你的循环逻辑有问题:
while(x<=10000) { printf("inside while"); f_array->td[x].data = "104,"; // ... 一系列append操作 x++; sprintf_s(log,sizeof(log),"Data for x-%d = %s\n",x,f_array->td[x].data); }
当你操作完f_array->td[x].data后,x立刻自增,然后你访问的是f_array->td[x].data——这时候的x已经是下一个未初始化的元素了,读取它的std::string会触发未定义行为,可能直接崩溃。
3. 过时的头文件
#include <iostream.h>是C标准出台前的旧头文件,现代C应该用#include <iostream>,这个旧头文件可能会导致兼容性问题。
修复后的代码
我把所有问题都修正了,你可以直接运行试试:
#include <stdio.h> #include <string> #include <stdlib.h> #include <iostream> using namespace std; #define MAX_TOKENS 300000 struct token_det { int token; std::string data; char mdepth[300]; }; typedef struct fastarray { token_det *td; } FASTARRAY; int main() { printf("inside main\n"); int lv_ret = 0; int count = 0; char log[50] = {""}; int wtoken = 0; FASTARRAY *f_array = nullptr; // 用new分配C++对象,确保构造函数被调用 f_array = new FASTARRAY(); f_array->td = new token_det[MAX_TOKENS]; printf("after allocation\n"); int x = 0; while(x <= 10000) { printf("inside while\n"); f_array->td[x].data = "104,"; f_array->td[x].data.append("stasimorphy"); f_array->td[x].data.append(","); f_array->td[x].data.append("psychognosy"); f_array->td[x].data.append(","); f_array->td[x].data.append("whoever"); f_array->td[x].data.append(","); // 先打印当前x的元素,再自增x sprintf_s(log, sizeof(log), "Data for x-%d = %s\n", x, f_array->td[x].data.c_str()); printf(log); x++; } // 用delete匹配new,注意数组要用delete[] delete[] f_array->td; delete f_array; printf("after while\n"); return 0; }
关键修复说明
- 用
new代替malloc:malloc只会分配内存,不会调用C++对象的构造函数,而std::string必须经过构造才能正常工作。new会自动调用token_det和std::string的构造函数,确保对象处于有效状态。 - 移除所有
memset:对于C++对象,永远不要用memset初始化,这会破坏对象的内部结构。 - 修正循环访问逻辑:先打印当前初始化好的元素,再自增
x,避免访问未初始化的内存。 - 显式调用
c_str():sprintf_s需要C风格的const char*字符串,std::string::c_str()可以安全地获取这个指针。 - 使用
nullptr:这是现代C++中表示空指针的标准方式,比NULL更安全。
内容的提问来源于stack exchange,提问作者Ghos3t
相关产品推荐
相关产品推荐

