我一直试图解决这个问题。
根据我的理解,指针声明如下:
int x =1;
int* p;
根据我的理解,p当前没有指向任何东西,但无论p指向什么都应该是int。有道理。
然后将x的地址传递给p,以便它可以指向其值
p = &x
现在x等于也等于* p,反之亦然。
遵循这一系列逻辑,如果你想初始化一个指针,你会这样做:
int x = 1;
int* p = x;
但这令我感到困惑。现在我所理解的是p的值(无论它指向什么)是x,1的值,但实际上并不指向x。那怎么办? p没有指向任何东西,但它指向的是1?我不明白。
我想知道的另一件事是指针=指针是如何工作的?
让我们看看另一个例子以及我的逻辑:
int x = 1;
int* p;
int* p2;
p = &x;
*p2 = *p;
这转化为我:p2处的指向值等于指向p的值,但不指向p指向的变量(即x),只是x的值。
有人可以为我澄清一下吗?我的逻辑列错了吗?如果是这样我该怎么看?
答案 0 :(得分:4)
在
int x = 1;
获取指向x
的指针
int * p = &x;
而不是
int * p = x;
所以你发现后者令人困惑是正确的。
在你的第二个例子中,当你说
时*p2 = *p;
会将事件p
指向(变量1
中包含的值x
)并尝试将其存储在p2
点的任何位置。遗憾的是,p2
尚未初始化,并且没有指出任何有用的内容,因此结果不太可能是您想要的任何内容。所以,再次,如果你对这会做什么感到困惑,你就应该感到困惑。
答案 1 :(得分:2)
重要的是,在计算机内存中没有整数或指针 - 只有字节序列。这是您的程序将这些字节解释为int
或int*
。 在您的程序之外,它只是字节
让我们一步一步看看你的例子。假设为了演示目的,你有256字节的内存,而你的int
只有1字节:
第1步: 你在哪里声明和分配一个变量
program:
int x = 1;
...
说你的编译器决定为变量x
分配内存单元12:
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |12:1| ... |255:X|
第2步: 你在哪里声明指针
program:
int x = 1;
int *p;
...
回忆第1步 ...并为编译器分配了变量p
的内存单元格5(注意 - p
尚未初始化,因此单元格5中的值为{ {1}}):
X
第3步: 你在哪里指定指针
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:X| .. |12:1| ... |255:X|
回忆第2步 ...现在,单元格program:
int x = 1;
int *p;
p = &x;
...
存储指向p
的指针。我们知道已为x
分配了单元格12,因此将12存储到x
(单元格5)中:
p
第4步: 你在哪里声明第二个指针
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12| .. |12:1| ... |255:X|
回忆第3步 ...并且您的编译器为变量program:
int x = 1;
int *p;
p = &x;
int *p2;
...
分配了内存单元格6(它尚未分配,因此值为p2
):
X
第5步: 你在哪里指定第二个(仍未定义!)指针:
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12|6:X| .. |12:1| ... |255:X|
回忆第4步然后program:
int x = 1;
int *p;
p = &x;
int *p2;
*p2 = *p;
...
使编译器回想起*p
是单元格5,因此它生成了从单元格5读取的insruction(有值12)并使用它value作为实际结果的地址:从单元格p
读取返回1.现在编译器知道已向单元格#6 12
提供名称p2
为6,但是{{1}表示您需要读取p2的值并将其用作实际存储的地址。但在我们的例子中,这个值是p2
(未定义)!但是在实际的内存芯片中没有未定义的值,并且在引导时存储了一些值(比如值*p2
)。如果虚拟内存受到影响,事情会变得更加复杂,但我不想在这里讨论它。因此,假设启动时的电荷和宇宙射线将该单元初始化为随机值X
。让我们看看42
将被执行时会发生什么:我们已经看到42
如何让我们返回1,现在程序将尝试找到将其存储到的位置。它将读取*p2 = *p
的值,产生42,现在程序将*p
存储到内存单元p2
,结果将显示:
1
在现实世界中,但是使用未初始化的值会经常导致崩溃。当虚拟内存涉及某些地址空间区域(我们的256个地址)可能没有为它们分配存储单元时,写入这样的地址会导致崩溃。
第6步:
您在哪里指定第二个指针并使其定义再次指向42
:
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12|6:X| .. |12:1| ... |42:1| ... |255:X|
回忆第4步并忽略导致程序崩溃的第5步 ...现在编译器知道哪些单元格用于x
(单元格5)和program:
int x = 1;
int *p;
p = &x;
int *p2;
p2 = p;
...
(细胞6)。因此,赋值p
以这种方式工作:从p2
(即12)获取值,不要将其解释为指针,而只是将其复制到p2=p
。现在,使用指向p
(单元格12)的指针初始化p2
。
p2
第7步: 在哪里指定指向未命名位置的指针:
x
...让我们关注这一行:memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12|6:12| .. |12:1| ... |42:X| ... |255:X|
这显示了如何指定指向未命名的内存单元格的指针。回想一下,编译器还没有为单元格#100分配名称。但是,如果你确定在这个内存位置有一些有趣的东西,例如计算机设备通过该单元与我们通信,那该怎么办呢?如果键盘将下一个字符存储到存储单元#100并且我们想要读取它会怎么样?现在您可以将其读作program:
int x = 1;
int *p;
p = &x;
int *p2;
p2 = (int*)100;
...
:
p2 = (int*)100;
第8步: 你在哪里揭示指向数组的指针的关系:
*p2
...让我们关注这一行:memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12|6:100| .. |12:1| ... |42:X| ... |100:keyboard| ... |255:X|
:这个声明行告诉编译器分配5个单元格并为它们使用名称program:
int x = 1;
int *p;
p = &x;
int a[5];
a[2]=18;
int *p2 = a;
p2[2]=3;
...
。编译器为int a[5];
:
a
请注意,它没有分配指针 - a
将像任何其他变量一样使用!这就是memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12|6:100|7:X|8:X|9:X|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|
的工作原理:第一个编译器知道a
开始和a[2]=18
,所以它使用该值作为开始,然后它将a
添加到7
}。因此找到目标存储单元 - 它是单元号9,因此它将18存储到该单元中:
2
所以让我们看看9
是如何工作的:编译器知道|0:X|1:X|2:X| ... |5:12|6:100|7:X|8:X|9:18|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|
从7开始。因此7被存储到int *p2 = a;
中(回想一下,#6单元被分配给{{1}在步骤4)
a
初始化指针后,您可以将其用作数组p2
:这是p2
的缩写。 |0:X|1:X|2:X| ... |5:12|6:7|7:X|8:X|9:18|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|
的值是7,加2得9,所以我们将3存储到单元格#9:
p2[2]=3;
很抱歉这么长的解释我试图涵盖值,变量,指针和数组之间的关系以及大多数用例。
答案 2 :(得分:0)
我认为有必要记住指针本身就是整数。因此,当您创建指针时,它实际上只是内存中的偏移数。指针的类型只是告诉编译器在取消引用指针时如何解释数据。所以当你做这样的事情时:
int *p = &x;
您只是将一个整数分配给p
,即x的内存地址(偏移量)。从某种意义上说,所有指针都具有相同的"类型",它们是32位或64位整数,具体取决于架构。取消引用这样的指针:
int y = *p;
只是意味着"通过p字节偏移到内存中,并以int(4字节)"的形式给出值。指针的类型只是告诉编译器如何在偏移后读取内存中的数据。