为什么这里需要一个 double-void 指针?动态 "generic" 数组
Why is a double-void pointer required here? Dynamic "generic" array
我试图实现一种 collections-library 的形式。在学习一门新语言时,我一直这样做,因为它教授了大部分语言细节。
所以,我从一种“通用”动态数组的形式开始。好吧,它并不是真正通用的,因为它只是包含指向实际数据的指针。
不过老实说,我不是很明白,为什么我这里需要一个double void指针。
我的头文件中定义的 Vector 结构(我在头文件中声明了每个方法和#include,但我在这里省略了它以保持代码的可读性。我还省略了一些边界检查)
typedef struct {
size_t capacity; //the allocated capacity
size_t length; //the actual length
void **data; //here I don't fully understand, why I need a double pointer.
} Vector;
这是我实现的一些方法,当我在我的结构中使用单个 void 指针时编译器会报错,所以 void *data
而不是 void **data
。
#include "utils.h"
const size_t INITIAL_SIZE = 16;
//Creates a new empty vector.
Vector *vec_new(void) {
printf("sizeof Vector is: %ld", sizeof(Vector));
Vector *vec = malloc(sizeof(Vector));
vec->length = 0;
vec->capacity = INITIAL_SIZE;
void *data = calloc(INITIAL_SIZE, sizeof(void*));
if(data == NULL) {
free(vec->data);
fprintf(stderr, "Error allocating memory.");
exit(EXIT_FAILURE);
}
vec->data = data;
return vec;
}
//This method appends the specified value at the end of the vector.
void vec_push(Vector *vec, void *data) {
if(vec->length == vec->capacity-1) {
vec_resize(vec);
}
vec->data[vec->length] = data;
vec->length += 1;
}
//gets the value at the specified index or NULL if index is out of bounds.
void *vec_get(Vector *vec, size_t index) {
return vec->data[index];
}
//Resizes the vector to 1.5x its current capacity.
void vec_resize(Vector *vec) {
vec->capacity *= 1.5;
void *data = realloc(vec->data, sizeof(void*) * vec->capacity);
if(data == NULL) {
free(vec->data);
fprintf(stderr, "Error allocating memory.");
exit(EXIT_FAILURE);
}
vec->data = data;
}
这似乎是魔法发生的地方,我还不明白:
void *data = malloc(...);
vec->data = data;
Malloc/calloc return 一个空指针,所以我要么必须声明一个实际类型,要么只使用 returned 空指针。所以第一行很清楚。
vec->data
是,根据我的理解,我没有在结构定义中使用相当于 (*vec).data
的双指针。所以基本上这一行应该将一个 void 指针分配给一个 void 指针。
也许有人可以用简单的术语向我解释一下,为什么这里只有一个 void 指针是不够的,或者我可能会误解的地方。
如果你有一个类型的指针
T *p1;
其中 T 是某种类型说明符,例如 void 然后指向该指针的指针将被声明为
T **p2 = &p1.
在这个calloc的调用中
calloc(INITIAL_SIZE, sizeof(void*))
您将分配一个类型为 void *
的指针数组。函数 returns 指向分配数组第一个元素的指针。所以你需要写
void **data = calloc(INITIAL_SIZE, sizeof(void*));
为了更清楚,我们假设您需要动态分配一个整数数组。在这种情况下,您将写
int *data = calloc( INITIAL_SIZE, sizeof( int ) );
所以取消引用指针 data
就像 *data
你会得到一个 int
类型的对象,更准确地说是分配数组的第一个元素。
当数组元素的类型为 void *
然后取消引用指针 data
就像 *data
你必须得到一个类型为 void *
的指针(第一个分配数组的元素)。因此,为了使操作正确,指针 data
的类型应为 void **
.
But to be honest, I don't fully understand, why I need a double void pointer here.
先介绍一些背景知识 - 也许您已经知道:
someType *
类型的指针是指向 someType
类型变量的指针 或 指向 [=] 类型变量数组的指针14=].
someType **
类型的指针是指向 someType *
类型变量的指针 - 这意味着:指向 someType
类型变量的指针。
void *
类型的指针是指向任何东西的指针;因为编译器不知道这个指针指向什么样的元素,所以不可能直接访问这样的元素。
相对于此,可知void **
类型的指针指向什么变量: 指向void *
.
类型的变量
为什么这个位置需要void**
:
关键是这几行:
vec->data[vec->length] = data;
...
return vec->data[index];
在这些行中,代码访问 vec->data
指向的数据。因此,vec->data
不能是 void *
而必须是 xxx *
而 xxx
是指针 vec->data
指向的数据类型。因为 vec->data
指向类型 void *
的指针,xxx
是 void *
所以 xxx *
是 void **
.
vec->data = data;
您的观察是正确的:vec->data
属于 void **
类型,data
属于 void *
.
类型
原因是malloc()
returns有一些内存,编译器不知道这块内存中存放的是哪种数据。所以 malloc()
返回的值是 void *
而不是 void **
.
在汽车行业中,您会使用如下所示的显式指针转换:
vec->data = (void **)data;
表达式(xxx *)y
告诉编译器指针y
指向一些xxx
类型的数据。所以 (void **)
告诉编译器指针指向 void *
.
类型的元素
但是,在桌面应用程序中,您通常不会编写 (void **)
。
我试图实现一种 collections-library 的形式。在学习一门新语言时,我一直这样做,因为它教授了大部分语言细节。
所以,我从一种“通用”动态数组的形式开始。好吧,它并不是真正通用的,因为它只是包含指向实际数据的指针。 不过老实说,我不是很明白,为什么我这里需要一个double void指针。
我的头文件中定义的 Vector 结构(我在头文件中声明了每个方法和#include,但我在这里省略了它以保持代码的可读性。我还省略了一些边界检查)
typedef struct {
size_t capacity; //the allocated capacity
size_t length; //the actual length
void **data; //here I don't fully understand, why I need a double pointer.
} Vector;
这是我实现的一些方法,当我在我的结构中使用单个 void 指针时编译器会报错,所以 void *data
而不是 void **data
。
#include "utils.h"
const size_t INITIAL_SIZE = 16;
//Creates a new empty vector.
Vector *vec_new(void) {
printf("sizeof Vector is: %ld", sizeof(Vector));
Vector *vec = malloc(sizeof(Vector));
vec->length = 0;
vec->capacity = INITIAL_SIZE;
void *data = calloc(INITIAL_SIZE, sizeof(void*));
if(data == NULL) {
free(vec->data);
fprintf(stderr, "Error allocating memory.");
exit(EXIT_FAILURE);
}
vec->data = data;
return vec;
}
//This method appends the specified value at the end of the vector.
void vec_push(Vector *vec, void *data) {
if(vec->length == vec->capacity-1) {
vec_resize(vec);
}
vec->data[vec->length] = data;
vec->length += 1;
}
//gets the value at the specified index or NULL if index is out of bounds.
void *vec_get(Vector *vec, size_t index) {
return vec->data[index];
}
//Resizes the vector to 1.5x its current capacity.
void vec_resize(Vector *vec) {
vec->capacity *= 1.5;
void *data = realloc(vec->data, sizeof(void*) * vec->capacity);
if(data == NULL) {
free(vec->data);
fprintf(stderr, "Error allocating memory.");
exit(EXIT_FAILURE);
}
vec->data = data;
}
这似乎是魔法发生的地方,我还不明白:
void *data = malloc(...);
vec->data = data;
Malloc/calloc return 一个空指针,所以我要么必须声明一个实际类型,要么只使用 returned 空指针。所以第一行很清楚。
vec->data
是,根据我的理解,我没有在结构定义中使用相当于 (*vec).data
的双指针。所以基本上这一行应该将一个 void 指针分配给一个 void 指针。
也许有人可以用简单的术语向我解释一下,为什么这里只有一个 void 指针是不够的,或者我可能会误解的地方。
如果你有一个类型的指针
T *p1;
其中 T 是某种类型说明符,例如 void 然后指向该指针的指针将被声明为
T **p2 = &p1.
在这个calloc的调用中
calloc(INITIAL_SIZE, sizeof(void*))
您将分配一个类型为 void *
的指针数组。函数 returns 指向分配数组第一个元素的指针。所以你需要写
void **data = calloc(INITIAL_SIZE, sizeof(void*));
为了更清楚,我们假设您需要动态分配一个整数数组。在这种情况下,您将写
int *data = calloc( INITIAL_SIZE, sizeof( int ) );
所以取消引用指针 data
就像 *data
你会得到一个 int
类型的对象,更准确地说是分配数组的第一个元素。
当数组元素的类型为 void *
然后取消引用指针 data
就像 *data
你必须得到一个类型为 void *
的指针(第一个分配数组的元素)。因此,为了使操作正确,指针 data
的类型应为 void **
.
But to be honest, I don't fully understand, why I need a double void pointer here.
先介绍一些背景知识 - 也许您已经知道:
someType *
类型的指针是指向 someType
类型变量的指针 或 指向 [=] 类型变量数组的指针14=].
someType **
类型的指针是指向 someType *
类型变量的指针 - 这意味着:指向 someType
类型变量的指针。
void *
类型的指针是指向任何东西的指针;因为编译器不知道这个指针指向什么样的元素,所以不可能直接访问这样的元素。
相对于此,可知void **
类型的指针指向什么变量: 指向void *
.
为什么这个位置需要void**
:
关键是这几行:
vec->data[vec->length] = data;
...
return vec->data[index];
在这些行中,代码访问 vec->data
指向的数据。因此,vec->data
不能是 void *
而必须是 xxx *
而 xxx
是指针 vec->data
指向的数据类型。因为 vec->data
指向类型 void *
的指针,xxx
是 void *
所以 xxx *
是 void **
.
vec->data = data;
您的观察是正确的:vec->data
属于 void **
类型,data
属于 void *
.
原因是malloc()
returns有一些内存,编译器不知道这块内存中存放的是哪种数据。所以 malloc()
返回的值是 void *
而不是 void **
.
在汽车行业中,您会使用如下所示的显式指针转换:
vec->data = (void **)data;
表达式(xxx *)y
告诉编译器指针y
指向一些xxx
类型的数据。所以 (void **)
告诉编译器指针指向 void *
.
但是,在桌面应用程序中,您通常不会编写 (void **)
。