我很困惑为什么这段代码会导致段错误
int array[] = {1, 2};
void** ptr = (void**) &array;
printf("%d", *(int*)ptr[0]);
Run Code Online (Sandbox Code Playgroud)
我希望它打印存储在 array[0] 中的 int,但它却出现段错误。
根据您期望看到的内容,您似乎认为数组是指针。它不是。
在大多数情况下,数组会衰减为指针,但不是指针。它是一组连续的值。这也意味着数组的地址将与第一个值的地址相同,尽管它们的类型不同。
在这一行:
void** ptr = (void**) &array;
Run Code Online (Sandbox Code Playgroud)
您获取数组的地址(与第一个成员的地址相同)并将其分配给ptr。
现在让我们分解一下您要打印的内容:
*(int*)ptr[0]
Run Code Online (Sandbox Code Playgroud)
您正在获取ptr具有类型的 whichvoid **并通过数组索引运算符与 取消引用它ptr[0]。这本身就是未定义的行为int[2],因为您正在尝试访问void *. 虽然 avoid *可以用作通用指针类型,但它不能扩展到void **.
但假设这按“预期”工作,您现在有一个类型的表达式void *,其值是数组的字节。如果您ptr[0]使用%p格式说明符进行打印,您可能会看到打印“0x200000001”(假设您的机器是小端字节序。
然后,您获取指针值 0x200000001,将其转换为 a int *,并取消引用它。由于该指针值可能不是有效值,因此当您尝试取消引用它时会出现段错误。
如果您使用void *如下:
void *ptr = array;
printf("%d", *(int*)ptr);
Run Code Online (Sandbox Code Playgroud)
甚至:
void *ptr = &array;
printf("%d", *(int*)ptr);
Run Code Online (Sandbox Code Playgroud)
你会得到预期的结果。