基本C指针分配/释放



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

如果我错了,请纠正我,但按照我的理解,当我为矩阵分配内存(使用内置的var = gsl_matrix_alloc(x,x))并将其存储在变量中时,我本质上是在创建指针,它只是内存的某个地址,例如:x01234749162

其指向我的GSL矩阵的第一个指针/存储器位置。跟踪何时解除分配与指针(同样是内置的gsl_matrix_free(x,x,x))关联的结构的内存是没有问题的,我知道在重新分配结构的指针之前我需要这样做,否则我会造成内存泄漏。

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

每个人都说"哦,把它设置为NULL"。为什么会这样?这只是更改指向已释放结构的内存地址。这是否告诉MMU该内存位置现在可以使用?例如,当我在XCode中调试程序时,gsl_matrix结构的所有属性都被成功释放;所有的东西都变成了随机十六进制字符的垃圾串,这就是释放内存应该做的。但是,在调试程序中,我仍然可以看到变量名(指针)。。。即使我将变量设置为NULL。我认为这意味着我没有释放指针,我只是释放了结构并将其设置为00010000(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?  

这里缺少的是关于"局部变量"如何在机器级别工作的知识以及"堆栈"的概念。

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

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

现在假设您的程序在main函数中定义了一组变量,即类似的变量

 int main() {
     int x;

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

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

并且记住(为了进一步编译的目的)CCD_ 5现在是位于存储器位置CCD_。您的堆栈现在如下所示:

 [---------- 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指针只是另一个类似的变量。

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

  • PPS:原则上,编译器可以自由地优化代码(尤其是如果您使用-O标志进行编译),而不是在堆栈上分配本地变量,它可能会:

    • 决定完全避免分配它们(例如,如果它们被证明是无用的)
    • 决定将它们临时分配到寄存器中(寄存器是处理器中不需要释放的固定内存插槽)。这通常是针对循环变量(for (int i = ...)中的变量)执行的
    • 。。好吧,只要结果不与语义相矛盾,就做他扭曲的头脑中出现的任何其他事情
  • PPPS:现在您已经准备好学习缓冲区溢出是如何工作的。去读一读吧,真的,这是一个神奇的把戏。哦,而且,一旦你做到了,就要看看堆栈溢出的含义。)

为什么要为5x5矩阵分配26个内存点?我想说,相信库提供的gsl_matrix_free函数会做正确的事情,并释放整个结构。

通常,如果您呼叫了malloccalloc,则只需要呼叫free。提供分配器的库函数通常提供匹配的解除定位器,这样您就不必跟踪内部。

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

每个人都说"哦,把它设置为NULL"。为什么会这样?

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

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

它修复了这个问题,因为在空ptr上调用free是一个无操作:

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

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

相关内容

  • 没有找到相关文章