深入理解指针(一)
1.内存和地址
2.指针变量和地址
3.指针变量类型的意义
4.指针运算
1. 内存和地址
1.1 内存
在讲内存和地址之前,为了大家更好的理解举了这么个例子:
假如有一栋教学楼,刚好你今天在这栋楼的某一个课室上课,已知这栋楼有50个课室,但是没有编号,你的舍友来找你拿宿舍门钥匙, 如果想找到你,就得挨个教室去找,这样效率很低,但是我们如果根据楼层和楼层的教室的情况,给每个房间编上号,如:
一楼:101,102,103......
二楼:201,202,203......
. . . . . . . . . . . . . . . . . .
有了教室号,你的舍友知道你在那一间教室上课,就可以快速的找到你且拿到宿舍钥匙。生活中,给每个房间编写编号,就能提高效率,能快速地找到你想要找的房间位置。
如果把上面的例子对照到计算机中,又是怎么样呢? 我们知道计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,那我们买电脑的时候,电脑上内存是 8GB/16GB/32GB 等,那这些内存空间如 何⾼效的管理呢? 其实也是把内存划分为⼀个个的内存单元,每个内存单元的大小取1个字节。 计算机中常见的单位(补充): ⼀个比特位可以存储⼀个2进制的位1或者0
内存单位:
- bit - 比特位
- Byte - 字节
- KB
- MB
- GB
- TB
- PB
- 1Byte = 8bit
- 1KB = 1024Byte
- 1MB = 1024KB
- 1GB = 1024MB
- 1TB = 1024GB
- 1PB = 1024TB
其中,每个内存单元,相当于⼀个教室,⼀个字节空间里面能放 8个比特位,就好比同学们住的八人间,每个人是⼀个比特位。 每个内存单元也都有⼀个编号(这个编号就相当于宿舍房间的门牌号),有了这个内存单元的编号,CPU就可以快速找到⼀个内存空间。生活中我们把门牌号也叫地址,在计算机中我们 把内存单元的编号也称为地址。C语言中给 地址起了新的名字叫: 指针。 所以我们可以理解为: 内存单元的编号 == 地址 == 指针
首先,必须理解,计算机内是有很多的硬件单 元,而硬件单元是要互相协同工作的。所谓的协同,至少相互之间要能够进行数据传递。但是硬件与硬件之间是互相独立的,那么如何通信呢?答案很简单,用"线"连起来。而CPU和内存之间也是有⼤量的数据交互的,所以,两者必须也用线连起来。不过,我们今天关心一组线,叫做地址总线。CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,而因为内存中字节很多,所以需要给内存进行编址(就如同宿舍很 多,需要给宿舍编号⼀样)。 计算机中的编址,并不是把每个字节的地址记录下来,而是通过硬件设计完成的。钢琴、吉他 上面没有写上“剁、来、咪、发唆、拉、西”这样的信息,但演奏者照样能够准 确找到每⼀个琴弦的每⼀个位置,这是为何?因为制造商已经在乐器硬件层面上设计好了,并且 所有的演奏者都知道。本质是⼀种约定出来的共识
2. 指针变量和地址
2.1 取地址操作符(&)
理解了内存和地址的关系,我们再回到C语言,在C语言中创建变量其实就是向内存申请空间,比如:
#include <stdio.h> 1
int main()
{int a = 10;return 0;
}

- 0x00EEFAE4 0a
- 0x00EEFAE5 00
- 0x00EEFAE6 00
- 0x00EEFAE7 00
#include <stdio.h>
int main()
{int a = 10;&a;//取出a的地址printf("%p\n", &a);return 0;
}
按照我画图的例子,会打印处理:006FFD70 &a取出的是a所占4个字节中地址较小的字节的地址。虽然整型变量占用4个字节,我们只要知道了第⼀个字节地址,顺藤摸瓜访问到4个字节的数据也是可行的。
2.2 指针变量和解引用操作符(*)
#include <stdio.h>
int main()
{int a = 10;int* pa = &a;//取出a的地址并存储到指针变量pa中return 0;
}
int a = 10;
int * pa = &a;
char ch = 'w';
pc = &ch;//pc 的类型怎么写呢?
#include <stdio.h>
int main()
{int a = 100;int* pa = &a;*pa = 0;return 0;
}
2.3 指针变量的大小
前面的内容我们了解到,32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产生的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4 个字节才能存储。 如果指针变量是用来存放地址的,那么指针变量的大小8就得是4个字节的空间才可以 同理64位机器,假设有64根地址线,⼀个地址就是64个⼆进制位组成的⼆进制序列,存储起来就需要8个字节的空间,指针变量的大小就是8个字节。
#include <stdio.h>
//指针变量的⼤⼩取决于地址的⼤⼩
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)
int main()
{printf("%zd\n", sizeof(char*));printf("%zd\n", sizeof(short*));printf("%zd\n", sizeof(int*));printf("%zd\n", sizeof(double*));return 0;
}
32位平台下地址是32个bit位(即4个字节):
64位平台下地址是64个bit位(即8个字节):
3. 指针变量类型的意义
//代码1
#include <stdio.h>
int main()
{int n = 0x11223344;int* pi = &n;*pi = 0;return 0;
}
代码2:
#include <stdio.h>
int main()
{int n = 0x11223344;char* pc = (char*)&n;*pc = 0;return 0;
}
3.2 指针+-整数
#include <stdio.h>
int main()
{int n = 10;char* pc = (char*)&n;int* pi = &n;printf("%p\n", &n);printf("%p\n", pc);printf("%p\n", pc + 1);printf("%p\n", pi);printf("%p\n", pi + 1);return 0;
}
运行结果:
#include <stdio.h>
int main()
{int a = 10;int* pa = &a;char* pc = &a;return 0;
}

4. 指针运算
- int arr[10] = {1,2,3,4,5,6,7,8,9,10};
代码:
#include <stdio.h>
//指针+- 整数
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = &arr[0];int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);for (i = 0; i < sz; i++){printf("%d ", *(p + i));//p+i 这⾥就是指针+整数}return 0;
}
运行效果:
代码 :
#include <stdio.h>
int my_strlen(char* s)
{char* p = s;while (*p != '\0') //判断没有'\0';p++;return p - s;
}
int main()
{printf("%d\n", my_strlen("abcdef"));//存在'\0'有7个字符。return 0;
}
运行效果:
4.3 指针的关系运算
代码:
//指针的关系运算
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = &arr[0];int sz = sizeof(arr) / sizeof(arr[0]);while (p < arr + sz) //指针的⼤⼩⽐较{printf("%d ", *p);p++;}return 0;
}
运行效果:
本章学习就到这啦!如果内容对你有用 ,请不忘三连支持一波!!!!
完。