虚拟指针的动态数组

时间:2014-01-09 11:49:40

标签: 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 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指针进行了研究,但显然我在这里遗漏了一些东西。我很感激我能得到任何帮助。感谢阅读,希望能回答!

4 个答案:

答案 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 = &aaPtr = 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指针存储在数组中的aPtrbPtr需要转换回int指针:(int *)*(vPtr + 1)

答案 3 :(得分:0)

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

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