一切都是地址
C语言用变量来存储数据,用函数来定义一段可以重复使用的代码,它们最终都要放到内存中才能供 CPU 使用。
数据和代码都以二进制的形式存储在内存中,计算机无法从格式上区分某块内存到底存储的是数据还是代码。当程序被加载到内存后,操作系统会给不同的内存块指定不同的权限,拥有读取和执行权限的内存块就是代码,而拥有读取和写入权限(也可能只有读取权限)的内存块就是数据。
CPU 只能通过地址来取得内存中的代码和数据,程序在执行过程中会告知 CPU 要执行的代码以及要读写的数据的地址。如果程序不小心出错,或者开发者有意为之,在 CPU 要写入数据时给它一个代码区域的地址,就会发生内存访问错误。这种内存访问错误会被硬件和操作系统拦截,强制程序崩溃,程序员没有挽救的机会。编译和链接过程的一项重要任务就是找到变量和函数名所对应的地址
指针变量
如下例子:a为正常变量,p为指针变量,p指向了100的地址
int a = 100;
int *p = &a;
获取指针的中的值,使用如下方式*p
#include <stdio.h>
int main(){
int a = 10;
int *p = &a;
printf("%d, %d\n", a, *p);
return 0;
}
两种方式都可以输出a的值
指针除了可以获取内存上的数据,也可以修改内存上的数据
#include <stdio.h>
int main(){
int a = 15, b = 99, c = 222;
int *p = &a; //定义指针变量
*p = b; //通过指针变量修改内存上的数据
c = *p; //通过指针变量获取内存上的数据
printf("%d, %d, %d, %d\n", a, b, c, *p);
return 0;
}
结果输出:99,99,,99,99
* 和 &的用法
&a可以理解为(&a),&a表示取变量 a 的地址(等价于 pa),(&a)表示取这个地址上的数据(等价于 pa),绕来绕去,又回到了原点,*&a仍然等价于 a。
&pa可以理解为&(pa),pa表示取得 pa 指向的数据(等价于 a),&(pa)表示数据的地址(等价于 &a),所以&*pa等价于 pa。
指针变量的运算
根据数据类型对指针进行增加,如下面运行代码
#include <stdio.h>
int main(){
char a = 15;
char *pa = &a;
int b = 55;
int *pb = &b;
double c = 11;
double *pc = &c;
printf("%#X,%#X,%#X\n" , pa, pb,pc);
printf("%d,%d,%d\n", *pa, *pb,c);
pa++;
pb++;
pc++;
printf("%#X,%#X,%#X\n" , pa, pb,pc);
return 0;
}
返回结果,
0X240FF27,0X240FF1C,0X240FF10
15,55,0
0X240FF28,0X240FF20,0X240FF18
0X240FF27到0X240FF28 char类型后移位
0X240FF1C到0X240FF20 int类型后移动4位
0X240FF10到0X240FF18 double类型后移8位
以 a 和 pa 为例,a 的类型为 int,占用 4 个字节,pa 是指向 a 的指针,如下图所示: