为什么我需要在 C 中用 * 定义对指针的引用?

Why do I need to define a reference to a pointer in C with *?

为什么这是有效的:

int a = 5;
int *aPtr = &a;
printf("%i", *aPtr);

但这不是:

int a = 5;
int aPtr = &a;
printf("%i", *aPtr);

我不是在寻找它抛出的错误。我试图理解为什么这在概念上行不通。

案例 1 :-

int a = 5;
int *aPtr = &a; /*this is valid bcz aptr is pointer and it need address and `&a` is valid address*/
printf("%i", *aPtr);/* here you can do *aptr, bcz aptr is pointer and
                     we can dereference pointer variable */ 

情况 2 :- 当您 int aptr = &a; 通过使用 -Wall 编译时阅读编译器警告,它说明了一切。

int a = 5;
int aPtr = &a;/* aptr is normal variable, you are assigning address to it ,but you can't dereference it like *aptr bcz aptr is not pointer */     

由于 aptr 是普通变量,当您执行 *aptr 时它会抛出错误,因为取消引用运算符 * 适用于指针变量,而不适用于普通变量。

printf("%i", *aPtr); /* invalid */ 

第一个无效,因为 & 是一元运算符,需要左值(变量),不能应用于右值(常量)。

出于同样的原因,这阻止了第二个有效。但是假设您将 5 替换为您创建的变量:

int a = 5;
int aPtr = &a;
printf("%i", *aPtr);

那么C的静态类型检查会发现aPtrint类型,aint类型(因此&a是类型int*),然后将 &aint* 强制转换为 int,然后将该地址 存储为 int 变成 aPtr。当 * 取消引用 aPtr 时,您将 运行 出错,因为 aPtrint 类型。由于您从 int* 转换为 intaPtr 现在是 int,而不是 int*

如果您按如下方式修复此问题:

int a = 5;
int aPtr = &a;
printf("%i", aPtr);

然后它会编译,打印 a 的地址(分配在堆栈上的变量),尽管它仍然会对从 int*int 的转换发出警告.

编辑:当机立断。

您的示例不起作用,因为:

sizeof(int)  == 4; // Bytes (usually)
sizeof(int*) == 8; // Bytes (assuming x86_64)

因此,在分配int aPtr = &a;时,最重要的4个字节将丢失。

这将工作只是找到(虽然不建议):

#include <stdint.h>
int main()
{
        int a = 5;
        uint64_t aPtr = (uint64_t)&a;
        printf("%i", *(int*)aPtr);
}

int aPtr = &a; 声明了一个名为 aPtr 且类型为 int 的对象,因此它不是指针。

更糟的是,sizeof(int) != sizeof(int *) 在几个常见平台上(例如 Windows 自 Windows XP 以来的所有 x64 版本),因此您会丢失一些信息指针包含,可能使存储的值无用。

假设它有效,但是,aPtr 仍然是一个 int 类型的对象,因此您不能使用指针间接获取存储在 aPtr 中地址的值,这意味着表达式 *aPtr 不会编译。没有什么可以阻止您将 aPtr 转换为正确的指针类型:

int a = 5;
int aPtr = &a;
printf("%i", *(int *)aPtr);

同样,这是假设 aPtr 存储了 a 的完整地址。无论如何,这只是 C 的类型安全在起作用,这是一件好事(参见上面的 sizeof(int) != sizeof(int *) 段)。

如果 "conceptually" 你的意思是 "assuming the address is properly stored in aPtr",除了它不是有效的 C 之外,你的代码没有任何问题,如上面的转换示例所示。如果地址是 0x80,您甚至可以根据需要将其存储在一个很小的 ​​unsigned char 对象中。它存储在内存中的那个地址,不管 C 拒绝编译语法无效的代码来阻止你用它做什么。当然,只使用正确的变量类型要容易得多,而不是与编译器作斗争并强制转换。

然后,您可能又会问,"If &a is stored in aPtr, why can't the compiler recognize that and simply understand *aPtr means the same thing as *&a?" 如果是这个问题,那么答案很简单:一旦您将 &a 存储在某种类型 T 的对象中,编译器知道对象用于存储 T 类型的值,仅此而已。它不知道它包含内存地址,无论您是否在该对象中存储了一个地址;它只知道里面存储了一个 T 类型的值。同样,这只是 C 的类型系统按预期工作。