基本C指针分配/释放

使用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结构的所有属性都被成功释放; 一切都变成了这个随机hex字符的垃圾串,这就是自由存储应该做的事情。 但是,我仍然可以通过调试器看到变量名(指针)…即使我将变量设置为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? 

每个人都说“哦,只需将其设置为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本身具有自动存储function,因此无需手动取消分配。 当它超出范围时,它的内存将被回收。 唯一需要my_matrix分配的是动态分配的内存( my_matrix指向的内存)。

你在这里想念的是“局部变量”如何在机器级工作以及“堆栈”的概念。

堆栈是一个可用内存块,在程序启动时为其分配。 假设,为了一个简单的例子,您的程序被分配了一个大小为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:现在您已准备好了解缓冲区溢出的工作原理。 去看看它,真的,这是一个惊人的技巧。 哦,一旦你在它,看看堆栈溢出的意义。 ;)

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

通常,如果调用malloccalloc ,则只需要调用free 。 提供分配器的库函数通常提供匹配的解除分配器,因此您不必跟踪内部。

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