什么是使用指针的正确方法。它们如何真正起作用?

时间:2016-04-22 15:44:25

标签: c pointers memory-address

我一直试图解决这个问题。

根据我的理解,指针声明如下:

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的值。

有人可以为我澄清一下吗?我的逻辑列错了吗?如果是这样我该怎么看?

3 个答案:

答案 0 :(得分:4)

int x = 1;

获取指向x的指针

int * p = &x;

而不是

int * p = x;

所以你发现后者令人困惑是正确的。

在你的第二个例子中,当你说

*p2 = *p;

会将事件p指向(变量1中包含的值x)并尝试将其存储在p2点的任何位置。遗憾的是,p2尚未初始化,并且没有指出任何有用的内容,因此结果不太可能是您想要的任何内容。所以,再次,如果你对这会做什么感到困惑,你就应该感到困惑。

答案 1 :(得分:2)

重要的是,在计算机内存中没有整数或指针 - 只有字节序列。这是您的程序将这些字节解释为intint*在您的程序之外,它只是字节

让我们一步一步看看你的例子。假设为了演示目的,你有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];

分配了单元格7,8,9,10,11
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字节)"的形式给出值。指针的类型只是告诉编译器如何在偏移后读取内存中的数据。