深入理解C语言指针(一):内存、地址与传址调用

深入理解C语言指针(一):内存、地址与传址调用
Lichermione深入理解C语言指针(一):内存、地址与传址调用
1. 内存与地址
内存可以看成由连续字节组成的空间,每个字节都有唯一地址。常见单位:
1 | 1 Byte = 8 bit |
变量占用若干连续字节,取地址操作符 & 可以获得其首地址。
1 | int value = 10; |
2. 指针变量
指针变量专门用于保存地址:
1 | int value = 10; |
p:保存地址;&value:取得value的地址;*p:访问该地址处的int对象,也称解引用。
3. 指针类型的意义
指针类型决定两件事:
- 解引用时按什么类型解释内存;
- 指针加减时一次跨过多少字节。
1 | int arr[3] = {10, 20, 30}; |
p + 1 前进 sizeof(int) 字节,而不是只前进1字节。
4. const修饰指针
4.1 指向常量的指针
1 | const int *p = &value; |
不能通过 p 修改对象,但 p 可以改为指向其他对象。
4.2 常量指针
1 | int *const p = &value; |
p 保存的地址不能改变,但可以通过 p 修改对象。
4.3 指向常量的常量指针
1 | const int *const p = &value; |
地址和指向的数据都不能通过 p 修改。
5. 指针运算
合法且常见的运算包括:
- 指针加减整数;
- 同一数组内两个指针相减;
- 同一数组范围内比较指针;
- 解引用和下标访问。
两个指针相减得到相隔的元素数量,结果类型为 ptrdiff_t。不要对互不相关的对象进行指针减法或大小比较。
6. 野指针与空指针
野指针指向无效或未知位置,常见来源:
- 指针未初始化;
- 指向的局部变量已经离开作用域;
- 动态内存释放后仍继续使用;
- 指针越过合法数组范围后被解引用。
1 | int *p = NULL; |
初始化为空指针不能自动保证安全,但能使状态明确、便于判断。
7. assert断言
1 |
|
断言用于检查程序内部“不应被破坏”的前置条件。发布模式下可能因 NDEBUG 被移除,因此不能用断言代替用户输入校验和正常错误处理。
8. 传址调用
C语言所有参数都是按值传递。所谓传址,是把地址值复制给形参,通过这个地址间接修改原对象。
1 | void swap(int *a, int *b) |
9. 总结
指针就是“带有类型信息的地址”。理解指针时始终回答三个问题:它保存了谁的地址、指向的对象是否仍有效、解引用时应按什么类型读取。