【问题标题】:Initializing pointers to pointers as "handles" to memory将指向指针的指针初始化为内存的“句柄”
【发布时间】:2015-02-03 02:24:56
【问题描述】:

当你有简单的类型,如 int、char 等时,指针(和指向指针的指针)相对容易理解,但是当你有结构时,我总是发现很难理解动态内存分配和指针(指向指针)。

这就是为什么我发布了一个较早的线程,试图理解为一个简单的结构动态分配内存。我最近开始研究指针指针的使用,并试图在另一个线程中进行实际练习:Why use double pointer? or Why use pointers to pointers? 特别是它说的部分

“指向指针的指针也可以作为指向内存的“句柄”派上用场 你想在函数之间传递一个“句柄”以重新定位 记忆。”

按照线程中提供的代码模板,我创建了以下函数(LIB_OBJECT 是线程中模板中定义的简单结构):

void lib_free_memblock(LIB_OBJECT** memblock)
{
if (*memblock) {
    free(*memblock);
    *memblock = NULL;
}
}

LIB_OBJECT **lib_create_memblock(void) 
{
LIB_OBJECT *memblock = (LIB_OBJECT*) malloc(10 *   
                          sizeof(LIB_OBJECT));

LIB_OBJECT **ptr_to_memblock = (LIB_OBJECT **) malloc(sizeof(LIB_OBJECT*));

*ptr_to_memblock = memblock; 

if (ptr_to_memblock == NULL)
     {
     printf("Memory block allocation (memblock) failed!\n");
     exit(1);
     }

printf("%d bytes of memory block successfully allocated starting at address %x\n", NUM_OBJECTS, *ptr_to_memblock); 

return ptr_to_memblock; 

}

void lib_resize_memblock (LIB_OBJECT **b, int new_size)
{ 
    *b = (LIB_OBJECT*) realloc ((void *)*b, new_size);if (b == NULL)
    {
    printf("Resizing memory block failed!\n");
    exit(1);
    }

    printf("Memory block at start address %x has been resized to %d bytes\n", *b, new_size);
 }

程序运行成功:

LIB_OBJECT **my_memblock = lib_create_memblock();
lib_resize_memblock(my_memblock, 20);
lib_free_memblock(my_memblock);

10 bytes of memory block successfully allocated starting at address 233c010
Memory block at start address 233c010 has been resized to 20 bytes

但是,当我改变时

*ptr_to_memblock = memblock;

 ptr_to_memblock = &memblock;

我可以使用 lib_create_memblock 成功分配 10 个字节:

10 bytes of memory block successfully allocated starting at address 1c2b010

但程序在 lib_resize_memblock 处崩溃:

Breakpoint 2, lib_resize_memblock (b=0x7fffffffdf40, new_size=20)
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7aa3c01 in realloc_hook_ini () from /lib64/libc.so.6

现在不是

*ptr_to_memblock = memblock;

 ptr_to_memblock = &memblock;

一样吗?

有人可以澄清一下吗?

如果我理解正确,*b 是分配的内存块的起始地址,**b 是指向分配的内存块的起始地址的指针,因此允许程序员对分配的内存块进行修改。那么,编译器如何理解 *b 在 lib_resize_memblock 中的含义,我们将 **b 作为参数发送给函数?从下面的初始化?

   *ptr_to_memblock = memblock;

我猜编译器遵循链式连接,从指针到指针再到指针,最后到指针指向的地址,我所要做的就是建立正确的连接,对吗?提前谢谢..

