【问题标题】:Deallocating void double pointer释放 void 双指针
【发布时间】:2016-05-23 00:29:57
【问题描述】:

如何释放一个 void 双指针?

deallocate(void** ptr)

这是我要测试的情况:

char* allocated = (char*)allocate_array(sizeof(char), BUFSIZ,0);

deallocate_array((void**)&allocated);

我需要检查 ptr 是否不为 NULL,所以这是我的尝试:

if(ptr != NULL && *ptr != NULL){
      free(*ptr);
}
ptr = NULL;
return;

【问题讨论】:

  • 需要检查 *ptr, free can handle it being NULL.
  • ptr 是如何分配的? ptr*ptr 是否都指向分配?您是要释放两个分配还是只释放一个分配?
  • char* allocated = (char*)allocate_array(sizeof(char), BUFSIZ,0); deallocate_array((void**)&allocated); 是我应该测试的情况
  • 你不释放指针,你释放它指向的对象。 (这里ptr是一个指针,*ptr既是一个指针又是一个被释放的对象,*(some_unknown_type*)*ptr是一个被释放的对象)
  • 不要改变你原来的问题。编辑时,您可以添加其他信息,但不要删除您的原始答案或在您的编辑不再有意义之前给出的所有答案...

标签: c++ memory-management


【解决方案1】:

您可能会让这变得比需要的更复杂。没有理由将的地址(例如&allocated)传递给您的deallocate 函数(除了将原始指针的值设置为NULL 而不使用返回)。您可以简单地传递一个指针。是的,该函数将接收该指针的副本,但它仍将包含要释放的内存块的起始地址。例如:

void deallocate (void *ptr)
{
    if (!ptr) return;
    free (ptr);
}

如果您的意图是在您的 deallocate 函数中解除分配并将原始指针指向的值设置为 NULL,那么是的,您确实需要传递原始地址以便将指针设置为 @ 987654327@ 反映在调用函数中(或者您可以将函数设为 void * 并返回指向设置为 null 的值的指针)。将传递给deallocate 的参数保留为void 指针,您可以执行以下操作:

void deallocate_doubleptr (void *ptr)
{
    if (!ptr || !*(void **)ptr) return;
    free (*(void **)ptr);
    *(void **)ptr = NULL;
}

(注意:,您没有传递void ** 参数,您只需传递一个void * (void) 指针并在函数内根据需要进行强制转换。参数仍然是@987654334 @指针。)

一个简短的例子说明两者是等价的,除了NULL的显式分配,并猜测你的allocate_array会是什么:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void *allocate_array (size_t size, size_t nmemb, int set);
void deallocate (void *ptr);
void deallocate_doubleptr (void *ptr);

int main (int argc, char **argv) {

    size_t size  = argc > 1 ? (size_t)strtoul (argv[1], NULL, 10) : 1;
    size_t nmemb = argc > 2 ? (size_t)strtoul (argv[2], NULL, 10) : 128;
    int    set   = argc > 3 ? (int)strtol (argv[3], NULL, 10) : 0;
    char *str = "The quick brown fox jumps over a lazy dog.";

    char *allocated = NULL;

    if ((allocated = allocate_array (size, nmemb, set)))
        printf ("\nsuccessfully allocated '%zu' bytes initialized to '%d' ('%c').\n",
                size * nmemb, set, set);

    if (31 < set && set < 127) { /* if filled with printable ASCII */
        allocated[strlen (str)] = 0;                /* nul-terminate */
        printf ("allocated : '%s'\n", allocated);   /* output array */
    }

    strncpy (allocated, str, size * nmemb - 1);     /* copy str to array */
    allocated[size * nmemb - 1] = 0;                /* nul-terminate */

    printf ("allocated : '%s'\n", allocated);       /* output */

#ifdef DEALLOCDBL
    deallocate_doubleptr (&allocated);
    printf ("deallocated all memeory, pointer reinitialized to 'NULL'\n");
#else
    deallocate (allocated);
    printf ("deallocated all memeory.\n");
#endif

    return 0;
}

void *allocate_array (size_t size, size_t nmemb, int set)
{
    if (!size || !nmemb) {
        fprintf (stderr, "error: invalid size or number of members.\n");
        return NULL;
    }

    void *memptr = NULL;

    if (set != 0) {
        memptr = malloc (nmemb * size);
        memset (memptr, set, nmemb * size);
    }
    else
        memptr = calloc (nmemb, size);

    if (!memptr) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        exit (EXIT_FAILURE);
    }

    return memptr;
}

void deallocate (void *ptr)
{
    if (!ptr) return;
    free (ptr);
    ptr = NULL;
}

void deallocate_doubleptr (void *ptr)
{
    if (!ptr || !*(void **)ptr) return;
    free (*(void **)ptr);
    *(void **)ptr = NULL;
}

编译

gcc -Wall -Wextra -o bin/allocate_deallocate allocate_deallocate.c

gcc -Wall -Wextra -DDEALLOCDBL -o bin/allocate_deallocate_dbl allocate_deallocate.c

(大多数编译器应该采用相同或非常相似的选项)

输出

无论调用何种实现,输出都是相同的。 (例如allocate_deallocateallocate_deallocate_dbl):

$ ./bin/allocate_deallocate 1 64 65

successfully allocated '64' bytes initialized to '65' ('A').
allocated : 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
allocated : 'The quick brown fox jumps over a lazy dog.'
deallocated all memeory.

内存/错误检查

$ valgrind ./bin/allocate_deallocate 1 64 65

$ valgrind ./bin/allocate_deallocate_dbl 1 64 65

==13759== Memcheck, a memory error detector
==13759== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==13759== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==13759== Command: ./bin/allocate_deallocate
==13759==

successfully allocated '64' bytes initialized to '65' ('A').
allocated : 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
allocated : 'The quick brown fox jumps over a lazy dog.'
deallocated all memeory, pointer reinitialized to 'NULL'
==13759==
==13759== HEAP SUMMARY:
==13759==     in use at exit: 0 bytes in 0 blocks
==13759==   total heap usage: 1 allocs, 1 frees, 64 bytes allocated
==13759==
==13759== All heap blocks were freed -- no leaks are possible
==13759==
==13759== For counts of detected and suppressed errors, rerun with: -v
==13759== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

查看一下,如果您有任何问题,请告诉我。

【讨论】:

    【解决方案2】:

    你的尝试很不错。你想要这样的东西:

    void deallocate(void **ptr) {
        char *allocated = NULL;
        if (ptr) {
            allocated = *ptr;
        }
        if (allocated) {
            free(allocated);
            *ptr = NULL;
        }
    }
    

    你会这样称呼它:

    deallocate(&allocated);
    

    你传入指针地址的原因是为了在释放后可以将指针设置回null。

    【讨论】:

    • 错误:编译期间assigning to 'char *' from incompatible type 'void *'
    • @MikeHenke:那么您正在编写 C++。您将问题标记为 C。
    • 不需要传(void **ptr),传(void *ptr)比较合适。指针的副本仍然保存要成为freeed 的块的起始地址。
    • 是的。您不必在 C 中将分配强制转换为 deallocate。
    猜你喜欢
    • 2020-12-18
    • 2016-09-07
    • 2013-12-18
    • 1970-01-01
    • 2014-06-22
    • 1970-01-01
    • 2020-04-01
    • 2017-09-05
    • 2014-02-15
    相关资源
    最近更新 更多