繁体   English   中英

使用函数返回指针作为左值

[英]Using function returning pointer as lvalue

假设我想动态分配一个数组,该数组可以保存任何数据,即在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;
}

这不是问这个问题的第一时间,但是答案通常是基于“您试图为函数分配某些东西,而不是不允许的函数返回值”。 足够公平,但是可以解决这个问题吗? 我有些困惑!

不允许对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.

相同的原理适用于返回空指针的函数。

您只需要将函数返回的指针强制转换为允许赋值的类型。

在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

像这样实现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;
getElement(test, 2) = (void*)&testThing;

这永远都行不通。 您不能为函数分配值。 用这个:

test[2] = (void*)&testThing;

请注意, getElement(test, 2)返回NULL ,它不是指向数组test的元素索引2的指针,而是它的值(这也是一个指针,但不是您需要的指针)。 无论您如何使用getElement(test, 2)提供的信息,您都无法使用它来更改test[2]

假设调用者无权访问test ,则必须编写setElement()函数。

void setElement(void** array, size_t index, void* value) {
  array[index] = value;
}
...
setElement(test, 2, (void*)&testThing);

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

指针的逻辑相同

暂无
暂无

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

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