【问题讨论】:

  • alloc 调用周围和内部有一堆不必要的转换;将它们全部删除。此外,create 函数生成了 10 个 objects,但 resize 函数生成了 bytes 的数量,这是一个不一致的接口;我建议更改 resize 函数以将对象的数量作为参数
  • 我记得读过一篇文章说强制转换 malloc 是不必要的,我想这就是您的意思(“内部”,我不明白您所说的“周围”到底是什么意思)。关于 bytes 参数,我错过了 - 我实际上在头文件中定义了 NUMBER_OF_OBJECTS,我将在函数中更正它..
  • 这就是我所说的“环绕”; “内部”是realloc ((void *)*b
  • 现在知道了,再次感谢!
  • 在您放弃内存块管理之前,我强烈建议您检查使用或不使用指针到指针逻辑的不同算法如何工作,并且可以使用 。最简单的方法之一是在插入新节点时保持顺序的单链表。算法基本相同,因为必须找到插入的“位置”。然而,实现有很大不同(您会惊讶于指针到指针的方法有多短)。挑战自己并尝试编写代码。

标签: c pointers dynamic-memory-allocation


【解决方案1】:

您的原始代码版本有效(但有一些不必要的花言巧语,我稍后会解释)。问题:

ptr_to_memblock = &memblock;

memblock是create函数的一个局部变量,它的生命周期在函数返回时结束。因此,该行最终会导致您返回一个指向不再存在的变量的指针。

这也会泄漏您刚刚malloc'd 的内存,因为不再有任何东西指向该内存。


事实上,create 函数具有不必要的间接级别,并且您的整个代码存在内存泄漏,因为您从来没有对应于mallocfree。使用以下内容会更好:

LIB_OBJECT *lib_create_memblock(void) ;

它只返回memblock,根本不用ptr_to_memblock。您的主要功能有几个选项,您可以自动分配“句柄”:

LIB_OBJECT *my_memblock = lib_create_memblock();
lib_resize_memblock(&my_memblock, 20);
lib_free_memblock(&my_memblock);   

或者您可以 malloc 句柄(除非您真的有充分的理由,否则这会不必要地复杂):

LIB_OBJECT **pp_memblock = malloc(sizeof *pp_memblock);
*pp_memblock = lib_create_memblock();
lib_resize_memblock(pp_memblock, 20);
lib_free_memblock(pp_memblock);
free(pp_memblock);

【讨论】:

  • 我现在看到了 create 函数的问题,我似乎不必要地使用了双指针。我现在更正了只返回 memblock 的代码。我似乎也忘记了释放(my_memblock),谢谢提醒!
  • 我们只是在你的例子中初始化了 **pp_memblock,那么编译器如何提取以下行中的 *pp_memblock 或 pp_memblock 的含义?可以在这里解释一下编译器的思维方式吗?
  • @c_b 第二个示例的第二行初始化 *pp_memblock 。之后,pp_memblock 指向lib_create_memblock 返回的指针(的副本),就像&my_memblock 在第一个示例中所做的那样
  • 交换第一行和第二行不是更好吗?我的意思是,我们不应该先定义 *pp_memblock 再定义 **pp_memblock 吗?
  • @c_b 我不确定你的意思,这甚至是不可能的。第一行声明了pp_memblock(不是**pp_memblock)并使它指向我们刚刚分配给malloc的一小块内存。第二行将一个值放入我们刚刚分配的内存块中。可能你误解了什么变量在内存中的位置,试着在纸上画一张图(用方框代表变量(有名或无名),用箭头代表指针指向的地方)
【解决方案2】:

*ptr_to_memblock = 内存块;和 ptr_to_memblock=&memblock 在这种情况下是不一样的。

当你看时

LIB_OBJECT **ptr_to_memblock = (LIB_OBJECT **)malloc(sizeof(LIB_OBJECT*));

*ptr_to_memblock = 内存块;

您正在创建一个指针,该指针实际上包含任何日期的 10 个连续位置。第二个表达式意味着存储在 ptr_to_memblock 中的地址是该数据的地址。这也是 memblock 中的相同值。但是方程式意味着有两件事指向数据。一个是 memblock ,另一个是地址在 ptr_to_memblock 中的指针。因此有两个独立的指针。

现在考虑,ptr_to_memblock=&memblock: ptr_to_memblock 存储 memblock 指针的地址。因此 ptr_to_memblock 指向 memblock,而 memblock 又指向数据。因此只有一个指向数据的指针。

希望这会有所帮助!

【讨论】:

  • 所以你说 ptr_to_memblock 和 memblock 在 *ptr_to_memblock = memblock 中指向不同的东西? “一个是 memblock” - 我明白了,“另一个是地址在 ptr_to_memblock 中的指针” - 我猜你的意思是 memblock 的地址在 ptr_to_memblock 中。如果是这样,那这和你下一段写的不一样吗?
  • 没有。在 *ptr_to_memblock = memblock 中,ptr_memblock 不包含 memblock 的地址。这里数据由 memblock 和一个地址在 ptr_memblock 中的指针指向。我的意思是说有两个指针指向同一个东西,“不是不同的东西”。
  • “数据正被 memblock 指向” - 好的,但是当你说“地址在 ptr_memblock 中的指针”时,我们到底在说什么指针?
  • 我说的是一个没有明确声明的指针。在 LIB_OBJECT ptr_to_memblock = (LIB_OBJECT)malloc(sizeof(LIB_OBJECT*));您正在创建一个内存(一个指针)并且该内存的地址在 ptr_memblock 中。让我取一些值:假设数据的起始地址是 10。10 将存储在 memblock 中。让您动态创建的指针在地址 70 处创建。现在 ptr_memblock 存储 70。您使用 malloc 显式创建的指针存储 10。因此,这个动态创建的指针指向数据。
猜你喜欢
  • 1970-01-01
  • 2016-11-09
  • 2010-10-11
  • 1970-01-01
  • 2015-04-28
  • 1970-01-01
  • 1970-01-01
  • 2013-04-01
  • 1970-01-01
相关资源
最近更新 更多