C Void指针的动态数组

C Void指针的动态数组,c,arrays,pointers,void-pointers,C,Arrays,Pointers,Void Pointers,我试图创建一个基于动态数组的动态集合抽象数据类型。但是,当我尝试将数据添加到数组时,会收到编译器警告和错误,它们是: 警告:取消引用“void*”指针[默认情况下已启用] 错误:无效使用void表达式 我的代码如下,我用注释标记了有问题的行 struct SET { //general dynamic array void *data; int elements; //number of elements int allocated; // size of array }; struct S

我试图创建一个基于动态数组的动态集合抽象数据类型。但是,当我尝试将数据添加到数组时,会收到编译器警告和错误,它们是:

警告:取消引用“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*
指针


((某些类型*)(s.data))[s.elements]=*(某些类型*)项

您试图将数据用作数组,但已将其声明为void*。编译器无法确定是否要将数据类型存储到此数组中


如果您知道要在“数据”中存储什么类型的数据,您可能应该为它声明一个类型。(如char*data或int*data)

首先,我认为您希望在结构中包含一个通用指针数组(数组of
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
行已更改:您不希望realloc到
s.allocated*sizeof(s)
,您希望
s.allocated*sizeof(*s.data)
,因为您将存储类型为
void*
*s.data
的类型是
void*
,我没有明确地编写
void*
,以便更容易适应未来可能的更改)


另外,我认为您应该更改函数以接收和返回指向
struct SET
的指针,否则,您将始终围绕结构进行复制(请记住,值是通过copy传递的).

我一直在为同一个问题苦苦挣扎。我已经将困惑与我们被教导的
void**ptr
是一个二维数组的想法隔离开来。也许它也是一个二维数组,但在大多数情况下,我们想要使用单个指针数组和二维数组的语法只是混淆了这个问题。使用int例如:

int a; 
a
是一个变量的名称,该变量引用一个包含int的内存块

int* aPtr;
aPtr
是一个变量的名称,它引用了一个内存块,该内存块拥有
size\t
类型。所有指针都是size\t类型,就像所有int都是int类型一样,float都是float类型。它所拥有的size\t将被分配一个地址(
aPtr=&a
,或
aPtr=malloc(sizeof(int))
)。因为这是一个int指针,分配的地址将是int的大小,它将存储int。因此,您将地址分配给
aPtr
。您将值分配给此地址,内存块
aPtr
通过取消引用
*aPtr=10指向;
读取通过取消引用
intv指向的int中的值al=*aPtr;

int** pPtr;
pPtr是一个变量的名称,该变量引用一个包含大小\u t的内存块。此大小\u t中存储的地址是另一个大小\u t内存块的地址,即指针。第二个大小\u t块是包含整数地址的指针。因此,您有:

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
,数组中的第二个元素so
*(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指针必须转换回type。因此,作为void指针存储在数组中的
aPtr
bPtr
需要转换回int指针:(int*)*(vPtr+1)

你应该把所有函数定义都放在这里..看来成员数据应该是空的**?我不确定我是否遵循..数组背后的想法是它可以存储任何类型的数据。然后你需要根据存储在其中的数据类型对其进行适当的强制转换。我已将其强制转换为char*,并进行编译,但我有点担心is违背了数组的用途。如果它是这样工作的,那么为什么不从字符串开始定义数组呢?@MattGrima不客气。动态数组背后的想法总是一样的。当你想在动态数组中存储
T
类型的元素时,你必须声明一个指向T的指针。在这种情况下,你想存储
void*
在动态数组中,因此您需要一个指向
void*
的指针,即
void**
。如果您遵循此思路,您将永远不会再犯此错误:)但是请记住,当您从集合中弹出这些元素时,如果要取消引用指针,则接收它们的函数必须知道它们的类型。