C语言 - 指针 | 多级指针 | 指针作参
指针
1 - 字节是最⼩的存储单元,为了正确访问内存单元系统会使每个内存单元都有一个编号,这个编号称作地址。指针就是内存地址,习惯上把内存地址叫做指针。存放内存地址的变量称为指针变量。指针变量所占的字节数跟指针变量的类型无关,它是跟系统位数有关:32 位下占 4 字节;64 位下占 8 字节
注:指针变量只有加减运算并且在运算时指针类型决定着指针变量所移动的字节数
2 - 如果出现 * 的地方前面有类型修饰符,此时 * 仅仅是修饰作用,告诉编译器:老子是一个指针;如果出现 * 的地方前面没有类型修饰符,此时 * 代表取值操作符,会把指针指向区域中的内容取出来
int a = 10; // 这是一个变量 int *p; // 这是一个指针 *p; // 取值:访问指针变量 p 指向的存储空间 p = &a; // 指针变量 p 指向了变量 a 的地址 *p = 20; // 使用指针修改变量 a 的值
3 - 代码示例
① 交换两个变量的值:指针用作参数
1 #include <stdio.h> 2 void change(int *a,int *b){ 3 4 int temp = 0; 5 temp = *a; 6 *a = *b; 7 *b = temp; 8 } 9 10 int main(int argc, const char * argv[]) { 11 12 int a = 100; 13 int b = 200; 14 printf("交换前:\na = %d b = %d\n", a,b); 15 change(&a, &b); 16 printf("交换后:\na = %d b = %d\n", a,b); 17 18 return 0; 19 }
② 使用指针可以实现让一个函数处理多个值。如下函数不仅返回了两数之和,还能够得到两数之差
1 #include <stdio.h> 2 3 int SumAndMinus(int n1,int n2,int *n3){ 4 5 *n3 = n1-n2; 6 return n1+n2; 7 } 8 9 int main(int argc, const char *argv[]) { 10 11 int a = 10; 12 int b = 11; 13 int sum; // 和 14 int minus;// 差 15 16 sum = SumAndMinus(a,b,&minus);// 把地址作为参数传出 17 printf("和 = %d,差 = %d\n",sum,minus); 18 19 return 0; 20 }
4 - 指针变量只能存储地址,而不是具体值
int *p2; p2 = 200;// 错误
5 - 野指针:指针变量未经初始化就不要拿来间接访问它的存储空间
int *p3; // 未初始化的指针 printf("%p\n",*p3);// crash
int *p1;// 你当然可以这样搞,不过很危险 int d = 10.0; p1 = &d; // 改正 int *p1 = &d;
int d = 10; int *p4 = &d;// &*p 和 &d 等价; *&d 和 d 等价
多级指针
1 - 其实就是指向指针的指针的指针的指针......
① 先看一段代码
int a = 10; int *p = &a; // 一级指针:p 就是个指针 int **p1 = &p; // 二级指针:p1 是指向 p 指针的指针 int ***p2 = &p1;// 三级指针:p2 是指向 p1 指针的指针
说明:*p 访问 a; *p1 访问 p; *p2 访问 p1
② * p1 相当于访问指针变量 p,而 ** p1 相当于访问 a
** p2 相当于访问指针变量 p,而 *** p2 相当于访问 a
注:n 级指针需要 n 个 * 才能访问到最终的内存地址
③ int **p 可以把它分为两部分看:int* 和 *p。 *p 中的 * 表示 p 是一个指针变量,int* 表示指针变量 p 只能存放 int* 型变量地址
对于二级指针甚至多级指针都可以把它拆成两部分,不论它是几级指针它实质上就是一个指针变量,指针变量就是一个 *,其余的 * 表示的是这个指针变量只能存放什么类型变量的地址。比如 int ****a 表示指针变量 a 只能存放 int*** 型变量地址
值传递 | 地址传递
1 - 代码示例
1 #include <stdio.h> 2 3 // 值传递 4 void newValue(int a){ 5 6 a++;// 形参发生变化 7 } 8 9 // 地址传递 10 void test_str(char s[]){ 11 12 s[0] ='w';// 形参指向的是实参的地址 13 } 14 15 int main(int argc, const char * argv[]) { 16 17 int x = 555; 18 newValue(x); 19 printf("%d\n",x);// 555 实参不会发生变化 20 21 char c[] = "me"; 22 test_str(c);// 传入地址 23 printf("%s\n",c);// we 实参发生变化 24 25 return 0; 26 }
指针类型
1 - 任何类型的指针都只和系统位数有关,那么为什么还要为指针加上类型呢。对下面一段代码进行内存分析就可以大致了解到因指针类型不正确而带来的严重后果
1 int i = 2; 2 char c = 1; 3 int *p = &c;// int 型指针指向 char 型变量地址 4 printf("%d\n",*p); // 513 5 printf("%d\n",c); // 1
指针 p 访问的本应该是 1 个字节空间的数据,但因指针类型是 int,所以程序自然地从指向地址 0x0a 开始读取 4 个字节的数据,访问的数据从 1 变成了 513
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)