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));
但是,使用它时会出现分段错误。有人可以解释一下为什么这不起作用而另一个有效吗?
感谢。
答案 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)不是此应用程序可以访问的地址,因此在尝试时会抛出访问异常。