我正在尝试基于动态数组创建动态集抽象数据类型。但是,当我尝试将数据添加到数组时,我收到编译器警告和错误,其中包括:
警告:解除引用'void *'指针[默认启用]
错误:无效使用void表达式
我的代码如下,我用注释
标记了有问题的行struct SET
{
//general dynamic array
void *data;
int elements; //number of elements
int allocated; // size of array
};
struct SET create()
{
//create a new empty set
struct SET s;
s.data = NULL;
s.elements = 0;
s.allocated = 0; //allocations will be made when items are added to the set
puts("Set created\n");
return s;
}
struct SET add(struct SET s, void *item)
{
//add item to set s
if(is_element_of(item, s) == 0) //only do this if element is not in set
{
if(s.elements == s.allocated) //check whether the array needs to be expanded
{
s.allocated = 1 + (s.allocated * 2); //if out of space, double allocations
void *temp = realloc(s.data, (s.allocated * sizeof(s))); //reallocate memory according to size of the set
if(!temp) //if temp is null
{
fprintf(stderr, "ERROR: Couldn't realloc memory!\n");
return s;
}
s.data = temp;
}
s.data[s.elements] = item; //the error is here
s.elements = s.elements + 1;
puts("Item added to set\n");
return s;
}
else
{
fprintf(stdout, "Element is already in set, not added\n");
return s;
}
}
我已经对void指针进行了研究,但显然我在这里遗漏了一些东西。我很感激我能得到任何帮助。感谢阅读,希望能回答!
答案 0 :(得分:4)
首先,我认为你打算在你的结构中拥有一个通用指针数组(void *
数组),因为你的项目是void *
,并且你想将它们存储为一个数组。也就是说,您想要一个void *
的动态数组,因此,您应该使用void **
:
struct SET {
void **data;
int elements;
int allocated;
};
当然,您的add
功能需要更新:
struct SET add(struct SET s, void *item) {
if (is_element_of(item, s) == 0) {
if (s.elements == s.allocated) {
s.allocated = 1 + (s.allocated * 2);
void **temp = realloc(s.data, (s.allocated * sizeof(*s.data)));
if (!temp) {
fprintf(stderr, "ERROR: Couldn't realloc memory!\n");
return s;
}
s.data = temp;
}
s.data[s.elements] = item;
s.elements = s.elements + 1;
puts("Item added to set\n");
return s;
}
else {
fprintf(stdout, "Element is already in set, not added\n");
return s;
}
}
注意realloc
行已更改:您不想重新分配到s.allocated * sizeof(s)
,您需要s.allocated*sizeof(*s.data)
,因为您将存储void *
类型的元素(*s.data
的类型为void *
,我没有明确写void *
以便更容易适应未来可能的更改。
另外,我相信您应该更改函数以接收并返回指向struct SET
的指针,否则,您将始终复制结构(请记住值是通过复制传递的)。
答案 1 :(得分:1)
您正在尝试将数据用作数组,但已将其声明为void *。编译器无法确定您是否打算将数据类型存储到此数组中。
如果你知道要在'data'中存储什么类型的数据,你应该为它声明一个类型。 (如char * data或int * data)
答案 2 :(得分:1)
我一直在努力解决同样的问题。我已经将这种混淆与我们所教导的void** ptr
是二维数组的想法隔离开来。也许它也是一个二维数组,但是对于大多数部分我们想要使用单个指针数组的语法,而且两个维度只会混淆问题。例如:使用整数:
int a;
a
是一个变量的名称,它引用一个包含int的内存块。
int* aPtr;
aPtr
是一个变量的名称,它引用一个包含size_t
类型的内存块。所有指针都是size_t类型,就像所有int都是int类型一样,浮点数是float类型。它所持有的size_t将被分配一个地址(aPtr = &a
或aPtr = malloc(sizeof(int))
)。因为这是一个int指针,所分配的地址将是int的大小,并且它将存储一个int。因此,您将地址分配给aPtr
。您可以通过解除引用aPtr
为此地址分配一个值,内存块*aPtr = 10;
指向您,您可以读取解除引用int val = *aPtr;
指向的int中的值
int** pPtr;
pPtr是一个变量的名称,它引用一个包含size_t的内存块。存储在该size_t中的地址是另一个size_t块存储器的地址,即指针。第二个size_t bloc是保存整数地址的指针。因此你有:
int a = 10;
int* aPtr = &a;
int* bPtr = malloc(sizeof(int));
*bPtr = 20;
int** pPtr = malloc(2 * sizeof(int*));
pPtr[0] = aPtr;
*(pPtr + 1) = bPtr;
printf("a is %d, aPtr address is %d, aPtr points to %d, bPtr points to %d.\n", a, aPtr, *aPtr, *bPtr);
printf("pPtr[0] points to aPtr which points to %d. Which is to say, qwe dereference pPtr to get to aPtr and dereference aPtr to get to its value.\n", *(pPtr)[0]);
printf("Which can be handled with different syntax illustrated by pPtr[1] to give %d\n", *(*(pPtr + 1)) );
需要取消引用pPtr才能访问它指向的指针。具体来说,我们希望指针指向bPtr
,这是数组中的第二个元素*(pPtr + 1)
。但我们希望bPtr
指向的值,而不是bPtr
的地址,因此我们必须取消引用*(pPtr + 1)
,因此*(*(pPtr + 1))
因此可以包括无效指针:
void** vPtr = malloc(2 * sizeof(void*));
*(vPtr + 0) = aPtr;
*(vPtr + 1) = bPtr;
printf("vPtr[1] is %d\n", *((int*)*(vPtr + 1)));
正如几位评论员已经注意到,必须将void指针强制转换为类型。因此,作为void指针存储在数组中的aPtr
和bPtr
需要转换回int指针:(int *)*(vPtr + 1)
答案 3 :(得分:0)
您需要在解除引用之前强制转换void *
指针。
((some_type *)(s.data))[s.elements] = *(some_type *)item;