如何用malloc/calloc创建含string的结构体动态数组?(禁用new/delete)
问题分析与解决
你的代码存在两个核心问题:
malloc/realloc不调用C++类构造函数:std::string是需要构造的类类型,直接用malloc分配的内存里,person的string成员处于未初始化状态,直接操作会触发未定义行为。- 输入缓冲区残留换行符:
cin>>members读取整数后,输入缓冲区里会留下换行符,后续第一个getline会直接读取这个空行,导致输入异常。
另外作业要求使用calloc,你当前用的是malloc,也需要替换。
修正后的代码
#include <iostream> #include <string> #include <cstdlib> // 包含calloc、realloc、free的头文件 using namespace std; struct person{ string name; string post; int age; char accessLvl; }; int main(){ int members = 2; // 用calloc分配初始内存,calloc会把内存初始化为0,但依然需要构造string person *guard = static_cast<person*>(calloc(members, sizeof(person))); if (!guard) { cerr << "内存分配失败" << endl; return 1; } // 初始化每个person对象(调用构造函数) for (int i = 0; i < members; ++i) { new (&guard[i]) person(); // placement new,在已分配内存上构造对象 } cout << "How many guards are active: " << endl; cin >> members; cin.ignore(); // 跳过输入整数后的换行符 // 重新分配内存 person *temp = static_cast<person*>(realloc(guard, sizeof(person)*members)); if(temp == NULL){ // 释放前先析构已构造的对象 for (int i = 0; i < 2; ++i) { guard[i].~person(); } free(guard); cerr << "内存重分配失败" << endl; return 1; } // 处理realloc后的对象构造/析构 if (temp != guard) { // 对新增的元素调用构造函数 for (int i = 2; i < members; ++i) { new (&temp[i]) person(); } } else { if (members > 2) { // 内存未扩容时,构造新增元素 for (int i = 2; i < members; ++i) { new (&temp[i]) person(); } } else if (members < 2) { // 内存缩容时,析构多余的对象 for (int i = members; i < 2; ++i) { temp[i].~person(); } } } guard = temp; for(int i = 0; i < members; i++){ cout << "\nname: "; getline(cin, guard[i].name); cout << "post: "; getline(cin, guard[i].post); cout << "age: "; cin >> guard[i].age; cin.ignore(); // 跳过age输入后的换行符 cout << "Access Level: "; cin >> guard[i].accessLvl; cin.ignore(); // 跳过accessLvl输入后的换行符 } for(int i = 0; i < members; i++){ cout << guard[i].name << endl; cout << guard[i].post << endl; cout << guard[i].age << endl; cout << guard[i].accessLvl << endl; } // 释放前先析构所有person对象 for (int i = 0; i < members; ++i) { guard[i].~person(); } free(guard); return 0; }
关键修改点说明
- 替换为
calloc:符合作业要求,calloc会将分配的内存初始化为0,但这不足以初始化std::string,仍需用placement new调用构造函数。 - placement new构造对象:在
calloc/realloc分配的内存上,手动调用person的构造函数,确保std::string成员被正确初始化。 - 手动调用析构函数:在
free内存前,必须调用每个person对象的析构函数,否则std::string管理的内存会泄漏。 - 清理输入缓冲区:每次用
cin>>读取数据后,调用cin.ignore()跳过残留的换行符,避免getline读取空行。 realloc后的对象管理:如果realloc分配了新内存,需要对新增元素调用构造函数;如果内存缩小,需要析构多余的对象。
内容的提问来源于stack exchange,提问作者user32782935
相关产品推荐
相关产品推荐

