realloc 可以用来将 ** 指针更改为 * 指针吗?

wro*_*n01 0 c arrays struct pointers

此代码来自Zed Shaw 的《Learn C The Hard Way》。在练习 34 中,实践问题之一是实现动态数组,它只是包含在结构中的指针数组。

该结构如下所示:

typedef struct DArray {
    int end;
    int max;
    size_t element_size;
    size_t expand_rate;
    void **contents;
};
Run Code Online (Sandbox Code Playgroud)

要初始化其中之一,我们使用 DArray_create()

DArray *DArray_create(size_t element_size, size_t initial_max)
{
    DArray *array = malloc(sizeof(DArray));
    array->max = initial_max;

    array->contents = calloc(initial_max, sizeof(void *));

    array->end = 0;
    array->element_size = element_size;
    array->expand_rate = 300;

    return array;
}
Run Code Online (Sandbox Code Playgroud)

还有一个调整数组大小的函数:

static inline int DArray_resize(DArray *array, size_t newsize)
{
    array->max = newsize;

    void *contents = realloc(array->contents, array->max * sizeof(void *));

    array->contents = contents;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

还有一些我遗漏的内存检查。

calloc我的问题与方式和realloc使用有关。第一个 callocDArray_create()分配给void **contents数组结构中的双指针,这对我来说很有意义,因为它是一个 void 指针数组。

然后,reallocDArray_resize()会调整内存大小,但使用void *contents单个指针来替换原始的双指针。为什么这样可以?我已经DArray_resize()使用单指针和双指针进行了测试,它们似乎都可以工作。如果原来calloc创建了一个void **指针,为什么可以将realloc其更改为void *指针?

n. *_* m. 6

void *是一种特殊的指针。它可以与任何其他类型的数据指针相互转换。

realloc接受并返回void *。它不知道你的程序操作的是哪种指针。调用者必须void *在调用时将您的指针转换为realloc,并将结果从 转换回来void *。这种转换在 C 语言中非常普遍,以至于它是自动完成的。

考虑对 的原始调用calloc

array->contents = calloc(initial_max, sizeof(void *)); // <- returns void*
                                                       // gets converted to void**
Run Code Online (Sandbox Code Playgroud)

calloc不创建void **指针。它返回一个void *指针(就像realloc那样)。调用者有责任将其转换为所需的任何指针类型。转换发生在赋值时,但如果您愿意,您可以插入显式强制转换:

array->contents = (void **)calloc(initial_max, sizeof(void *));
Run Code Online (Sandbox Code Playgroud)

返回到realloc,同样的事情发生在那里,只是这次使用了显式中间变量:

void *contents = realloc(array->contents, array->max*sizeof(void*)); // void* returned here
array->contents = contents; // converted to void** here
Run Code Online (Sandbox Code Playgroud)

realloc如果需要,您可以将转换转移到调用的行。在哪里完成并不重要。

void **contents = realloc(array->contents, array->max*sizeof(void*)); // converted here
array->contents = contents; // assignment, no conversion
Run Code Online (Sandbox Code Playgroud)

还有一个隐式转换为array->contents when void*realloc调用。如果需要,您还可以在此处使用强制转换:

void **contents = (void**)realloc((void*)array->contents, array->max*sizeof(void*));
Run Code Online (Sandbox Code Playgroud)

...或中间变量,或两者兼而有之。但它并没有真正提高程序的质量,因此通常不会这样做。