为什么我需要在 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的静态类型检查会发现aPtr
是int
类型,a
是int
类型(因此&a
是类型int*
),然后将 &a
从 int*
强制转换为 int
,然后将该地址 存储为 int
变成 aPtr
。当 *
取消引用 aPtr
时,您将 运行 出错,因为 aPtr
是 int
类型。由于您从 int*
转换为 int
,aPtr
现在是 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 的类型系统按预期工作。
为什么这是有效的:
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的静态类型检查会发现aPtr
是int
类型,a
是int
类型(因此&a
是类型int*
),然后将 &a
从 int*
强制转换为 int
,然后将该地址 存储为 int
变成 aPtr
。当 *
取消引用 aPtr
时,您将 运行 出错,因为 aPtr
是 int
类型。由于您从 int*
转换为 int
,aPtr
现在是 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 的类型系统按预期工作。