关于与 free() 一起使用时指针和数组表示法之间的区别

On the difference between pointer and array notation when used with free()

而且,欢迎回到 'Puny Mortals Asking (Potentially) Dumb Questions' 的另一精彩片段。

我写了一个K&R's exercise 1-16 that uses dynamic memory allocation. As part of checking my work, I ran my code through Valgrind. Valgrind reported some memory leaks, though I had a 1:1 malloc:free ratio (which is perplexing). After much fiddling and reading of the GNU c lib manual and the Valgrind user manual的解决方案,我最终来到了SO。我阅读的 post 中的 None 确实解决了我的问题,直到我注意到其他不相关问题的一些解决方案使用了可以表示为以下等价的符号:

*(dbl_ptr + i) == dbl_ptr[i]

其中 dbl_ptrchar** 类型,iint 类型。

在我自己的原始代码中,我一直试图通过以下方式 free() 双指针:

for( i = 0 ; i < count ; ++i ) {
   free( (dbl_ptr + i) );     //Valgrind complains about a leak right here
}

free( dbl_ptr );

但是当我用这些行重新编译程序时:

for( i = 0 ; i < count ; ++i ) {
    free( dbl_ptr[i] );    //No more Valgrind complaints
}

free( dbl_ptr );

然后该程序被报告为内存安全的。为什么?

帮助我理解,仁慈的StackOverlords!

尾声:

如果您想深入了解这里发生的事情,我建议您阅读 templatetypedef 对此 post 的回答。我不相信我可以写出更好的解释来解释我自己的代码中出了什么问题。事实证明,我的错误是对 free() 如何解释参数的误解,以及对 C 中数组语法背后语义的基本无知。

快速而肮脏:dbl_ptr[i] 隐式取消引用 dbl_ptr + i

您在

中忘记了取消引用运算符
free( (dbl_ptr + i) );   

应该是

free( *(dbl_ptr + i) ); 

free 释放指针参数指向的内存。在正确的情况下,free(dbl_ptr[i]),您从数组中查找一个指针,然后释放它指向的内存。在不正确的情况下,free( (dbl_ptr + i)),传递给它的指针实际上是一个指向数组中某个位置的指针,一个指向您要释放的内存的指针。

要查看差异的简单方法,请考虑 i=0 的情况。正确的版本是 free(dbl_ptr[0])。错误的版本是 free(dbl_ptr+0),与 free(dbl_ptr).

相同

当您调用 free 时,参数应该是指向您要释放的内存块前面的指针。

因此,假设您有一个 double* 数组。该数组如下所示:

  dbl_ptr ---> [ 0 ][ 1 ][ 2 ] ... [ k ]
                 |    |    |         |
                 v    v    v         v
                arr  arr  arr       arr

现在,假设你调用

free(dbl_ptr + i);

图形上,dbl_ptr + i 点在这里(让我们选择 i = 1

  dbl_ptr + i --------+
                      |
                      v
  dbl_ptr ---> [ 0 ][ 1 ][ 2 ] ... [ k ]
                 |    |    |         |
                 v    v    v         v
                arr  arr  arr       arr

因此,free 将此调用解释为好像您想从分配给 dbl_ptr 的内存块中间释放某些东西,而不是 [=21] 指向的内存块=].这是个问题,因为你不能用指向内存块中间的指针调用 free

另一方面,调用

free(*(dbl_ptr + i));

free(dbl_ptr[i]);

那么你实际上是在说释放dbl_ptr指向的数组的第i个元素指向的内存,这就是你想要的。