这与家庭作业有关,但这似乎是一个常见的问题,因此问题就在这里。
我有两个结构
typedef struct Vector {
Element **elements;
int top;
int max_size;
} Vector;
typedef void Element;
向量由元素组成,元素可以是任何类型,原始或不是。
使用此函数向向量添加值(尚未编写)。
void Add_To_Vector(Vector *old_vector, Element *element, int index) {
// create a new vector. loop throught the elements in old vector and
// assign each to a newly created vector. return new vector.
}
在主要部分
scanf("%d %d", &vector_value_int, &index);
Add_To_Vector(vector, vector_value_int, index);
不是将vector_value_int传递给函数,而是需要传递一个元素指针(不知何故将point元素传递给输入的值)。我尝试了很多不同的东西,但是gcc不断发出警告:
如何使用元素将该参数或任何类型参数传递给函数?对于“typedef void Element”的含义,我也很遗憾。它存储数据吗?它需要内存分配吗?
谢谢!
答案 0 :(得分:2)
类型void只是一种说法:'它没有类型'。因此,void指针是指向内存的一部分的指针,而不知道其中的内容。所以Element =没有意义的类型。
现在,要传递指向vector_value_int的指针,您应该使用运算符&
Add_To_Vector(vector, &vector_value_int, index);
& variable =变量的l值(地址)。
如果你有一个指针,并且你想获得它所指向的内存的内容,你应该使用运算符*。
* pointer =存储在指针中包含的地址中的值。
这里类型为void,你应该将它强制转换为(int)以将其解释为整数。
如果要在结构中存储某些内容,应使用malloc分配vector_value_int,因为如果不是,则该变量将存储在堆栈中,并且当声明它的过程完成时,该地址将被释放并且不确定结果可能会出现。
实际例子:
void add_to_vec(Vector *oldvector, Element *element, int pos) {
printf("%d\n", *((int*)element));
//iterate over the oldvector->elements
//and create the new one
}
int main() {
Vector vec;
int x = 3; // this should be done with malloc
add_to_vec(&vec, (Element*)&x, 0);
}
答案 1 :(得分:2)
首先,让我们忽略所有的typedef;这是一种罕见的情况,它们掩盖的不仅仅是它们的照明。
以下是C语言标准{草稿n1256)中void
数据类型的定义:
6.2.5类型
...
19void
类型包含一组空值;它是一种不完整的类型,无法完成。
IOW,void
是一种“不属于上述”的数据类型;它没有相关的值。类型为void
的函数没有返回值,不应使用void
表达式的(不存在)结果。
与任何其他不完整类型一样,您可以创建指向void
的指针。它们作为一种通用指针类型; void
指针可用于指向任何其他类型的对象:
6.3.2.3指针
1指向void
的指针可以转换为指向任何不完整或对象类型的指针。指向任何不完整或对象类型的指针可以转换为指向void
并再次返回的指针;结果应该等于原始指针。
因此,例如,我可以使用void指针指向int,float或char数组等:
int x = 1;
double y = 2.0;
char *z = "three";
void *p[3];
p[0] = &x;
printf("address of x is %p\n", p[0]);
p[1] = &y;
printf("address of y is %p\n", p[1]);
p[2] = &z;
printf("address of z is %p\n", p[2]);
这是一个假设的内存映射,显示每个的值(假设为int和浮点数为32位,字符数据为ASCII):
Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
"three" 0x00001000 0x74 0x68 0x72 0x65 // string literals are stored "somewhere else"
0x00001004 0x65 0x00 xxxx xxxx // xxxx indicates any random value
...
x 0x10008000 0x00 0x00 0x00 0x01
y 0x10008004 0x40 0x00 0x00 0x00 // Binary representation of 2.0 on my system
z 0x10008008 0x00 0x00 0x10 0x00 // z contains the address of the first element of the string literal
p 0x1000800C 0x10 0x00 0x80 0x00
0x10008010 0x10 0x00 0x80 0x04
0x10008014 0x10 0x00 0x80 0x08
如您所见,p[0]
(地址0x10008010
)中存储的值是x
(0x10008000
)的地址。同样,p[1]
存储y
的地址,p[3]
存储z
的地址。 void
指针的这个属性为我们提供了一种从代码中分离类型信息的方法,尽管不像C ++模板或Java泛型那样简单。因此,我们可以使用void
指针数组来构建一个通用容器,该容器可以容纳任何类型的对象(技术上,指向对象的指针)。
注意:在采用1989标准之前,你会使用 char *
作为“通用”指针类型;但是,您必须显式地将指针值强制转换为目标类型,而不必使用void指针(在C中;对于C ++而言,这不是真的,它确实需要explcit强制转换)。这是你仍然看到人们投射 malloc/calloc/realloc
的结果的部分原因;曾几何时,你有到。
那么让我们看看你的数据结构和代码,但最初没有typedef:
struct Vector {
void **elements;
int top;
int max_size;
};
void **elements
将elements
声明为指向void的指针;在这种情况下,我们将动态分配void
指针的向量。这与上面示例中的数组p
类似。
void allocateVector(struct Vector *vector, int maxSize)
{
vector->elements = malloc(sizeof *vector->elements * maxSize);
if (vector->elements)
vector->maxSize = maxSize;
}
我们现在有一个指向void
的1-d指针数组,能够容纳maxSize
个元素。现在我们可以编写Add_To_Vector
函数:
void Add_To_Vector(struct Vector *vector, void *objectPtr, int index)
{
if (vector->elements)
{
if (index < vector->maxSize)
{
vector->elements[index] = objectPtr;
}
}
}
然而,有两个非常大的问题。首先,我们无法确定指针本身所指向的对象的类型;它只是一个地址,没有描述被指向对象的信息。如果我们想要打印矢量中所有对象的值,我们就不知道要使用哪个转换说明符。其次,如果我们按如下方式构造代码:
while (!done)
{
scanf("%d %d", &vector_value_int, &index);
Add_To_Vector(&vector, &vector_value_int, index);
...
}
我们会继续向数组添加相同的地址(&vector_value_int
),这不是我们想要的。我们想要对vector_value_int
中的内容进行复制,但是我们还没有设置知道如何执行此操作,因为我们不知道objectPtr
的类型{1}}指向。
解决这个问题的一个常见方法是使用指针信息传递所谓的回调函数;回调知道如何制作指向值的副本。例如:
void *copyIntValue(void *objectPtr)
{
int *copy = malloc(sizeof *copy);
if (copy)
*copy = *(int *) objectPtr;
return copy;
}
void Add_To_Vector(struct Vector *vector, void *objectPtr, void *(*cpyFunc)(void *), int index)
{
if (vector->elements)
{
if (index < vector->maxSize)
{
vector->elements[index] = cpyFunc(objectPtr);
}
}
}
...
while (!done)
{
scanf("%d %d", &vector_value_int, &index);
AddToVector(&vector, &vector_value_int, copyIntValue, index);
}
我们已经消除了第二个问题,但不是第一个问题;我们仍然不知道vector->elements[i]
指向哪种类型。不知何故,该信息需要作为数组的一部分保留。
我想我现在打算破解论坛软件,所以我将把它留作以后的练习。
答案 2 :(得分:1)
我将从底部开始:
typedef void Element
为现有数据类型(void)创建新名称(Element)。实际上,在编译之前,代码中“Element”的任何位置实际上都替换为“void”。你需要做的就是解决你的问题就是把你的(可能是自动/堆栈存储)vector_value_int变量,用它来创建一个新的(基于堆的,由你的向量管理)整数,然后使用指向它的指针新创建的整数,转换为Element *,以传递到Add_To_Vector函数。
答案 3 :(得分:0)
typedef Element void;
..是“void”类型的别名,它根本就没有类型。该函数采用指向Element的指针,实际上是 void指针。无效指针基本上可以指向任何东西,但有明显的警告:你丢失了类型信息。
实施例
// manipuating myint requires no knowledge of the underlying type,
// it's right there in the declaration.
int myint = 10;
myint += 5;
// manipulating data probably requires knowledge of the underlying type.
// note: it points to the same data as myint.
void *data = &myint;
// we need to cast it to a type (usually a pointer to the original type)
int *data_as_int = (int *) data;
*data_as_int += 5;
// myint is now 20.
这意味着您需要将void / Element指针传递给Add_To_Vector
。如果仔细查看对Add_To_Vector
的来电,您可能会发现为什么会收到错误。与您对scanf
的通话比较。
第一条错误消息也为您提供了重要的提示。