❤博主CSDN:啊苏要学习
▶专栏分类:C语言◀
C语言的学习,是为我们今后学习其它语言打好基础,C生万物!
开始我们的C语言之旅吧!✈
目录
前言:
一.字符指针
二.指针数组
三.数组指针
四.数组、指针参数
4.1一维数组传参
编辑4.2二维数组传参
编辑4.3一级指针传参
4.4二级指针传参
五.函数指针
六.类型重定义
“爷爷,爷爷!你关注的啊苏博主终于更新啦!”,博主六月中旬在忙期末复习,七月在搞军训,兜兜转转,落下了两个月。
现在要快马加鞭学习总结知识啦!今天总结的知识是指针进阶,干货满满,希望大家喜欢。
在指针初阶的文章里面,我们已经初步认识指针是存放地址的变量,然后通过解引用操作,可以找到对应空间里的值。
字符指针是存放字符变量地址的变量,比如:
我们知道对字符数组有两种初始化方式,请看:
arr1数组名本质是首字符'h'的地址,那么同为字符数组的arr2,也应该表示首元素的地址,这样得出一个结论:
字符串"helloworld"实际上表示'h'的地址;
既然字符串是字符的地址,那就可以用字符指针管理字符串:
讲到这里,大家对字符指针有更进一步的认识了,接下来补充一个点:
改变数组的首字符'h'是没问题的,改变字符指针的就出问题了,原因是:
数组通过字符串的形式初始化,数组里的内容可以改,而字符指针管理的字符串,是一个常量字符串,不能被修改。
指针数组,存放指针的数组。我们使用指针数组来模拟实现一下二维数组:
int main()
{
int arr1[] = {1,2,3,4,5};
int arr2[] = {6,7,8,9,10};
int arr3[] = {11,12,13,14,15};
//arr1、arr2、arr3是1 6 11的地址
//整型的地址要放到整型指针中
int* arr[] = {arr1, arr2, arr3};
return 0;
}
arr有三个元素,每一个元素是一个一维数组的起始地址。arr[0]是第一个元素,相当于arr1。
假如我们要访问arr1中5个元素,我们可以直接用arr1[i],i从0—4增长;也可以像二维数组arr[0][i]这样访问。
学习指针数组,让我们对指针和数组的关系更加清晰,这里希望读者能明白什么是指针数组,简而言之就是存放指针的数组。
数组指针是指向数组的指针,这个指针存放的是数组的地址。大家先分析两句代码分别是什么意思:
int main()
{
int *pa[10];
int(*pa)[10];
return 0;
}
第一句代码:int * pa[10]是一个指针数组,pa先和[10]结合,pa是一个数组,数组的每个元素是int*。
第二句代码:int(*pa)[10]是一个数组指针,pa和*括起来,先成为一个指针,指向int[10]这个存放十个整型的数组。
我们先来看一个代码:
这种方式非常麻烦,直接用arr就可以了,根本不需要把数组的地址给数组指针,解引用找到数组,数组再解引用找到数据。
一句话,上面是脱裤子放屁。数组指针用在二维数组里:
总结:二维数组的数组名是一维数组的地址,解引用一层,得到一维数组的数组名,是数据的地址,再解引用一层,得到数据。
在使用库函数或者是自定义函数时,常常需要传递实参,形参要接收。
不论是给了实参写形参,还是根据形参写实参,都需要遵循类型匹配的原则,这样才不会出错。
函数在调用的时候,也会开辟栈空间,相应的也会有地址,那么存放函数地址的指针就叫做函数指针。
不难看出,pf是一个指向Add函数的指针,解引用的*实际上是摆设,可以不加,但是如果加上,一定要括号括起来(*pf)。
否则,执行的逻辑就是,pf(3,5)调用返回8这个值,然后对8解引用,这是错误的。
接下来看看这两个代码分别表示什么意思:
(* (void(*)()) 0)();
这句代码是什么意思呢?咋一看,跟没看差不多,完全不知所语,博主一开始也是一样~
0本来是一个整型,使用C语言中的强制类型转换,把0转换为一个函数的地址,这个函数没有参数、没有返回值。
然后使用解引用的方式调用这个函数,所以这句代码的本质是一次调用以0为地址处的函数。
void(*signal(int, void(*)(int)))(int);
这句代码的本质是一句函数声明,我们来分析一下:
signal先和括号结合,说明是一个函数,参数是int,和以int为参数,返回类型为空的函数指针;
去掉函数名和参数部分,剩下的就是函数的返回类型,也是一个函数指针。
相信读者已经懂为什么这是一个函数声明的原因了,我们想了想,这种代码可读性那么差,真实不方便!于是:
在初始C语言中,typdef能将类型重新定义,以至于不会让代码看起来冗长,难以理解,函数指针也是类型,也可以重定义。
int main()
{
typdef unsigned int u_int;
typdef int* ptr_t;
//数组指针类型这样重定义可行吗?
typdef int(*)[10] parr_t;
typdef int(*)(int, int) pf_t;
//更改
typdef int(*parr_t)[10];
typdef int(*pf_t)(int, int);
return 0;
}
前面我们创建一个数组指针和函数指针的书写的时候,先是(),里面放*和一个变量名确保变量是一个指针。
在类型重定义的时候也是一样,要把重新定义的名字放在(*)里面,更改后的写法才是正确的。这样再对前面第二段代码进行简化。
int main()
{
//重定义参数为int,返回类型为空的函数指针类型
typdef void(*pf_t)(int);
void(*signal(int, void(*)(int)))(int);
//简化
pf_t signal(int, pf_t);
return 0;
}
简化后是多么令人心情愉悦啊。
好的,这篇文章内容也差不多了,还有一部分的讲解我们留给下一篇,如果你喜欢,可以留个大拇指噢~
结语:希望读者读完有所收获!在学C的路上,祝福我们能越来越C!✔
读者对本文不理解的地方,或是发现文章在内容上有误等,请在下方评论区留言告诉博主哟~,也可以对博主提出一些文章改进的建议,感激不尽!最后的最后!
❤求点赞,求关注,你的点赞是我更新的动力,一起努力进步吧。