🏆浮世尘弦:个人主页
⭐个人专栏:《C语言》、《数据结构与算法》、《C++》
💎:非淡薄无以明志,非宁静无以致远
文章目录
一,深入理解数组名
二,使用指针访问数组
三,一维数组传参的本质
四,冒泡排序
五,二级指针
六,指针数组
七,字符指针变量
八,数组指针变量
1,定义
2,表示
3,数组指针的初始化
九,二维数组传参的本质
1,剖析二维数组
2,运用展示:
十,函数指针变量
十一,关键字typedef
1,typedef的定义和运用
2,typedef和define的区别
十二,函数指针数组
1,定义
2,运用:
十三,转移表
一,深入理解数组名
1,引出问题
通过上述代码可知arr确实是首元素的地址,但是在sizeof中的arr又表示出了40个字节,这就又表示arr代表的是整个数组,产生了矛盾。
结论:说数组名就是地址是正确的。不过有两个例外:
1.sizeof(arr):此时arr表示的是整个数组的大小
2,&arr,此时代表的是arr整个数组的地址
通过下面的分析:
由上图可知:
arr和&arr[0]都代表着数组首元素的地址,所以他们加1时,地址改变一个整型变量的大小, 但是&arr表示的是整个数组的地址,所以在加1时,直接跳过了40个字节(一个整型占4个字节)。
只是由于&会选取最小的一个进行表示,故&arr可以表示首元素的地址。
二,使用指针访问数组
由arr[i] = *(arr+i)
得:*(i+arr)=i[arr] 注意:i[arr]也可以但是不建议使用,因为会影响代码的可读性。
总结:
1,数组就是数组,是一块连续的空间(大小取决于数组内元素的个数和元素的类型)
2,指针(变量)就是指针(变量),是一个变量(大小为4/8个字节)
3,数组名是地址,是首元素的地址。
4,可以使用指针来访问数组。
三,一维数组传参的本质
总结:1,数组传参时传入的是首元素的地址,产生了传址调用,因此形参和实参是同一个数组,不会创建新的地址。
2,形参的数组是不会再创建地址空间的,所以形参的数组是可以忽略掉数组的大小,写成arr[ ]
3,一维数组传参时,形参可以写成数组形式,也可以写成指针形式。
四,冒泡排序
冒泡排序的核心思想是:对相邻两个元素进行比较,然后进行排序。
分析:对一个数组内的元素进行排序
例如数组内元素为: 10 9 8 7 6 5 4 3 2 1
按照升序的方式排列:1 2 3 4 5 6 7 8 9 10
我们需要先选取10和9两个元素进行比较,在交换两个元素的位置,依次往下进行,当遍历完数组内所有元素后变为9 8 7 6 5 4 3 2 1 10。接着我们需要重复上述过程,总共进行遍历9次,得到升序数组。
代码实现:
五,二级指针
二级指针就是指针变量的地址
结果为:0 //**pp两次解引用为a, *pp一次解引用为p
int*表示pp指向对象的类型,*表示pp为一个指针变量
p+1跳过4个字节(取决于p的类型)pp+1跳过4或8个字节(取决于是x64还是x86)在确定环境下,指针的大小是不变的。
六,指针数组
指针数组的本质是数组,数组内的元素为指针变量。
运用:
七,字符指针变量
两种字符指针:
1,接收数组内容,可变。
2,接收常量字符串内容,不可变。
打印结果:
wbcdef
wbcdef
abcdef
补充:char* ps = "abcdef"可更改为const char* ps = "abcdef",这样出现*ps更改时可以直接拦截,并在编译器中报错。
例题:
输出结果:
not same
same
分析:
srt1和str2是创建的两个不同的数组,虽然内容一样,但是首元素的地址不一样,同时两个都可以进行更改,故不相同。
首先arr1和arr2表示的是首元素的地址,arr1和arr2指向的是同一个字符串常量,这个常量字符串被储存在一个地址中,不可更改。故相同。
八,数组指针变量
1,定义
类比:
整形指针变量:int* print:指针存放的地址是整型变量的地址,能够指向数据。
数组指针变量:本质上是一种指针,存放的是数组的地址(不是数组首元素的地址),能够指向数组。
2,表示
int* p1[10] //指针数组,本质上是数组,数组内存放的是地址
int (*p2)[10] //数组指针,本质上是指针
理解:由于()的优先级比[]高,使得*和p2进行结合。故*p2可以表示指针,去掉(*p2)剩下的部分:int表示指针指向的是一个整形数组类型,[10]数组内储存的元素的个数为10
3,数组指针的初始化
int (*p2) [10] = &arr; //&arr可以表示整个数组的地址。
九,二维数组传参的本质
1,剖析二维数组
二维数组可以看成每个元素都是一个一维数组的数组。
换一种解读:arr[3][5]前面的arr[i]表示的是数组的每一行,后面的[5]表示的是每一行(一维数组)中的各个元素。
可以把每一行当作数组中的每一个元素,我们知道数组在传参时传入的是首元素的地址,又因为二维数组的首元素是一个数组,所以要接收它就要用到数组指针变量int (*p)[10]。
2,运用展示:
分析:形参可以传二维数组arr[3][5],也可以传数组指针int(*p1)[5],本质上都是数组首元素的地址,即第一行的地址。
十,函数指针变量
1,函数的地址
函数是有地址的,函数名就是函数的地址,其次&函数名这种形式也可以表示函数的地址。
如果想要将函数的地址存储起来,并运用的话,就要创建一个指针来接收它,这个指针就是函数指针变量。
类比数组指针引出函数指针:
数组指针:int (*p1)[10]
函数指针 :int (*p2)(int x,int y) =&add
分析:p2中存放的是函数的地址 ,int表示函数的返回类型,(int x,int y)表示函数的参数,可省略为(int,int).&add表示函数的地址,可省略为add.
2,运用
分析:ps和(*ps)都可以表示地址
分析复杂调用:
1,
2,
十一,关键字typedef
1,typedef的定义和运用
typedef的作用是用来重命名的,可以将复杂的类型进行简化。
展示:
2,typedef和define的区别
typedef int* nrt
#define NRT_T int*
nrt p1,p2
p1和p2都是指针变量
NRT_T p3,p4
p3是指针变量,p4是整型变量
原因:替换后 int*p3 p4 故只有p3是指针变量
十二,函数指针数组
1,定义
把一个函数的地址放到数组中,这个数组就叫做函数指针数组。
语法:
int (*parr[4])(int,int) = {add,,sub,mul,div};
parr[4]表示数组,parr是数组名,[4]是数组的个数。
int(*)(int,int)表示是函数指针类型。
{}内的是同类型的不同的函数名。
2,运用:
十三,转移表
模拟实现计算机
主调函数
分析:
让arr[5]数组的首元素为0,第一可以使得arr[input]中的input和数组进行正确匹配。
二是可以补充输入0的情况。
中间调用函数
回调函数
回调函数就是通过函数指针调用的函数。
把一个函数的指针作为参数传递给另一个函数,另一个函数在使用这个指针时所调用的函数就是回调函数。
主调函数把函数的指针传给中间调用函数,中间调用函数利用函数指针找到回调函数,对回调函数进行操作再返回内容到主调函数中。
转移表通过函数指针的方式,实现了对不同函数相似操作,降低了函数一个一个进行相似操作而带来的代码冗余,节省了空间。