11

c语言入门20,一文扒开C语言指针神秘的外衣,终于明白了

 3 years ago
source link: https://blog.popkx.com/c-language-entry-20-a-text-to-remove-c-language-pointer-mysterious-cloak-and-finally-understand/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

c语言入门20,一文扒开C语言指针神秘的外衣,终于明白了

发表于 2018-11-16 08:11:28   |   已被 访问: 297 次   |   分类于:   C语言   |   暂无评论

指针是 C 语言的灵魂,指针可以直接操作内存,指针使C程序更加高效,等等等等。相信 C 语言初学者学到指针时,会看到很多这样描述指针的话,但是却往往一头雾水。所以,本节不会一上来就直接说指针,但是相信我,看完本节,你一定会觉得 C 语言的指针也不过如此,没那么神秘。

a6cd1ef4134fbe94e6d5d027c84c5a39.png

上一节介绍了 C 语言中的数据类型,提到不同的数据类型的主要区别在于占用的存储空间不同。我们知道,C 程序是运行在计算机的内存中的,因此 C 程序的变量也是存在于内存中的。C 标准规定 char 类型占用一个字节的存储空间,对其他整型却没有做规定,现在为了解释的方便,我们假设 int 类型的数据占用内存 4 个字节。

假设我们如下定义了两个变量:

signed char i = 3;
int j = 8;

那么,i 占用了 1 字节的内存空间,j 占用了 4 字节的内存空间,请看下图。

dc717c39c15f0c62381f7d2281497cdc.png

方框表示内存空间,内部表示存储的值。我们把内存逐字节编号,方框外部的数字表示方框的编号(这样的内存“编号”即所谓的“内存地址”)。修改变量 i 的值,实际上就是修改地址为 4000 的内存空间里的值。那反过来呢?如果我修改了地址为 4000 的内存空间里的值,i 的值会相应改变吗?答案是肯定的,请继续往下看。
56d23d752c20e69dfc29ab96809cd538.png

上图中的内存地址“4000”是我为了解释方便随意取的。那么,在实际应用中,变量 i 的地址如何获取呢?C 语言提供了“&”运算符,就是获取变量地址的。请看下面的例子:

#include <stdio.h>
int main()
{
    signed char i = 3;
    int j = 8;
    long p1 = (long)&i;
    printf("p1: %ld\n", p1);
    return 0;
}
4ca43539576eade936dc1db99b94cad5.png

我们取出了 i 的地址,把它强制转换为 long 型(关于强制类型转换,可参考上一节),传递给 p1 了。编译执行,发现变量 i 的地址被打印出来了。这说明,C 程序变量的地址也是一个整数。

按照上面的说法,修改 i 的值除了直接对 i 赋值以外,还可以通过修改 p1 地址处的内存空间里的数值。那,怎样才能“通过修改 p1 地址处的内存空间里的数值”修改 i 的值呢?

上面的代码实例中,我们使用了 long 型变量 p1 存储了 i 的地址。事实上,C 语言有专门的数据类型存储地址,定义方式也很简单,就是:“类型描述符 * ”,例如,可以定义以下变量存储地址:

signed char *p1 = &i;
int *p2 = &j;
781b25194d3348a0e4a0af40be4293e3.png

p1 和 p2 就是 C 语言中所谓的指针类型,因为 i 是 signed char 类型的,所以定义了 signed char * 类型的指针存储 i 的地址。j 是 int 类型的,所以定义了 int * 类型的指针存储 j 的地址。另外,C 语言提供了“&”运算符取变量地址,与之对应的,还提供了“ * ”运算符从相应地址内存里取出数值。

好了,了解了 C 语言的指针类型和“ * ”运算符,现在来看看如何“通过修改 p1 地址处的内存空间里的数值”修改 i 的值。请看如下代码:

signed char *p1 = &i;
*p1 = 5;
printf("i=%d\n", i);
6f12e85b12c98629102cf8ed463e4e52.png

编译运行,发现程序输出“i=5”,这样我们就实现了“通过修改 p1 地址处的内存空间里的数值”修改 i 的值。

在定义变量时," * "放在变量符号前,可以定义指针变量。在定义完指针变量后,“ * ”放在变量前,就表示从地址取值的运算符了。另外,“ * ”还可以表示乘法运算符,读者自己思考什么情况下,“ * ”表示乘法运算符。

以上的操作,实际上就是 C 语言的指针操作,可以看出它一点也不神秘,接下来几节,我们将继续讨论 C 语言的指针,比如为什么 int 类型的变量 j 的地址要使用 int* p2; 定义,而不能使用 signed char* p2; 定义,使用指针为何能写出紧凑、高效的 C 程序等等。

阅读更多:   C语言


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK