首页 > 解决方案 > 使用 malloc 而不是 new 导致 free(): invalid pointer 错误

问题描述

出于某种原因,使用 gcc 编译以下代码并在 Ubuntu 上运行它生成的二进制文件会出现free(): invalid pointer错误:

#include <stdlib.h>
#include <fstream>
#include <string>
#include <iostream>
#include <sstream>
#include <ios>
#include <new>

struct arr_double_size {
   double *array;
   int size;
};

struct Record {
   int ID;
   std::string str1;
   std::string str2;
   int num;
   struct arr_double_size values;
};

struct Record_array {
   struct Record *array;
   int size;
};

void Copy_Read(void) {
   std::ifstream file{"in_file"};
   std::ofstream new_file{"out_file"};
   std::string line;
   while (std::getline(file,line)) {
      new_file << line << std::endl;
   }
   file.close();
   new_file.close();
}

int main(void) {
   Copy_Read();
   struct Record rec;
   struct arr_double_size values;
   values.size = 1;
   values.array = (double *)malloc(1 * sizeof(double));
   values.array[0] = 72.12;
   rec.ID = 2718;
   rec.str1 = "Test1";
   rec.str2 = "Test2";
   rec.num = 1;
   rec.values = values;
   struct Record_array record_list;
   record_list.size = 1;
   record_list.array = (struct Record *)malloc(1 * sizeof(struct Record));
   record_list.array[0] = rec;   
   return 0;
}

的内容in_file是:

TEST TEST TEST

奇怪的是,注释掉调用mainCopy_Read解决问题,就像用调用替换调用malloc一样new。使用 gdb 运行程序显示尝试分配recrecord_list.array[0]. 为什么会出现这种情况?我试图在这里举一个最小的例子;以前,此代码的扩展版本导致分段错误而不是free(): invalid pointer错误。我知道这是一个可怕的代码,永远不应该在严肃的程序中使用(我应该使用标准库vector和,无论如何)关于和new之间的区别mallocnew这是此代码问题的根源。

标签: c++segmentation-faultmallocnew-operator

解决方案


我不明白 malloc 和 new 之间的区别

您需要阅读更多关于 C++的内容,例如一些C++ 编程书籍,以及一个好的C++ 参考站点。是的,C++ 是一种非常困难的语言(你需要多年的工作才能掌握它)。稍后,您可以深入了解 C++11 标准n3337(或一些更新的 C++ 标准)。您当然需要准确理解构造函数析构函数的作用(并解释这需要很多页,远远超过您在任何 StackOverflow 答案中合理预期的内容)。

你需要让你的构造函数的代码被执行(这是用new但不是用来完成的malloc) - 稍后也应该在释放内存之前执行析构函数。析构函数由delete(以及在许多其他情况下)调用,但当然不是由free. 另请阅读关于五规则和关于RAII的信息。

如果可能,您应该更喜欢使用智能指针。有时(例如对于循环引用)它们是不够的。

害怕未定义的行为

valgrind工具可用于查找与内存相关的错误。您还应该使用所有警告和调试信息进行编译,因此g++ -Wall -Wextra -g使用GCC。您可能还想使用静态源代码分析器工具,例如clang-analyzerFrama-C。使用它们可能需要很多专业知识;没有灵丹妙药

struct Record_array错了:更喜欢使用std::vector<Record>. 阅读有关标准 C++容器的更多信息。

你的构造函数Record会调用of的构造函数str1str2即它的构造函数std::string-s应用于两个不同的位置)。如果您不调用该Record构造函数,str1str2保持某种未定义状态(因此,一旦使用它们,您就会有一些未定义的行为)。

malloc& free(对于 C)和newand (对于 C++)之间的主要区别在于delete构造函数和析构函数的参与方式。当然,malloc&free 忽略它们,但不是new& delete。内存分配失败(例如,当虚拟内存耗尽时)也有不同的处理方式。

PS。在实践中,你永远不应该malloc在 C++ 代码中使用,除非 - 在极少数情况下 - 定义你自己的operator new. 因为malloc不调用 C++ 构造函数(但new确实如此)。另外,请理解C 和 C++ 是不同的编程语言,并且malloc是针对 C 而不是 C++。许多C++ 标准库实现在其标准实现中使用 在其.malloc::operator newfree::operator delete


推荐阅读