动态分配二维C-string数组访问与修改异常问题排查
嘿,这个问题我太熟悉了——咱们来一步步拆解哪里出问题,以及怎么修复:
核心问题:你覆盖了动态分配的指针,还指向了同一个缓冲区
你一开始的动态分配逻辑是对的:
for (int i = 0; i < n_names; i++) names[i] = new char[SPACE_FOR_EACH_NAME];
这确实给每个子数组分配了独立的内存空间。但后面你执行这句的时候出了大问题:
names[count-1] = (char*) current.c_str();
这里你做了两件坏事:
- 直接覆盖了之前动态分配的指针:原来
names[count-1]指向你刚new出来的内存,现在你把它换成了current.c_str()返回的指针——这直接导致之前分配的内存再也没法释放,造成了内存泄漏。 - 所有索引都指向同一个内存地址:
current是同一个std::string对象,每次调用std::getline都会更新它内部的字符缓冲区,而c_str()返回的指针始终指向这个缓冲区的起始位置。所以不管你给names的哪个索引赋值,最终所有元素都指向同一块内存,最后一次输入的内容自然会覆盖之前的,导致输出两次最后那个名字。
另外还要提一句:std::string::c_str()返回的是const指针,你用(char*)强制转换去掉const是不安全的,而且这个指针的有效期只到current的内容被修改或者它被销毁之前,完全不适合用来长期保存。
修复方案:复制内容到动态分配的内存里
你需要把current中的字符串内容复制到之前分配好的char数组中,而不是直接赋值指针。可以用C标准库的strncpy(记得包含<cstring>头文件)来做安全的复制:
修改后的输入循环应该是这样:
#include <cstring> // 别忘了加这个头文件 // ... int count = 0; while (count < n_names) { std::cout << "Name " << ++count << ": "; std::getline(std::cin, current); // 复制current的内容到已分配的内存,最多复制SPACE_FOR_EACH_NAME-1个字符(留位置存结束符) strncpy(names[count-1], current.c_str(), SPACE_FOR_EACH_NAME - 1); // 手动添加字符串结束符,防止strncpy在源字符串过长时不自动添加 names[count-1][SPACE_FOR_EACH_NAME - 1] = '\0'; }
额外注意点
- 为什么用
strncpy而不是strcpy?因为strcpy不会检查目标数组的大小,如果输入的名字超过SPACE_FOR_EACH_NAME-1,会造成缓冲区溢出,而strncpy可以限制复制的字符数,更安全。 - 必须手动添加
'\0':如果源字符串长度等于或超过SPACE_FOR_EACH_NAME-1,strncpy不会自动在目标数组末尾加结束符,这样后续遍历字符串的时候会读到垃圾数据。 - 修复后,你之前的内存释放逻辑就能正常工作了,不会再出现内存泄漏。
现在再运行代码,输入两个不同的名字,就能正常输出各自的内容啦!
内容的提问来源于stack exchange,提问作者BMendes
相关产品推荐
相关产品推荐

