基本C指针分配/释放

时间:2014-09-11 22:21:30

标签: c pointers malloc free

使用GNU的GSL库快速提出基本问题,用C语言编写代码,从未正式学习过任何代码。

如果我错了,请纠正我,但我理解它的方式,当我分配内存用于我的矩阵(使用内置的var = gsl_matrix_alloc(x,x))并将它们存储在变量中时,我&# 39; m基本上是创造 一个指针,它只是一些内存地址,如: x01234749162

指向我的GSL矩阵的第一个指针/内存位置。跟踪何时释放与指针关联的结构的内存(同样,内置gsl_matrix_free(x,x,x))是没有问题的,我理解我需要在重新分配结构的指针之前执行此操作,否则我&#39 ; ve创建了内存泄漏。

所以现在我的问题,再次,我知道这是基本的,但是听我说 - 我无法在stackoverflow上找到一个特别直接的答案,主要是因为很多答案涉及C ++而不是C - 我如何释放指向结构本身的指针?

每个人都说"哦,只需将其设置为NULL"。为什么会这样?这只是将POINTS的内存地址更改为解除分配的结构。这是否告诉MMU现在可以使用该内存位置?例如,当我在XCode中调试程序时,gsl_matrix结构的所有属性都被成功释放;一切都变成了这个随机十六进制字符的垃圾串,这就是自由的内存应该做的事情。但是,我仍然可以通过调试器看到变量名(指针)...即使我将变量设置为NULL。我会解释这意味着我没有释放指针,我只是释放了结构并将其设置为x0000000(NULL)。

我做的一切都是正确的,这只是XCode的一个功能,还是我遗漏了一些基本的东西?

我意识到,如果结构被解除分配,单个指向结构的指针可能被认为不是什么大问题,但重要的是。

这里有一些代码试图说明我的想法。

gsl_matrix* my_matrix; 
// create single memory address in memory, not pointing to anything yet 

my_matrix = gsl_matrix_alloc(5, 5); 
// allocates 25 memory spaces for the values that the pointer held by my_matrix 
// points too
// Note: so, now there's 26 memory spots allocated to the matrix, excluding other
// properties created along with the my-matrix structure, right? 

gsl_matrix_free(my_matrix); // deallocates those 25 spaces the structure had, 
// along with other properties that may have been automatically created
free(my_matrix); // SIGBRT error. Is the pointer to the deallocated structure
// still using that one memory address?  
my_matrix = NULL; // this doesn't make sense to me.I get that any future referral
// to the my_matrix pointer will just return garbage, and so setting a pointer to
// that can help in debugging, but can the pointer--that is just one memory 
// address--be completely deallocated such that in the debugger the variable name
// disappears?  

3 个答案:

答案 0 :(得分:3)

你在这里想念的是关于"局部变量"在机器级工作以及"堆栈的概念"。

堆栈是一个可用内存块,在程序启动时为其分配。假设,为了一个简单的例子,您的程序被分配了一个大小为1MB的堆栈。堆栈附带一个特殊的寄存器,称为#34;堆栈指针",它最初指向堆栈的末尾(不要问为什么不是开始,历史原因)。这是它的外观:

 [---------- stack memory, all yours for taking ------------]
                                                            ^
                                                            |
                                                          Stack pointer

现在假设你的程序在main函数中定义了一堆变量,比如

 int main() {
     int x;

这意味着当在程序开始时调用main函数时,编译器将生成以下指令:

 sp = sp - 4;       // Decrement stack pointer
 x_address = sp;

并记住(为了进一步编译)x现在是位于内存位置x_address的4字节整数。您的堆栈现在看起来如下:

 [---------- stack memory, all yours for taking --------[-x--]
                                                        ^
                                                        |
                                                       Stack pointer

接下来,假设您从main中调用了一些函数f。假设f在其中定义了另一个变量

int f() {
    char z[8];

猜猜现在发生了什么?在输入f之前,编译器将执行:

sp = sp - 8;
z_address = sp;

即。你会得到:

 [---------- stack memory, all yours for taking -[--z----][-x--]
                                                 ^
                                                 |
                                                 Stack pointer

如果你现在调用另一个函数,堆栈指针将更深入到堆栈中,"创建"更多的局部变量空间。但是,每次退出函数时,堆栈指针都会恢复到调用函数之前的位置。例如。退出f后,您的堆栈将如下所示:

 [---------- stack memory, all yours for taking -[--z----][-x--]
                                                          ^
                                                          |
                                                       Stack pointer

请注意,z数组基本上没有被释放,它仍然存在于堆栈中,但你不在乎。为什么不关心?因为当应用程序终止时,整个堆栈会自动释放。这就是为什么您不需要在堆栈上手动释放变量的原因,即那些被定义为函数和模块本地变量的变量。特别是,你的my_matrix指针只是另一个变量。

  • PS:堆栈上发生的事情比我描述的要多一些。特别是,堆栈指针值在递减之前存储在堆栈中,以便在退出函数后可以恢复它。此外,函数参数通常通过将它们放入堆栈来传递。从这个意义上讲,它们看起来像是用于内存管理的局部变量,你不需要释放它们。

  • PPS:原则上,编译器可以自由地优化您的代码(特别是如果您使用-O标志进行编译)而不是在堆栈上分配您的局部变量:

    • 决定完全避免分配它们(例如,如果它们变得无用)
    • 决定暂时将它们分配到寄存器(处理器中不需要释放的固定内存插槽)。这通常是针对循环变量(for (int i = ...)中的变量)进行的。
    • ..好吧,只要结果与语义不矛盾,做其他任何事情都会扭曲他的思想。
  • PPPS:现在您已准备好了解buffer overflow的工作原理。去看看它,真的,这是一个了不起的技巧。哦,而且,一旦你了解它,请查看stack overflow的含义。 ;)

答案 1 :(得分:0)

  

每个人都说"哦,只需将其设置为NULL"。为什么会这样?

它们可能意味着这可以解决您在指向已经取消分配的某些数据的指针上调用free的问题,这就是您在此处所做的事情:

gsl_matrix_free(my_matrix); // deallocate
free(my_matrix); // Mistake, BIG PROBLEM: my_matrix points to de-allocated data

它解决了这个问题,因为在null-ptr上调用free是一个无操作:

gsl_matrix_free(my_matrix); // deallocate
my_matrix = NULL;
free(my_matrix); // Mistake, but no problem

注意my_matrix本身具有自动存储功能,因此无需手动取消分配。当它超出范围时,它的内存将被回收。唯一需要解除分配的是动态分配的内存(以及my_matrix个点。)

答案 2 :(得分:0)

为什么要为5x5矩阵分配26个记忆点?我要说信任库提供的gsl_matrix_free函数来做正确的事情并释放整个结构。

一般情况下,如果您拨打freemalloc,则只需拨打calloc即可。提供分配器的库函数通常提供匹配的解除分配器,这样您就不必跟踪内部结构。

如果您担心的第26个点是指针本身(换句话说,存储矩阵地址所需的内存),该空间是您的函数的堆栈帧的一部分,它会自动弹出当函数返回时。