00:00
同学们,我们来看下一个问题,那下一个呢,要给大家讲的是返回指针的函数,也就是说C语言允许函数的返回值是一个指针,或者说是一个地址,那这样的函数呢,我们称之为指针函数。啊,指针函数,那现在呢,我们来看一个小案例,请编写一个函数叫string now,返回两个字符串中较长的这么一个字符串,这太简单了,对不对?你看我我现在在这里呢,同学们看到我在这里有一个字符串数组。这有第二个字符串,字符数组,那么让我输入第一个,输入第二个,这次输入的时候呢,我们用用的是gets,用的是这个函数。用的是gets这个函数没问题,这个函数一样可以接收一个字符串,跟我们原先写的那个SKYF是一个道理。啊,那么得到这两个字符串过呢,我传给了一个函数叫使俊,那它在这里呢?接收大有有发现啊,这里呢,是定义的两个字符指针,那么这个字符指针呢,可以接收我们的这个字符数组的手地址拿到,拿到过后呢,我在这里做了一个判断,非常简单一个判断,如果。
01:19
第一个十寸一的长度大于十寸二的长度,我们就返回十寸一,否则返回十寸二就完事了。对吧,那拿到过后呢,同学们可以看到,呃,最后我们这返回的是个什么呢?就看清楚了,返回的就是我们这一个使STRING1和实STRING2,那实STRING1和STRING2其实就是指针,因此大家可以看到我在这里返回值呢,是是是一个char。信号这个就体现出返回,体现出这个指针就是呃,这个函数,这个函数返回的是char新。啊,恰心其实就是指针嘛。啊,就这么一个题,就这么一个题,好,我们给我们给大家运行一下就可以了,这个题很简单。
02:05
好,我把这个呢注销一下啊,我们来看下面的内容。啊好,我们新建。还是在这里哈,新建一个。稳健。我们写一个叫返回的是一个指针的函数return。Return pointer function问题,Pointer function。然后在这里呢,我们把它的后缀稍微的修改一下,代码都很简单,老师呢,直接给大家做一个解释说明一下就可以了。Include。是吧,Std。L。对。好,因为我们还会用到。一个字符串相关的函数,说把这个引进来,引进来过后呢,我们把这段代码拿过来用一下就可以了,好吧。非常简单。
03:01
那这边咱们就不要一两次了。好,引到这呢,我们这个代码就OK了,那OK,我们来分析一下他应该返回什么,就是呃,我们我们用这个来接收大家看到。是这是一个什么类型啊,是不是这是一个指针呢?使菌是一个指针。是一个指针类型能问题吧,指针类型它指向指向一个字符串,可以这样写吧,它指向一个字符串OK了。那同学们,现在我们来玩一把就就行了哈,非常简单这段代码。就是体,在这体现出它返回的是一个指针,那我们来运行一把吧。运行。运行一下,那运行过后呢,我分别输入第一个字符串和第二个字符串,看看它返回哪个,比如说我输入一个J。JK呢?有四个字符回车,我们再输入一个汤姆,哪一个更长一点呢?显然第一个字符串JK有四个字符,它的长度为四,而第二个字符串呢,它的长度为三,因此应该返回阶,我们看是不是返回阶回车,OK,使卷一的长度为40,卷二的长度为三,因此呢,Longer就是长一点的,这不算式Jack好。
04:22
第一个我们就讲完了,非常简单,那现在呢,我们顺便就说一下,在。使用返回指针的函数时,我们需要注意哪些?地方我这里呢,总结了使用指针函数的注意事项有三点。第一点,用指针作为函数返回值,返回值时需要注意的是,函数运行过后呢?就是我们调用的函数运行过后,它会销毁在它内部定义的所有局部变量。包括局部数据啊,包括局部变量,局部数组,还有形参都会被销毁的。
05:01
那么函数返回的指针不能指向这些数据。我举个例子。我给大家举个例子,大家一目而了然。好,这个案例呢,我们专门讲一下,就是它的一个细节,我们写到这里来,叫return point point function的细节。OK,我们专门讲细节,在这里呢,我们把它的后缀改一下,大家注意观察一下细节是哪是哪个电影就行了,好吧。代码我给大家放过来。呃,同样,我们需要引入相应的文件,相应的头文件,Include std。好,引进去了。好,那么我跟大家讲一个道理,你看啊。哦,大家大家看我这画一个简单示意图就可以了,同学们看这里我们有,嗯,这个地方大家可能看的有点不明白,我把这个换一下。
06:01
Int n,好,这样大家就应该看明白了。TN。上面呢有一个分号。同学们看一下这里面我们是做了什么事情?在这里我调了一个function。对,那这个function呢,Function它返回返回的是一个指针。对吧,而而这个指针其实它是干什么的,大家看这里,它在内,这是个局部变量。大家想这个局部变量,其实根据我们原先讲的这个原则,这是我们的主站,它调用的时候呢,会产生一个新站,那相当于说这个N其实是在哪里呢?是在我们这个站里面产生的,对不对。是这样子的吧,结果呢,你把它的指针把它地址返回来了,返回给谁了呢?返回给这个P了,这就很麻烦,麻烦在什么地方,你们知道吗?因为当这个函数返回的时候,这个我们认为是销毁了的。
07:00
那完蛋了,那你返回的这个P,它指向的这一个空间就有可能是一个无效的,我说的是可能是一个无效的啊,那也就是说你这样去用这个P指向的是一个什么呢?是一个无效的空间,因此你在这里输出。在输出这个N的时候,你看你看我怎么做的,我把这个星号P。返回给这个N,在就说这个是相当于说我本意想把这个100返回给这个N嘛,那么我在这里到底能不能输出100呢?我们要思考一下,思考是否能够输出100。大家觉得能不能输出啊?大家觉得能不能说出这个答案是不一定。啊,不一定。说老师你刚才说的不是有问题吗?为什么又变成不一定了呢?同学们看这样子一个道理就是我们先来看一下,这个时候其实你会发现它确实能够输出100,他确实能够输出100,我给大家运行一下,你们先看一下。
08:05
你们你们先来看一下,此时此刻在这像现在像像我这样用啊,你会发现它确实能够输出100。他的确能够输出100,您你看一下它输出的值呢。输出的值是多少呢?就是100,诶那就怪了,刚才老师说的这个局部变量是在什么呢?在这个function返回时,返回时就会销毁啊。那就会销毁,为什么,为什么你这还能够返回到这个100呢,大家知道为什么吗?哎,你就看老师说的第二个细节。大家看,函数运行结束后,会销毁所有的局部数据,销毁谁的局部数据呢?销毁函数的应该这样写,会销毁该函数。该函数所有的数据。这里所谓的销毁并不是将局部数据占用的内存全部清零,这句话很重要,而是程序放弃对它的使用权限。
09:11
后面的代码可以使用这块内存。这句话一定要深刻的理解啊,各位同学,这句话一定要深刻的理解。那有时候老师这个话怎么理解呢,大家看。你们你们知道为什么刚才老师这样去使用这个N,它就是输出100吗?原因是这样子的,还是画一个示意图。跟上老师思路。OK,跟上老师说了啊,这课我就省点事,这是我们的。M站就是主站,那么根据你的区别调用,你调用那个function,那么会产生一个function站。在这里面呢,你创建了一个N。的确这个N呢,它是一个100,这个没有任何问题,然后他把这个地址返回给我们这个P了,也就是说P呢。
10:01
P它指向了哪个呢?它指向了这个这个100。这也没问题,但是当你调用完这个方形的时候,其实这个空间呢,确实是被销毁了的。但是它所谓销毁并不是把这个100。数据存放的这个清零,而是代表这个空间,假设这个这个空间占用的是A这么大的一个空间,而是代表这个空间的权限。放弃了,就是说如果有别人在去使用内存的话呢,别人可以去使用这块内存,那你看你为什么刚才可以输出100,是因为你在这个地方把星号P你,你在这地方没有做任何的操作。没有做任何操作,那么这个时候注意听讲,你看啊,它会把这个星号100这个值呢,付给这个N。N会怎么办呢?因为这个空间现在还没人用,所以说他通过星号P呢,其实可以拿到这个100的,拿到这个100呢,把它付给他就OK了,所以说他原因是这样子的。
11:06
也就是说,虽然这个空间已经被销毁了,但是这个100这个所在的这个数据呢,并没有清零。没有,为什么没有清零呢?是因为你在这段代码的这个过程中,还没有使用到原先100占用的空间,那如果我稍微改一下,你会发现马上就变化了,比如说同学们看我在这里。我在这里干件什么事情呢?我在这里说出一句话。啊,比如说我写OKOK。各位同学,当我说出这么一句话的时候呢,这个函数它也会占用空间。这个时候就有可能把原先100这个局部变量占用的空间重新使用,就是它呢可能。可能去使用到,使用到原先这个局部变量哪个呢?原原先局变量这个东西。
12:06
占用的。占用的空间,这样子的话呢,告诉大家,这样子的话呢,我们输出这一个N呢,就有可能不是100了。为什么?因为因为他取的时候,这个地址,就是原先那个地址的数据已经被别人占用了。我们来运行一下,看看是不是这个道理,走起来。好,我们看一下这个结果,好,同学们可以看到现在这个结果。你看变成负二了。为什么变成负二了?知道吗?就是刚才老师画的这个图。画这个图,就是原先这个N,它有一个空间存了一个100,但是因为你这句话在执行的过程中也会占用空间,所以他有可能把你这里面的这个100的数据呢。这个占用的空间给你制成一个其他的值了。你如果没有这句话呢,是有可能因为你没有这句话的话呢,他这个空间没有被人占用,所以说就这样子的,明白了吧,好,我把这个就讲清楚了啊,我们再来看第三个细节,C语言不支持在调用函数时返回局部变量的地址,如果你确实有这样的需求,那么需要定义局部变量为static变量,这个就能解决问题。
13:26
这个就能解决问题,那有些同学说老师你给我演示一下可以的,我给大家演示一下,大家看啊,我现在这仍然输出OKOKOK,大家可以看到此时此刻它输出的就不是100了,因为这个空间已经被人占用了。对吧,但是我就是想返回怎么办呢?你看我加一个static就可以了。好,我在这,我把我把这个换一个写法啊,Static int n等于100。那么我要说的是,如果这个局部变量,如果这个局部变量是static性质的。
14:06
Static性质。性质的,那么那么注意听,那么。那么这个空间,这个空间在哪里分摊呢?就是这个N的空间啊,N存放数据。数据的空间在哪里呢?在静态,静态这个数据区。数据去,那这样呢就不会有问题了,大家回忆以前我们讲过的这一个变量,Static的一个变量存储位置,我们打开是不是老师在讲变量作用域的时候,我们在讲变量作用域的时候,我们画了画过一个图啊,就这个图还记得吗?还记不记得我们讲过,如果你这个局部变量是丹提克修饰的,那么这个局部变量就不会在战区放我们的数据,而是在我们静态存储区放。
15:04
那换言之就是如果我加了一个STATIC100,那么这个100呢,不会存在站区,而是存在我们这个静态存储区,因为静态存储区它属于全局的概念,因此它在它会让这个。指向哪里呢?指向这个100。好,如果指向这个100就没问题了。为什么?因为你指向这个地方,这个地方如果存了一个100数据,它把这个指针返回过,返回过去过后呢,在这个主站里边,它仍然指向这个空间。那这样子就无所谓了,因为你即使再去用别的代码,它也不会不能够占用到静态数据区的这个空间,因此就不会有问题。明白了吧?想清楚了没有?讲清楚了啊,这点如果再不清楚的话,说不过去,我已经讲的很清楚了,来我们试一下,如果说老师在这里加上一句话,你会发现一切OK,看到没有,这里面你你再打多少。多少句话都没有问题,你答多少句都没都无所谓,这个时候你会发现他就会老老实实的输出100,老老实实的输出100,来看一下。
16:10
运行跑起来。这个是绝对会输出100的,因为这个时候static int n呢,大家看是不是这样子的。你们看一下这边输出的是不是100,原因是因为我写到这里来。这个局部变量是13性性质特色,那么N存的数据空间就在静态数据区。这个静态数据区呢,就不会再被其他的变量来占用了。所以说你这样写多少句语句都不会占用这个N所在的空间,因此就没问题。明明白了吧,好,明白过后呢,我们再来做一个题吧,我们再来做一个题,它要求呢,编写一个函数,能够生成十个随机数,并使用表示指针的数组名来返回它们,啊,这个太简单了,说白了它就让你写一个函数,能够在这个函数里面生成一个十个随机数的一个一位数组返回来供我们主函数使用,来跟上老师思路,我们来编写一下。
17:12
那这样向同学们我们打开。我们这块我们来编写一下啊同学。只要你明白前面的道理,那这个呢,就是小儿科了。还有老规矩,我们写一个什么呀,练习。EXERCIC。好,我把这个后缀呢,还是改一下吧。把这个后缀改一下。好。STDIO。VO的主函数。没问题吧,同学们,这个应该很轻松,我现在呢写一个函数。编写一个函数,返回一个一维数组。
18:01
啊,OK,那开始写了啊,那返回一个,因为数组显然我假设是整形的,我就返回它好不好,然后就写个F1。好,那么现在呢,我去整一个数组。这个数字呢为十好,大家知道,因为我们讲过,就是如果说你要返回,通过一个函数返回一个指针,那这个呢,一定要用sta体来修饰,也就是说我们希望这个数组在哪里分配呢?在哪里分配呢?在这个静态区去分配,而不是在站区分配,因为静态数据区呢,它是属于全局的范畴,它的生命周期很长,如果你这样不加时,它会在这里分配我们的数组空间,那用完了过后这个就没有了。所以说很危险,因此呢,我们这样必须加上13说明,必须加上。Sta让什么呢?让我们这个R的R瑞的空间数据空间在哪里呢?在静态数据区。
19:06
去啊去分配。这个大家一定要认真的理解哈,好的,那现在就简单了,我们就负循环一把吧,来一个I等于零负循环。而I等于零,I小于十,I加加。那现在呢,我们就来往里面扔东西了。I等于RA啊随机数,那这个RA呢,需要以一个头文件,我们也是应该是用过的是std std lib,好像是这个包包里面下面头文件有是吧,好,这就产生一个随就产生完了过后怎么办?Return谁呀瑞。因为我们讲过宿主呢,它的首地子就是地,呃,它的宿主的名就是首地子返回给用in特新的形式返回,为什么因特心呢,因为你是这个对吧,好,我们这少加这这个,因为你你是int嘛,所以说我用int新来返回没问题,好现在呢,我们来测试一把。
20:08
我们来测试一下。嗯,怎么呃怎么测试呢。好,怎么测试呢?我写一个心。好,这是一个指针哈,当然我P等于什么呢?F1。没问题吧,现在我开始遍历一下for循环,我再来一个。再定一个特吧。In the I,我,我用指针来遍历一下这里生成的数组数据哈,For,循环。I等于0I小于10I加加。哀家家。然后呢,我把这个数据取出来,大家看一下。找百分号D,百分号D呢为每每来一个,咱们换一个行,怎么取呢?我这样取这个P,我先问大家这个时候这个P它指向哪里啊,指向的是在注意听在这个F1中。
21:06
在这个F1中生成的,哎,生成的这个数组的首地子首弟子。其实就是第一个元素的地子,即怎么样,即第一个元素的地址,能理解哈,那现在我们就这样玩了,走。让它让这个P加一个I,然后呢,取个星号就完事了。能看懂吗,同学们?应该能看懂啊,这个没什么难度的好。你看我这个P加I呢,是第一次加零就相当于不加第二次呢加一,加一就取到了我们这个返回的数组的第二个元素,加二呢就返回第三个元素,也就是说将来你这个地方有数组有几有很多元素。那么我们原我们这个P呢,它最先前指向的是第一个元素,好这时呢,我们就把它,呃,把这个值取出来,是多少就多少,然后P加一,让这个P再指向哪里呢?P再指向这个元素,再把值取出来,P加二再指向这个元素,以此类推,我取我取几次呢?取十次,因为我有十个数元素,对不对?好写完了我们来看一下对不对。
22:18
来个朋友,我们先生成一下解决方案。看代码有没有问题。Okay。看有没有问题。好,现在呢,代码没有问题,我们运行一下。诶,你看我们产生的十个随机数,这样的一二三四五六七八九十十个,我们再来一次吧。我们再运行一下,又产生十个。哎,你看还是这样子的,对不对,走起来。对吧,它总是这样子这样子的,因为我我们那个种子没有变化,所以他每次返回值是一样的啊,就是十个数十个数好的,而且呢,你因为你是静态的,所以说你不会影响到,就是说你整个过程中不会影响影响到我们这个数组存放的数据。
23:09
各位同学,那关于我们返回指针的函数呢,就给大家讲解到这里,我们梳理一下讲解的内容。返回指针的函数我们讲了哪些呢?我们来梳理一把。往下拉啊,其实这个并不难,对不对,并不难。往下走一下。现在我们讲的是返回指针的函数,讲了哪些内容呢?首先我们做了一个基本的介绍。对,我们先说一下,C语言可以允许函数返回一个值是指针,这样的函数称之为指针函数,我们紧接着来个快速入门,诶,这个。这快速入门。那快速入门呢,我们写了一个代码拿过来,代码在哪里呢?是在我们point第一个。是不是这个案例啊?是的,谁敢你?是不是这个案例啊,应该就是这个案例了,我把这个案例呢给同学们板书过来。
24:05
这些都不难啊,同学们都不难,只要你前面听懂了,这些都是小儿科,这个做完了过后呢,是不是我们又给大家说了一下返回的指指针函数需要注意的三点细节讲了没有,是不是在这讲的。三点细节我们也梳理到这里。说到这里。那针对这上面细节呢,我们有个代码演示。是有代码演示吧,代码演示呢,实际上就是在这个地方了。细节我也给大家标出去。写到这来。这是我们的代码演示。那么代表演示里面把这些细节都已经讲清楚了,总而言之,大家要记住,我们就是记住哪一句话呢?记,记住这句话,这是最关键的一句话。这句话是非常非常重要的,一定要有印象啊。C语言不支持在调用函数是返回局部变量的地址,这个局部变量是可以是单个的变量,也可以是数组,如果确实有这样的需求,需要将局部变量定定义成是单个,也就是这个解决方案。
25:12
必须记住这个,否则的话,你不要把一个局部变量的地址返回给其他。返回给别的函数去使用,肯定要出问题。明白这个意思吧,好,这是细节,那细节讲完了过后,是不是我们还讲了一个应用案例,加深大家对这个指针函数的理解,是吧,写了这么一个,那代码呢,把它放放这。代码演示,各位同学,我把代码演示呢给大家梳理一下,在哪里呢?其实就是在这儿呗。是吧,在这好同学们,我把这个代码呢,也给大家板书到咱们这个位置。OK。这一点不明白的同学,自己再去看一看好不好,再去看一看那各位同学关于返回指针的函数。
26:03
我们就讲到讲到这里,大家呢,消化一下。
我来说两句