繁体   English   中英

基本C指针分配/取消分配

[英]Basic C pointer allocation/deallocation

使用GNU的GSL库,用C编写代码,从来没有正式学过任何代码,这是一个基本的问题。

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

该指向我的GSL矩阵的第一个指针/内存位置。 跟踪何时取消分配与指针关联的结构的内存(再次,内置gsl_matrix_free(x,x,x) )是没有问题的,并且我知道我需要在重新分配结构的指针之前执行此操作,否则我创建了内存泄漏。

所以,现在我的问题又一次地,我知道这是基本的,但是请听我说-我找不到关于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?  

您在这里错过的是有关“局部变量”如何在计算机级别工作的知识以及“堆栈”的概念。

堆栈是程序启动时分配给程序的可用内存块。 举一个简单的例子,为您的程序分配一个大小为1MB的堆栈。 堆栈带有一个特殊的寄存器,称为“堆栈指针”,该寄存器最初指向堆栈的末尾(不要问为什么不从头开始,历史原因)。 外观如下:

 [---------- 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:现在您准备学习缓冲区溢出如何工作。 继续阅读,确实,这是一个了不起的技巧。 哦,还有,一旦你在它,检查出的意思堆栈溢出 ;)

每个人都说“哦,只要将其设置为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指向该内存)。

为什么要为5x5矩阵分配26个内存点? 我想说的是,信任库提供的gsl_matrix_free函数可以做正确的事并取消整个结构的分配。

通常,仅在调用malloccalloc时才需要调用free 提供分配器的库函数通常提供匹配的解除分配器,因此您不必跟踪内部结构。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM