C语言学习记录230703~230708合集

        连续好几天没更新总结,我心难安啊!主要原因是最近这几天的本职工作压力非常大,工作的事情已经把我的精力耗费的一干二净了,实在没有精力再去写总结。不过虽然断更了这么几天,但我每天的课程还是坚持上,每天该敲的代码还是努力再敲,因为考虑到写总结其实完全可以几天一结,所以选择了先放一下,今天实际上实际也不算很充裕,但已经积累了好几天的内容,想着今天还是能在有限的时间里能讲一点是一点。

        这几天上课的内容其实仍然没有脱离前一篇总结,主要是对指针学习的延续,包含了数组的传参、一级、二级指针的传参,函数指针,函数指针数组,函数指针数组的数组指针,回调函数等等,最早跟着在Mooc上翁恺老师的课,上完了以后也没发现有那么多花样,这次学习以后真的是大开眼界,没想到能弄得那么复杂,接下来依次介绍吧。

        (一)数组的传参

                传参嘛,自然是把实参的值复制给函数的形参去,那数组是如何实现传参的呢?我们接下来会把一维数组和二维数组分开讨论,更多维的数组就不考虑了,其实如果能够理解二维数组,理解更多维的数组也就不在话下了。我们接下来的讲解会围绕下面定义的数组来讲解:

int num1[20];
int num2[4][5];

                ①一维数组

                        想要搞清楚数组的传参,我们首先要搞清楚,我们传给形参的实参是什么,我们传递给函数一个数组,并希望函数能够调用,那么我们一般会将数组的地址传送过去,这里的地址会分为两种情况,第一种情况是函数某个元素的地址,一般来说是首个元素的地址,而首个元素地址就是数组名,当然,也可以是用下标运算符后再用取地址运算符取用,形式大致如下:

num1
&num1[0]

                         这两种方式都能将数组的某个元素地址传送过去,但这个地址代表的其实是数组的某个元素地址,当函数内调用这个数组时,实际上是通过某个元素的地址,应用数组的数量和数组元素类型实现对数组各个元素的访问。

                        第二种情况是我们可以传入函数一个数组指针,这种情况下,我们传递给函数的就是一个数组指针,当函数内想要访问数组某个元素时,需要先对数组的地址使用间接寻址运算符,实现对这个数组的访问,然后再用下标或者正常的方式来对数组的各个元素进行访问。那么按照这种方式,我们的实参形式如下:

&num1

                        上述两种实参的形式都能让我们把数组传送到函数内,并让函数正常调用。这些实参的方式只是通常的方式,还有其他一些特殊的方式,这里就不讲解了,接下来我们看看形参那一侧,形参如何接受这些实参数据。

                        我们知道第一种方式传入的是数组内某个元素的指针,那实际上是不是指的就是一个指针呢?所以按照第一种方式,假定一个test函数, 形参可以用下面多种方式表达:

void test(int *num1);
void test(int  num1[]);
void test(int  num1[20]);

                        那参照第二种方式呢?第二种方式传入函数的是数组指针,所以会略显麻烦,结果如下: 

void test(int (*num1)[20]);

                        上面两种方式,传入到函数中,应用上也会略有不同。

                ②二维数组

                        跟一维数组一样,二维数组也有不止一种的情况,我们传递二维数组前,我们首先要搞清楚二维数组里到底有什么东西,二维数组可以按下面的说法理解,二维数组的第一个维度里保存了多个指针,每个指针指向的是一个数组。如果用矩阵的思维考虑,那么二维数组第一个下标代表的就是这个矩阵有多少行,第二个下标代表每一行有多少列。并且二维数组内所有元素在内存内是连续存放的。

                        那我们传递一个二维数组数组,并想要调用它,其实也不难,我们如果按一维数组的思路,我们可以只传递某个元素的地址,然后利用数组的元素数量及元素类型来实现访问整个数组,我们也可以传递进去一个指针数组,每个指针指向一个数组;当然我们也可以传递进去一个数组指针,这个数组指针指向这个数组。通常来说,我们就会直接传入一个num2,这个num2代表的是这个二维数组首元素的地址,而对二维数组而言首元素地址代表的实际上是第一行的地址,也就是数组指针。以这个思路为例,我们形参就可以写成下面的方式,下面第三种方式是最能反应num2本质的,同时因为num2代表的是首个元素,首个元素内是数组指针,所以就不能用用二级指针作为形参,因为实际传进去的是一个数组指针。

void test(int num2[][5]);
void test(int num2[4][5]);
void test(int (*num2)[5]);

                ③一级、二级指针传参

                        一级、二级指针的传参相对数组的传参就简单了很多,如果上面第一第二条能搞明白,一级二级指针的传参自然不在话下,所以这里就不讨论了。

        (二)函数指针、函数指针数组、指向函数指针数组的数组指针

                ①函数指针

                        很容易也能想到,这是一个指向函数的指针,这个指针如何表示呢?其实声明这样一个函数指针,情况跟声明一个数组指针略微有些类似,假设有下面这样一个函数声明:

int test(int x,int y);

                        当我们要声明一个指针变量指向这个函数时,我们就跟声明一个指针变量指向整个数组是一样的,我们将这个test用指针替代,假设我们声明一个指针变量p用于指向这个函数,则声明如下:

int (*p)(int ,int );

                         我们会发现形参可以跟函数原型一样不写,这也同样意味着,如果别的函数返回值类型以及实参类型与该函数一致,我们同样能用这个指针变量去指向那个函数。

                        声明是上面的样子,那如何给这个指针变量赋值呢?我们这里有两种赋值形式,形式如下:

p=test;
p=&test;

                        对函数名取地址和直接拿函数名,效果是一样的,都能给变量p正确赋值。

                       函数指针如何使用呢?同样也有两种形式,我们可以用间接寻址运算符也可以不用,效果如下:

(*p)(x,y);
p(x,y);

                         两者本质上是一样的,当指针变量赋值后,他就能代表对应的函数,也能像使用函数一样去使用它。

                ②函数指针数组

                        不多废话了,直接给出对应数组的声明形式:

int (*p[5])(int ,int );

                        接下来开始拆解解释,首先我们看到星号,而星号与一个数组结合,说明这个数组内每个元素的元素类型是指针变量,而(*p[5])替代的元素是函数名,所以这个指针变量指向的是一个函数,而这个函数的返回值是int,形参是两个int。

                        函数指针数组的作用主要用于转移表,转移表就是当需要根据情况,对输入的数据进行不同的处理时,可以利用函数指针数组去调用不同的函数。

                ③指向函数指针数组的数组指针

                        声明形式如下:

int (*(*p)[5])(int ,int );

                        开始剖析,我们先找到最里面一层的星号,发现他直接跟p结合, 而*p在外一层代表的是一个数组的数组名,所以说明p是一个指向数组的指针,然后我们发现数组外面还有一个*号,(*p)[5]与*号结合,星号说(*p)[5]这一块元素代表的也是指针,而这一块元素是一个数组,那么说明这个数组里的元素都是指针,现在就可以知道,p是一个指针,他指向一个数组,而这个数组内的元素也都是指针,所以p当前是一个指向指针数组的数组指针,(*(*p)[5])在整个声明中替代的是函数名,所以说明这个指针数组内的元素是指向函数的,我们的逻辑思路如下:

1、*p得到p是一个指针变量

2、(*p)[5]告诉我们这是一个数组,所以p指向一个数组

3、*(*p)[5]告诉我们这个数组也是一个指针,换句话说这个数组内的所有元素也是指针,所以p指向了一个元素是指针的数组,而我们目前只知道这个数组元素是指针,我们还需要知道这个指针指向的类型是什么。

4、int (*(*p)[5])(int ,int )告诉我们,(*(*p)[5])替代的是函数名,所以这个数组里的指针指向的是函数,这个函数的返回值为int,形参为两个int。

5、最后我们就可以得到,p是一个元素类型为指向函数的指针数组的数组指针。

                        因为这个数组指针用的地方不是特别多,这里就不再深入讨论下去了,只要知道这是一个指向函数的指针数组的数组指针就行了。

               ④回调函数

                回调函数说起来,其实也很简单,我们为了防止弄混,先假定一个函数1和函数2,如果我们声明一个函数指针变量p,指向了函数2,将p作为实参复制给函数1的形参,最后函数1在自己的程序块内,通过函数指针调用了函数2,那称这种形式调用的函数为回调函数。

                回调函数有很大的作用,这里不便展开,但其实主要目的还是为了能够拥有更好的通用性,具体可以参照标准库函数qsort函数来进行学习。

                

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值