文章目录
- 一,指针的回忆杀
- 1,指针的概念
- 2,指针的声明和赋值
- 3,指针的使用
- 3.1 直接给指针变量赋值
- 3.2 通过*运算符读写指针指向的内存
- 3.2.1 读
- 3.2.2 写
- 二,二级指针详解
- 1,定义
- 2,示例说明
- 3,二级指针与一级指针、普通变量的关系
- 3.1,与一级指针的关系
- 3.2,与普通变量的关系,
- 示例说明
- 4,二级指针的常见用途
- 5,二级指针扩展到多级指针
- 小结
C语言的学习之旅中,二级指针乃至多级指针往往是初学者感到“恶心”却又不得不面对的重要概念。
不过,一旦掌握了它们的精髓,你会发现它们其实并不那么可怕,反而在某些高级应用中显得尤为强大和灵活。
一,指针的回忆杀
1,指针的概念
指针就是内存地址,内存地址指向内存中的一个单元,这个单元就像一个个小房间,里面住着某种数据,可能是整数,可能是浮点数,可能是字符,也可能是另一个指针。
为了方便理解和记忆,可以把指针当作酒店房间号。
指针作为一种特殊的数据,也需要存储在内存中。
2,指针的声明和赋值
C语言通过指针变量为指针开辟一块内存。
int num = 10;
int* p;
p = #
如上代码,定义了指针变量p
,声明变量时如果带有*
号,说明这个变量是指针变量。
这个*
号的作用是告诉编译器,这个指针变量p
要存储的是变量num
的值的内存地址,这个内存地址从形式上看也没什么特别,就是一个整数。
上面的代码中p = #
,通过地址运算符&
取出变量num
的地址,赋给指针变量p
。
3,指针的使用
3.1 直接给指针变量赋值
上面的代码中p = #
所示,可以和普通变量一样,直接给指针变量赋值,只是这个值代表的是内存地址而已。
3.2 通过*运算符读写指针指向的内存
3.2.1 读
我们还可以通过* 运算符操作指针指向的内存中的值。
int num = 10;
int* p;
p = #int num2 = *p;
如上代码最后一行int num2 = *p;
,运算符*
的作用是告诉编译器,找到指针p
指向的地址,从中读取数据。
3.2.2 写
当然,可以修改指针指向的内存中的数据。
int num = 10;
int* p;
p = #*p = 100;
上述代码*p = 100;
,将指针p
指向的内存中数据的值修改为100
。注意,此时num的值也变为100了,原因是修改的就是num
的内存中的值。
二,二级指针详解
1,定义
二级指针,顾名思义,是指向指针的指针,即一个变量,其类型是指向指针的地址。在C语言中,声明一个二级指针的基本形式如下:
数据类型** pointerName;
这里,**pointerName
表示pointerName
是一个指向指针的指针,它存储的是一个指针变量的地址。
int num = 10;
int* p;
p = #int** pp = &p;
如上,二级指针变量pp
指向的是指针变量p
的地址。
如上图所示,发现二级指针需要跳2级才能获取普通变量内存中的值,这也是二级指针名称的来源。
2,示例说明
以一个整型变量为例:
int a = 12;
int *p = &a;
int **pp = &p;
根据上述定义,我们可以得出以下计算结果:
p == &a
*p == 12
pp == &p
*pp == p
**pp == a
**pp
就是获取a
变量的值,因为pp
指向的是p
的地址,而p
指向的又是a
的地址,所以 **pp
就相当于a
。
3,二级指针与一级指针、普通变量的关系
3.1,与一级指针的关系
一级指针存储的是普通变量的地址,而二级指针存储的是一级指针的地址。
通过二级指针,我们可以间接访问到一级指针所指向的数据,实现更深层次的间接访问。
3.2,与普通变量的关系,
普通变量是数据存储的最直接形式,通过一级指针,我们增加了一层间接访问;二级指针则在此基础上再增加一层间接性,使得对普通变量的操作更为灵活。
示例说明
#include <stdio.h>
#include <stdlib.h>int main() {int value = 10;int *p = &value; // 一级指针,指向valueint **pp = &p; // 二级指针,指向一级指针pprintf("Value: %d\n", value); // 直接访问printf("Value via *p: %d\n", *p); // 通过一级指针访问printf("Value via **pp: %d\n", **pp); // 通过二级指针访问return 0;
}
此例中,value
是一个普通整型变量,p
是一级指针指向value
,而pp
作为二级指针,则指向p
。通过**pp
,我们依然能最终访问到value
的值,展示了指针间接访问的层级关系。
4,二级指针的常见用途
- 动态内存管理:在动态分配数组时,可以使用二级指针来存储数组的首地址,便于管理和释放内存。
- 函数参数传递:当希望函数能够修改外部指针变量(而非指针所指向的内容)时,需使用二级指针作为函数参数。
- 指向指针的指针运算:在复杂数据结构操作中,二级指针提供了对指针进行指针运算的能力,如链表的节点交换、树结构的遍历等。
5,二级指针扩展到多级指针
多级指针的概念基于二级指针进一步扩展,即指针的指针的指针……依此类推。
一句话,多级指针存储的是上一级指针的地址。
虽然在日常编程中较为罕见,但在特定场景下,如复杂的内存管理、高度抽象的数据结构设计或底层系统编程中,多级指针可以提供极大的灵活性。
示例:三级指针
#include <stdio.h>void printViaTriplePointer(int ***triplePtr) {printf("Value via ***triplePtr: %d\n", ***triplePtr);
}int main() {int value = 7;int *p = &value;int **pp = &p;int ***triplePtr = &pp;printViaTriplePointer(triplePtr);return 0;
}
这个例子中,triplePtr
是一个三级指针,通过它我们依然能够最终访问到最初定义的value
。虽然看起来繁琐,但在特定逻辑或系统级操作中,这样的间接访问机制可能非常有用。
小结
总之,二级指针乃至多级指针虽初看复杂,实则是C语言中处理复杂数据结构和内存管理的强大工具。通过实践和理解,你将逐步揭开它们的神秘面纱,发现其背后的逻辑之美。