简体   繁体   English

虚拟指针的动态数组

[英]Dynamic Array of Void Pointers

I'm trying to create a dynamic set abstract data type, based on a dynamic array. 我正在尝试基于动态数组创建动态集抽象数据类型。 However, I get a compiler warning and an error when I try to add the data to the array, which are: 但是,当我尝试将数据添加到数组时,我收到编译器警告和错误,这些是:

warning: dereferencing 'void *' pointer [enabled by default] 警告:解除引用'void *'指针[默认启用]

error: invalid use of void expression 错误:无效使用void表达式

My code is as follows, I've marked the problematic line with a comment 我的代码如下,我用注释标记了有问题的行

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;
}
}

I've done research on void pointers, but clearly I'm missing something here. 我已经对void指针进行了研究,但显然我在这里遗漏了一些东西。 I'd appreciate any help I can get. 我很感激我能得到任何帮助。 Thanks for reading and hopefully answering! 感谢阅读,希望能回答!

First, I think what you intend to have in your structure is an array of generic pointers (array of void * ), because your items are void * , and you want to store them as an array. 首先,我认为你打算在你的结构中有一个通用指针数组( void *数组),因为你的项目是void * ,你想将它们存储为数组。 That is, you want a dynamic array of void * , thus, you should use void ** : 也就是说,你想要一个void *的动态数组,因此,你应该使用void **

struct SET {
    void **data;
    int elements;
    int allocated;
};

Of course, your add function needs to be updated: 当然,您的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;
    }
}

Note the realloc line was changed: you don't want to realloc to s.allocated * sizeof(s) , you want s.allocated*sizeof(*s.data) , since you'll be storing elements of type void * (the type of *s.data is void * , I didn't explicitly write void * to make it easier to accomodate possible future changes). 请注意realloc行已更改:您不想重新分配到s.allocated * sizeof(s) ,您需要s.allocated*sizeof(*s.data) ,因为您将存储void *类型的元素( *s.data的类型是void * ,我没有明确地写出void *以便更容易适应未来可能的更改)。

Also, I believe you should change your functions to receive and return pointers to struct SET , otherwise, you will always be copying around the structure (remember that values are passed by copy). 另外,我相信您应该更改函数以接收和返回指向struct SET指针,否则,您将始终复制结构(请记住,值是通过复制传递的)。

You are trying to use data as an array, but have declared it as void *. 您正在尝试将数据用作数组,但已将其声明为void *。 The compiler is not able to figure out if you intend to store the type of data into this array. 编译器无法确定您是否打算将数据类型存储到此数组中。

If you know what kind of data you are going to store in 'data', you should probably declare a type for it. 如果你知道要在'data'中存储什么类型的数据,你应该为它声明一个类型。 (like char *data or int *data) (比如char * data或int * data)

I have been struggling with the same issue. 我一直在努力解决同样的问题。 I have isolated the confusion to to the idea we are taught that void** ptr is a two dimensional array. 我已经将这种混淆与我们所教导的想法隔离开来,即void** ptr是一个二维数组。 Maybe it is also a two dimensional array, but for the most parts we want to use the syntax for a single array of pointers and two dimensionality just confuses the issue. 也许它也是一个二维数组,但是对于大多数部分我们想要使用单个指针数组的语法,而且两个维度只会混淆问题。 To use ints for example: 以使用int为例:

int a; 

a is the name of a variable that refers to a bloc of memory that holds an int. a是一个变量的名称,它引用一个包含int的内存块。

int* aPtr;

aPtr is the name of a variable that refers to a bloc of memory that holds a size_t type. aPtr是一个变量的名称,它引用一个包含size_t类型的内存块。 All pointers are size_t types just as all ints are int types, floats are float types. 所有指针都是size_t类型,就像所有int都是int类型一样,浮点数是float类型。 The size_t it holds will be assigned an address ( aPtr = &a , or aPtr = malloc(sizeof(int)) ). 它所持有的size_t将被分配一个地址( aPtr = &a ,或aPtr = malloc(sizeof(int)) )。 Because this is an int pointer the assigned address will be the size of an int, and it will store an int. 因为这是一个int指针,所分配的地址将是int的大小,并且它将存储一个int。 Thus you assign an address to aPtr . 因此,您为aPtr分配地址。 You assign a value to this address, the memory bloc aPtr points to, by dereferencing *aPtr = 10; 您可以通过取消引用*aPtr = 10;为此地址指定一个值,即aPtr指向的内存块*aPtr = 10; You read the value in the int pointed to by dereferencing int val = *aPtr; 你读取dereferencing int val = *aPtr;指向的int中的值int val = *aPtr;

int** pPtr;

pPtr is the name of a variable that refers to a bloc of memory that holds a size_t. pPtr是一个变量的名称,它引用一个包含size_t的内存块。 The address stored in this size_t is the address of another size_t bloc of memory, ie, a pointer. 存储在该size_t中的地址是另一个size_t块存储器的地址,即指针。 This second size_t bloc is the pointer that will hold the address of the integer. 第二个size_t bloc是保存整数地址的指针。 Thus you have: 因此你有:

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 needs to be dereferenced to access the pointer it points to. 需要取消引用pPtr才能访问它指向的指针。 Specifically we want the pointer pointed to to be bPtr , the second element in the array so *(pPtr + 1) . 具体来说,我们希望指向的指针是bPtr ,数组中的第二个元素是*(pPtr + 1) But we want the value that bPtr points to, not bPtr 's address so we have to dereference *(pPtr + 1) hence *(*(pPtr + 1)) 但我们想要bPtr指向的值,而不是bPtr的地址,所以我们必须取消引用*(pPtr + 1)因此*(*(pPtr + 1))

Void pointers can be included thusly: 因此可以包括空指针:

void** vPtr = malloc(2 * sizeof(void*));
*(vPtr + 0) = aPtr;
*(vPtr + 1) = bPtr;

printf("vPtr[1] is %d\n", *((int*)*(vPtr + 1)));

As several commentators have have already noted the void pointer must be cast back to type. 正如一些评论员已经注意到,必须将void指针强制转换为类型。 Thus aPtr and bPtr which were stored in the array as void pointers need to be cast back into int pointers: (int*)*(vPtr + 1) 因此,作为void指针存储在数组中的aPtrbPtr需要被转换回int指针:(int *)*(vPtr + 1)

您需要在取消引用之前强制转换void *指针。

((some_type *)(s.data))[s.elements] = *(some_type *)item;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM