在C中的结构中访问void *

时间:2017-05-12 03:36:51

标签: 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;

的main.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));

但是,使用它时会出现分段错误。有人可以解释一下为什么这不起作用而另一个有效吗?

感谢。

3 个答案:

答案 0 :(得分:0)

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

您要做的就是告诉编译器取“地址”并再次将其视为一个数字,您可以使用:

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

(int)演员撤消之前的(int*)演员阵容。

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

答案 1 :(得分:0)

您将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("%d\n", *((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("%d\n", (int)node->item);     // Treat the pointer variable as an `int`.

free(node);

答案 2 :(得分:0)

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)  %d\n", *((int *)newNode));         // works
    printf("((int)newNode->item)  %d\n", ((int)newNode->item));   // works
    printf("*((int *)newNode->item)  %d\n", *((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)不是此应用程序可以访问的地址,因此在尝试时会抛出访问异常。