假设我想在C中动态分配一个可以容纳任何数据的数组,即使用void**
作为我的类型。然后,不是每次都重写指针算术逻辑,我想要一个简单的函数返回元素的地址。为什么我不能在赋值中使用这个函数(即,我可以设置,以及获取元素的值)?
以下是一些示例代码:
#include <stdio.h>
#include <stdlib.h>
void printIntArray(void** array, size_t length) {
printf("Array at %p\n", array);
while (length--) {
printf(" [%zu] at %p -> %p", length, array + length, *(array + length));
if (*(array + length)) {
printf(" -> %d", *(int*)*(array + length));
}
printf("\n");
}
}
void* getElement(void** array, size_t index) {
return *(array + index);
}
int main(int argc, char** argv) {
const size_t n = 5;
size_t i;
/* n element array */
void** test = malloc(sizeof(void*) * n);
i = n;
while (i--) {
*(test + i) = NULL;
}
/* Set element [1] */
int testData = 123;
printf("testData at %p -> %d\n", &testData, testData);
*(test + 1) = (void*)&testData;
printIntArray(test, n);
/* Prints 123, as expected */
printf("Array[1] = %d\n", *(int*)getElement(test, 1));
/* Something new in [2] */
/* FIXME lvalue required as left operand of assignment */
int testThing = 456;
getElement(test, 2) = (void*)&testThing;
printIntArray(test, n);
return 0;
}
这不是第一次提出这个问题,但答案通常是“你试图将某些东西分配给一个函数,而不是一个函数的返回值,这是不允许的”。很公平,但可以解决这个问题吗?我有点困惑!!
答案 0 :(得分:2)
不允许对void进行赋值,因此您需要将void指针强制转换为其他任何类型的指针。
换句话说,
void *vPtr = malloc(35);
*((int *)vPtr) = 5; // legal since cast void * to int *
*vPtr = 5; // illegal since size of the memory location pointed to is unknown.
同样的原则适用于返回void指针的函数。
您只需将函数返回的指针强制转换为允许赋值的类型。
在Visual Studio 2005中编译的一个简单示例是。
void *xPtr (int *pp)
{
return pp;
}
void jj ()
{
int jjj;
*( (int *)xPtr(&jjj)) = 6;
}
如果您将函数jj()
更改为
void jj ()
{
int jjj;
*(xPtr(&jjj)) = 6;
}
您将看到编译错误,例如
1>c:\fileobject.c(191): error C2100: illegal indirection
1>c:\fileobject.c(191): warning C4047: '=' : 'void *' differs in levels of indirection from 'int'
1>c:\fileobject.c(191): error C2106: '=' : left operand must be l-value
答案 1 :(得分:2)
像这样实施getElement()
:
void ** getElement(void ** ppv, size_t index) {
return ppv + index;
}
并像这样使用它:
*getElement(test, 2) = &testThing;
如果您使用宏,您甚至可以按照预期的方式进行:
#define GET_ELEMENT(ppv, index) \
(*(ppv + index))
像这样使用:
GET_ELEMENT(test, 2) = &testThing;
答案 2 :(得分:1)
getElement(test, 2) = (void*)&testThing;
这不会奏效。您无法为函数指定值。使用此:
test[2] = (void*)&testThing;
注意getElement(test, 2)
返回NULL
,它不是指向数组2
的元素索引test
的指针,它是它的值(也是指针,但不是你需要的那个)。无论您使用getElement(test, 2)
为您提供的信息如何处理,您都无法使用它来更改test[2]
。
假设调用者无权访问test
,您必须编写setElement()
函数。
void setElement(void** array, size_t index, void* value) {
array[index] = value;
}
...
setElement(test, 2, (void*)&testThing);
答案 3 :(得分:0)
C使用指向伪的指针,其他语言称之为引用...以下是您尝试执行的操作示例:
typedef struct
{
int x;
} st;
st f()
{
st p;
p.x = 20;
return p;
}
int main()
{
f().x = 9;
}
您正在从函数返回一个值...您需要在使用它之前将该值赋值给某个值。是的,指针遵循相同的规则,不同之处在于它的值是某些东西的地址......所以你必须将函数的返回值分配给void *变量以及你想要做什么这个变量。
在我的例子中,为了使它工作,你需要像:
int main()
{
st v = f();
v.x = 9;
}
指针
的逻辑相同