在 C 中的结构中访问 void *

  • 本文关键字:void 访问 结构 c malloc
  • 更新时间 :
  • 英文 :


List.c

int const LIST_SIZE = 100;
typedef struct node {
void *item;
} Node;
typedef struct list {
Node *currentItem;
Node *items[LIST_SIZE];
} LIST;

主.c

#include <stdlib.h>
#include <printf.h>
#include "List.h"

LIST *ListCreate();
int main() {
LIST *newList = ListCreate();
Node *newNode = malloc(sizeof(Node));
newList->currentItem = newNode;
newNode->item = (int *)200;
printf("%d", *((int *)newNode));
}
LIST *ListCreate() {
LIST *newList = malloc(sizeof(LIST));
return newList;
}

我的问题是: 在main.c中,我使用printf语句来访问newNode中的项目。根据我的理解,正确的调用应该是:

printf("%d", *((int *)newNode->item));

但是,使用它时我遇到了分段错误。谁能解释一下为什么这不起作用而另一个有效?

谢谢。

>(int*)200告诉编译器取数字200并假装它是int的地址。但是,它实际上不是int的有效地址,因此您无法取消引用它(即您不能使用*(int*)newNode->item来获取该地址的int)。

您要做的只是告诉编译器获取"地址"并将其再次视为数字,您可以使用:

printf("%d", (int)newNode->item);

(int)演员表撤消了之前的(int*)演员表。

旁注:在这里使用(int*)有点不寻常;没有理由使用它代替(void*)

您将200(不是指针值)存储在指针变量中,然后将该变量视为指针,即使它实际上不包含指针值。


某些类型type的一般模式:

Node* node = malloc(sizeof(Node));
node->item = malloc(sizeof(type));
*((type*)node->item) = ...;
type val = *((type*)node->item);
free(node->item);
free(node);

所以,要存储一个int,它将是

Node* node = malloc(sizeof(Node));
node->item = malloc(sizeof(int));
*((int*)node->item) = 200;
printf("%dn", *((int*)node->item));
free(node->item);
free(node);

现在,指针可用于存储整数,因此您可以在这种特殊情况下使用一些技巧来保存分配。这是一个更高级的解决方案。

Node* node = malloc(sizeof(Node));
node->item = (void*)200;             // Store the number in a pointer variable.
printf("%dn", (int)node->item);     // Treat the pointer variable as an `int`.
free(node);

main()稍作更改,让我们看一下在调试模式下使用 Visual Studio 2013 运行的应用程序。

修改后的main()如下:

int main() {
LIST *newList = ListCreate();
Node *newNode = malloc(sizeof(Node));
newList->currentItem = newNode;
newNode->item = (int *)200;       // assign the value 200 to the pointer item
printf("*((int *)newNode)  %dn", *((int *)newNode));         // works
printf("((int)newNode->item)  %dn", ((int)newNode->item));   // works
printf("*((int *)newNode->item)  %dn", *((int *)newNode->item));  // access violation exception 
}

运行此控制台应用程序时,显示的窗口包含两行输出:

*((int *)newNode)  200
((int)newNode->item)  200

在调试器中,当单步执行函数时main()指示的行上引发访问冲突异常。访问冲突的实际文本为:

First-chance exception at 0x010E1BAF in ConsoleApplication1.exe: 0xC0000005: Access violation reading location 0x000000C8.
Unhandled exception at 0x010E1BAF in ConsoleApplication1.exe: 0xC0000005: Access violation reading location 0x000000C8.

0x000000C8,读取的位置是十进制数 200,当尝试取消引用指针item作为包含值 200 的int指针时,内存位置 200 对于在用户模式下在 Windows 10 下运行的此应用程序无效。

*((int *)newNode)表示将变量newNode的值视为指向int的指针,然后在该地址获取值。这是有效的newNode因为它包含此应用程序可以访问的地址。

(int)newNode->item表示将变量newNode->item的值视为int并获取该变量的值。该变量不被视为指针,而是被视为包含int的变量。

*((int *)newNode->item)意味着将变量newNode->item的值视为指向int的指针,然后在该地址获取值。这不起作用,因为变量newNode->item的值(值 200)不是此应用程序可以访问的地址,因此在尝试时会引发访问异常。

根据我的理解,正确的调用应该是:

printf("%d", *((int *)newNode->item));

这只从句法的角度来看是正确的。但这是错误的,因为您没有正确使用指针。

newNode->item = (int *)200;

不确定您期望该行做什么。 将 200 转换为int*不会为您提供有效的指针。

*((int *)newNode->item

仅取消引用值200假装为有效指针。这会导致未定义的行为。

您可以使用:

// Allocate memory for newNode->item
newNode->item = malloc(sizeof(int));
// Set the value
*((int *)newNode->item) = 200;
// Print the value
printf("%d", *((int *)newNode->item));

除非你想在node中存储其他类型的对象,否则我建议使用:

typedef struct node {
int item;
} Node;

然后你的代码可以简单一点。

// Set the value
*newNode->item = 200;
// Print the value
printf("%d", newNode->item);

最新更新