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

时间:2018-04-28 03:17:10

标签: c pointers memory reference pass-by-reference

为什么这有效:

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

但这不是:

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

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

4 个答案:

答案 0 :(得分:2)

你的例子不起作用,因为:

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);
}

答案 1 :(得分:2)

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

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

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

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

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

如果在概念上&#34;&#34;你的意思是&#34;假设地址已正确存储在aPtr&#34;中,除了它无效的C之外,你的代码没有任何问题,因为以上例子显示。如果地址是0x80,您甚至可以将它存储在一个小的unsigned char对象中,如果您愿意的话。它存储在内存中的该地址,无论C通过拒绝编译语法无效的代码阻止您使用它。当然,使用正确的变量类型要容易得多,而不是对抗编译器和投射事物。

然后,您可能会问,&#34;如果&a存储在aPtr中,为什么编译器无法识别,只需理解*aPtr就意味着与*&a相同的事情?&#34;如果这是问题,那么答案很简单:一旦将&a存储在某种类型T的对象中,编译器就会理解该对象用于存储类型{{1}的值这就是全部。它不知道它包含一个内存地址,无论你是否在那个对象中存储了一个;它只知道存储在其中的T类型的值。同样,这只是C型系统按预期工作。

答案 2 :(得分:1)

案例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 */ 

答案 3 :(得分:0)

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

这可以防止第二个因同样的原因而生效。但是假设您用您创建的变量替换了5

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

然后C的静态类型检查会发现aPtr的类型为inta的类型为int(因此&a的类型为{{ 1}}),然后从int*投射(带警告)&aint*,然后将该地址存储为 int int。然后,aPtr解除引用*时会遇到错误,因为aPtr的类型为aPtr。由于您已从int投放到int*int现在为aPtr,而不是int

如果你修改如下:

int*

然后它会编译,打印int a = 5; int aPtr = &a; printf("%i", aPtr); 的地址(在堆栈上分配的变量),尽管它仍会对从aint*的强制转换发出警告。 / p>

编辑:击败拳头。