师承clc
认识指针
指针==地址
我们访问变量有两种方式:1.变量名直接访问,2.地址间接访问
比如访问女朋友定的酒店:
1.xxx酒店xxx主题房间 --变量名访问
2.福建省鼓楼区xxx路xxx号313房间 --地址访问
![](https://i-blog.csdnimg.cn/blog_migrate/0b022e7191585fde8943ac0e2f4d6874.png)
通过地址也能访问,& 取地址运算符,* 将地址内的值读出运算符
![](https://i-blog.csdnimg.cn/blog_migrate/7a7edf4d9bf5074ae5cc0eea67b9ad50.png)
指针变量==存放地址的变量
如何定义一个指针变量
![](https://i-blog.csdnimg.cn/blog_migrate/21a76399161c0b99df5af3bd9dc544ae.png)
*的标识的作用,只产生在指针变量定义或声明的时候
如何使用一个指针变量
*的运算运用,如上图代码的*p,*(&a)
访问变量的两种方式
![](https://i-blog.csdnimg.cn/blog_migrate/614ec30d1ceadb2b209aa3d9ac3419d6.png)
所谓的间接防访问的方式就是用指针的方式。
区分指针类型
指针是存放地址的变量,但是不同类型的指针
指向空间的大小是不一样的,有可能会造成取值的问题丢失数据。
指针的增量也可能会不同
int *a 和char *b在 a++和 b++时他们的地址增量是不同的
![](https://i-blog.csdnimg.cn/blog_migrate/c3b7ab99e059f3a431abc1d320ffa58a.png)
为什么要用指针
我们来举个很简单的例子,实现一个封装函数,实现两个数的交换
有不同的两份代码,我们来看一下
![](https://i-blog.csdnimg.cn/blog_migrate/f5223b13bdc94fd6e0b5eaaedd8d5338.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7b0f964a332336f795bf4815e71f6f42.png)
运行后,我们可以发现,只有用了间接访问把地址传给函数的第二份代码,运行的结果才是正确的,在第一份代码里,调用changeData(data,data2),实际上函数是进行了值拷贝,虽然函数里的data和main函数里的data看起来一样,但是他们的地址是不同的,只有把他们的地址进行交换,才是真正进行了数据交换。
2.在单片机,armbootloader的开发当中,我们经常需要指针指向固定的地址。
![](https://i-blog.csdnimg.cn/blog_migrate/0d497bd834b2ec669ed13f0ae5d706f1.png)
练习
输入三个数a,b,c; 要求不管怎么输入,在输出的时候,a,b,c就是由大到小的顺序输出,用函数封装实现
![](https://i-blog.csdnimg.cn/blog_migrate/383d6a2616561827190131280fb9e29e.png)
通过指针 引用数组
定义一个指针变量指向数组
![](https://i-blog.csdnimg.cn/blog_migrate/6dd4cd7c1e23c739b2206f68f0d20707.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c1ff1a8141000ab20f9b572464202261.png)
int *p;
p = a = &a[0];
指针增量和数组的关系
![](https://i-blog.csdnimg.cn/blog_migrate/1b06f1b6818788f835a73b19149d4d47.png)
通过指针引用数组元素
![](https://i-blog.csdnimg.cn/blog_migrate/962b7153ce712389ee6b9ebcd5a754e8.png)
注意:p要指回首地址,p = arr;
访问数组元素
下标法a[0],a[1]
指针法
![](https://i-blog.csdnimg.cn/blog_migrate/3f8e762fd8aa7b95f055b35560a7d5f0.png)
偏移
取内容
见怪不怪:
1.指针当做数组名,下标法访问
2.数组名拿来加
数组名和指针的区别:
a++可否?:
常量指针 -- 数组名 ,不能改变首地址的位置,
arr++ 即 arr = arr+1 改变了首地址的位置
指针变量 -- *p
sizeof的时候
![](https://i-blog.csdnimg.cn/blog_migrate/0ec2f5b394f7051529c44f2985880b4b.png)
两种方法效率对比
![](https://i-blog.csdnimg.cn/blog_migrate/095be8d4622c867d4f92c8cf07a96512.png)
练习
函数封装数组初始化,遍历
![](https://i-blog.csdnimg.cn/blog_migrate/d3f71f234f020bf41fb983135fca75e2.png)
将数组中的n个元素按逆序存放
![](https://i-blog.csdnimg.cn/blog_migrate/a48fc6c8fba98b117c42a414f0406113.png)
指针和二维数组
概念
二维数组中上官特有说法:父子数组为了研究清楚地址的概念,把二维回归到一维数组
![](https://i-blog.csdnimg.cn/blog_migrate/55a5bf85cafc0e89d04812b30ab96cc2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a4e3f4b0b722b07159afcbdc4fba90b9.png)
a[1] == &a[1][0];//
a[1]不是元素而是数组名,是子首地址。
a表示二维数组(父数组)的地址
a[0] , *a 表示子数组的地址
那么a[0]+1又是什么意思呢
![](https://i-blog.csdnimg.cn/blog_migrate/405bd3e4dd892f51c22eb9b9c955251e.png)
//在二维数组里
arr[0] == *(arr+0);
arr[0]+1 == *(arr+0)+1;
![](https://i-blog.csdnimg.cn/blog_migrate/da59489cf4dc9c193928d49f8fd08bb2.png)
a[0]+1第0行第一列的地址,是地址的意思 == *(a+0)+1
也可以说是第0个子数组的第1个元素的地址
而第0个子数组的第1个元素表示方式是a[0][1],不要乱
提示
![](https://i-blog.csdnimg.cn/blog_migrate/a73d4cbc8c65558c306ff37a6ba6e19d.png)
进阶
![](https://i-blog.csdnimg.cn/blog_migrate/64aef682dce4a011176c68166ef6a8f2.png)
思考
![](https://i-blog.csdnimg.cn/blog_migrate/c8067b6bb551138172a514a4ee51724a.png)
解答:它们只是值相等,但类型不相等,a+1是int **类型,指向的是数组a的第二行的首地址; *(a+1)是int *型,指向的是数组a的第二行第一个元素的地址。
小总结,嵌入式笔试题可能考
![](https://i-blog.csdnimg.cn/blog_migrate/ba2158d0d06a168efd90128c8445be29.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f15baf1231709db3584921a32b14ba62.png)
数组指针
指向数组的指针 int(*p)[5]
指向一个含有4个元素的数组:
![](https://i-blog.csdnimg.cn/blog_migrate/91e59b54cfb027f1591b13888fec4422.png)
输出二维数组任意行列的数:
![](https://i-blog.csdnimg.cn/blog_migrate/917e6233cdac570248eb4ff543fb4564.png)
函数指针
定义“函数地址”
![](https://i-blog.csdnimg.cn/blog_migrate/8021440aa1948fed62cfbaa6ccd1bb65.png)
函数名就是地址 --类似--数组名就是地址
如何定义一个函数指针变量
跟普通变量一样
int getData(int a, int b);
int (*p)(int a,int b)
使用函数指针
函数调用概念和变量一样
![](https://i-blog.csdnimg.cn/blog_migrate/147dd747d594cd889ac75ad2230a9716.png)
![](https://i-blog.csdnimg.cn/blog_migrate/467a263c46a7b6dc3ec2bdc8bea42c8a.png)
好用之处
根据程序运行过程的不同情况,调用不同的函数
java接口
回调函数的底层逻辑
线程
int pthread_create(pthread_t *id,const pthread_attr_t *attr, void*(*start_rtn)(void*), void *restrict arg);
QT的信号与槽
练习
![](https://i-blog.csdnimg.cn/blog_migrate/c990535210edc7395beb1b7eb40c6e17.png)
![](https://i-blog.csdnimg.cn/blog_migrate/90901dde098e9721fcc7828f8c02c702.png)
指针数组
概念
定义,注意和数组指针的区别,面试的笔试题会考
![](https://i-blog.csdnimg.cn/blog_migrate/49befcd252d3575dcf385004939f6a45.png)
![](https://i-blog.csdnimg.cn/blog_migrate/376c52b76fe1e9fc9409d2c50a697f02.png)
它是数组,数组的每一项都是一个指针变量
![](https://i-blog.csdnimg.cn/blog_migrate/e3a3fec9ece17f5de0c882418ccd0bfa.png)
指针函数--返回指针值的函数
概念
![](https://i-blog.csdnimg.cn/blog_migrate/8ef6ab4f4ca8e5c1ae9775e72a522c14.png)
练习
![](https://i-blog.csdnimg.cn/blog_migrate/2421bea08c2971ae6e197ae997d7e220.png)
![](https://i-blog.csdnimg.cn/blog_migrate/838638762401f8a2ab22c0bd95181755.png)
二级(多级)指针
认知考虑的时候,其实所有东西跟一级指针一样,写法int **p
差别就是保存的是指针变量的地址
![](https://i-blog.csdnimg.cn/blog_migrate/20c95a26648cb5c215887a21b66070fc.png)
当你通过函数调用来修改调用函数指针指向的时候,就像通过函数调用修改某变量的值的时候一样
![](https://i-blog.csdnimg.cn/blog_migrate/e88a76b1012ac52efdffde76b880a5fc.png)
二级指针不能简单粗暴指向二维数组
![](https://i-blog.csdnimg.cn/blog_migrate/446b38e9a3ae5b1e234a892cba486650.png)
总结
![](https://i-blog.csdnimg.cn/blog_migrate/837b9b1d6fadd0526f83cce4c584ca99.png)
后面还会更新结构体指针等等。。。。。。。