在C语言中什么时候应该使用双重间接?谁能举个例子解释一下吗?

我所知道的是双间接是指向指针的指针。为什么我需要指向指针的指针?


当前回答

例如,你可能想要确保当你释放某个东西的内存时,你将指针设置为空。

void safeFree(void** memory) {
    if (*memory) {
        free(*memory);
        *memory = NULL;
    }
}

当你调用这个函数时,你会用指针的地址来调用它

void* myMemory = someCrazyFunctionThatAllocatesMemory();
safeFree(&myMemory);

现在myMemory被设置为NULL,任何重用它的尝试都将是非常明显的错误。

其他回答

例如,你可能想要确保当你释放某个东西的内存时,你将指针设置为空。

void safeFree(void** memory) {
    if (*memory) {
        free(*memory);
        *memory = NULL;
    }
}

当你调用这个函数时,你会用指针的地址来调用它

void* myMemory = someCrazyFunctionThatAllocatesMemory();
safeFree(&myMemory);

现在myMemory被设置为NULL,任何重用它的尝试都将是非常明显的错误。

字符串是使用双指针的一个很好的例子。字符串本身是一个指针,所以任何时候你需要指向一个字符串,你就需要一个双指针。

我经常使用它们的一件事是,当我有一个对象数组,我需要根据不同的字段对它们执行查找(二进制搜索)。 我保留原始数组…

int num_objects;
OBJECT *original_array = malloc(sizeof(OBJECT)*num_objects);

然后创建一个指向对象的排序指针数组。

int compare_object_by_name( const void *v1, const void *v2 ) {
  OBJECT *o1 = *(OBJECT **)v1;
  OBJECT *o2 = *(OBJECT **)v2;
  return (strcmp(o1->name, o2->name);
}

OBJECT **object_ptrs_by_name = malloc(sizeof(OBJECT *)*num_objects);
  int i = 0;
  for( ; i<num_objects; i++)
    object_ptrs_by_name[i] = original_array+i;
  qsort(object_ptrs_by_name, num_objects, sizeof(OBJECT *), compare_object_by_name);

您可以根据需要创建任意数量的已排序指针数组,然后对已排序指针数组使用二进制搜索,根据已有的数据访问所需的对象。对象的原始数组可以保持无序,但是每个指针数组将按照它们指定的字段进行排序。

I have used double pointers today while I was programming something for work, so I can answer why we had to use them (it's the first time I actually had to use double pointers). We had to deal with real time encoding of frames contained in buffers which are members of some structures. In the encoder we had to use a pointer to one of those structures. The problem was that our pointer was being changed to point to other structures from another thread. In order to use the current structure in the encoder, I had to use a double pointer, in order to point to the pointer that was being modified in another thread. It wasn't obvious at first, at least for us, that we had to take this approach. A lot of address were printed in the process :)).

当你处理在应用程序其他地方被更改的指针时,你应该使用双指针。在处理返回和寻址给您的硬件时,您可能还会发现双指针是必须的。

Pointers to pointers also come in handy as "handles" to memory where you want to pass around a "handle" between functions to re-locatable memory. That basically means that the function can change the memory that is being pointed to by the pointer inside the handle variable, and every function or object that is using the handle will properly point to the newly relocated (or allocated) memory. Libraries like to-do this with "opaque" data-types, that is data-types were you don't have to worry about what they're doing with the memory being pointed do, you simply pass around the "handle" between the functions of the library to perform some operations on that memory ... the library functions can be allocating and de-allocating the memory under-the-hood without you having to explicitly worry about the process of memory management or where the handle is pointing.

例如:

#include <stdlib.h>

typedef unsigned char** handle_type;

//some data_structure that the library functions would work with
typedef struct 
{
    int data_a;
    int data_b;
    int data_c;
} LIB_OBJECT;

handle_type lib_create_handle()
{
    //initialize the handle with some memory that points to and array of 10 LIB_OBJECTs
    handle_type handle = malloc(sizeof(handle_type));
    *handle = malloc(sizeof(LIB_OBJECT) * 10);

    return handle;
}

void lib_func_a(handle_type handle) { /*does something with array of LIB_OBJECTs*/ }

void lib_func_b(handle_type handle)
{
    //does something that takes input LIB_OBJECTs and makes more of them, so has to
    //reallocate memory for the new objects that will be created

    //first re-allocate the memory somewhere else with more slots, but don't destroy the
    //currently allocated slots
    *handle = realloc(*handle, sizeof(LIB_OBJECT) * 20);

    //...do some operation on the new memory and return
}

void lib_func_c(handle_type handle) { /*does something else to array of LIB_OBJECTs*/ }

void lib_free_handle(handle_type handle) 
{
    free(*handle);
    free(handle); 
}


int main()
{
    //create a "handle" to some memory that the library functions can use
    handle_type my_handle = lib_create_handle();

    //do something with that memory
    lib_func_a(my_handle);

    //do something else with the handle that will make it point somewhere else
    //but that's invisible to us from the standpoint of the calling the function and
    //working with the handle
    lib_func_b(my_handle); 

    //do something with new memory chunk, but you don't have to think about the fact
    //that the memory has moved under the hood ... it's still pointed to by the "handle"
    lib_func_c(my_handle);

    //deallocate the handle
    lib_free_handle(my_handle);

    return 0;
}

希望这能有所帮助,

杰森