[英]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
函数可以做正确的事并取消整个结构的分配。
通常,仅在调用malloc
或calloc
时才需要调用free
。 提供分配器的库函数通常提供匹配的解除分配器,因此您不必跟踪内部结构。
如果您担心的第26个点是指针本身(换句话说,就是存储矩阵地址所需的内存),则该空间是函数堆栈框架的一部分,当该函数出现时会自动弹出返回。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.