由于某种原因,使用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
奇怪的是,将main
中对Copy_Read
的调用注释掉即可解决此问题,对malloc
的调用替换为对new
的调用也可以解决此问题。使用gdb运行程序显示尝试将rec
分配给record_list.array[0]
时发生错误。为什么会发生这种情况?我试图在这里举一个最小的例子。此代码的先前扩展版本导致分段错误,而不是free(): invalid pointer
错误。我知道这是可怕的代码,永远不要在严肃的程序中使用(我应该使用标准库vector
和new
),但是似乎有些我不理解的东西,这是关于malloc
和new
之间的差异(这是此代码存在问题的根源)的文献资料不足(无论如何,对于初学者来说都是这样)。
答案 0 :(得分:0)
我不了解malloc和new之间的区别
您需要阅读有关C ++的更多信息 ,例如一些C++ programming书和一个不错的C++ reference网站。是的,C ++是一门非常困难的语言(您需要花费大量的时间才能掌握它)。稍后,您可以深入研究C ++ 11标准n3337(或更新的C ++标准)。当然,您确实需要准确地了解constructors和destructors的作用(并说明这需要很多页面,远远超出了您在StackOverflow答案中可以合理预期的范围)。 / p>
您需要先执行constructors的代码(这是通过new
完成的,而不能通过malloc
完成的)–之后,析构函数也应先执行释放内存。 delete
(在许多其他情况下)调用析构函数,但是free
当然不会。另请参阅有关rule of five和RAII的信息。
您应该尽可能使用smart pointers。有时(例如用于循环引用)还不够。
valgrind工具可用于寻找与内存相关的错误。您还应该编译所有警告和调试信息,因此将g++ -Wall -Wextra -g
与GCC一起使用。您可能还希望使用静态源代码分析器工具,例如clang-analyzer或Frama-C。使用它们可能需要很多专业知识;有no silver bullet。
您的struct Record_array
是错误的:更喜欢使用std::vector<Record>
。详细了解标准C ++ containers。
您的Record
的构造函数将调用str1
和str2
的构造函数(即std::string
的构造函数应用于两个不同的位置)。如果您不调用该Record
构造函数,则str1
和str2
保持某种未定义状态(因此,使用它们后您将立即拥有一些undefined behavior)。>
malloc
和free
(对于C)与new
和delete
(对于C ++)之间的主要区别是构造函数和析构函数的涉及方式。当然,malloc
和free
会忽略它们,但不会忽略new
和delete
。内存分配失败(例如,虚拟内存耗尽时)的处理方式也不同。
PS。实际上,除了在极少数情况下,在定义自己的malloc
时,切勿在C ++代码中使用operator new
。因为malloc
不会调用C ++构造函数(而new
会调用)。另外,请理解 C和C ++是不同编程语言,而malloc
是C而不是C ++。许多C++ standard library实现在标准malloc
的实现中使用 {em> ::operator new
,在其free
的使用::operator delete
中。