这也许是最不正经的C语言教程……函数篇

Chapter One 函数

这是一份纯入门的教材。我尽量写的通俗易懂,希望通过这些东西让大家以最轻松的方式理解C语言的世界观从而迅速入门。可能显得有些墨迹,很多地方也不是很正式,已经学的比较明白的同学还是直接看教材就好了。也希望看完这个的同学也可以回去看一遍教材,肯定会有更多理解,到那时候才是真正掌握了。

阅读这一章之前希望大家已经对C语言的基本结构和变量,判断,循环等基本语法有大概了解,如果不了解,请期待后续教程……前半部分为尽量轻松的讲解,中间也会加入考试真题的讲解。最后附有速成清单。

 

在经历了变量,常量,判断,循环等一系列晦涩难懂的词语的狂轰滥炸之后,我们终于迎来了一个似乎是比较熟悉的东西——函数。函数我知道啊!奇函数,偶函数,指数函数,对数函数我都知道啊!

然后你就会发现,这里的函数和你想的“f(x)”根本一毛钱关系都没有……

 

Part One 函数到底是什么鬼?为什么要用它?

其实这本来是翻译上的不准确,在其他某些语言里,函数(function)有一个更容易理解的名字,它叫做方法。

方法又是什么?方法是完成某项任务的途径,或者说,某种流程。

下面举个不是特别恰当的例子,假如你是老板,如果你想打印一份文件a,你需要怎么做呢?也许你需要完成以下的任务:

第一步,找到几张A4纸

第二步,把纸放进打印机里面

第三步,打开打印机的电源

第四步,打开要打印的文件a,点打印按钮

好了,现在你的文件已经打出来了

不对啊,你是老板啊,这种事情怎么能亲自做呢

所以你找到了一个新来的,告诉他,小杨啊,把这份文件给我打出来!

然后,你就可以坐在老板椅上,喝着茶水,等着你的文件来了

没错,当你明白了这一点,你就完成了当一个合格的老板的第一步(误),同时,你也已经初步理解了所谓“函数”的工作思想

没错,这里小杨来打印,就是一个方法,或者说,函数。它解决了打印过程中的一系列工作。

下面我们把刚才的问题抽象成一个C程序

#printAbyBoss.c

int main()

{

拿出一张A4纸;

上纸;

打开电源;

打开文件a并打印;

拿出文件;

return 0;

}

看起来没什么不对,逻辑也很清晰,嗯。而且只有六行代码,看起来也挺简单的。

然而请永远不要忘记,你是老板

现在我们来设想一下,假如,打完了文件a,你发现你又想要打印文件b……

你就需要把以上所有的事情再重复一次……

你累不累啊……

突然,你脑袋里的小人问你,为什么不再叫一次小杨呢?

现在我们来看下一段程序

#printByXiaoYang.c

void XiaoYang(char x)

{

 拿出一张A4纸;

上纸;

打开电源;

打开文件x并打印;

拿出文件;

}

Int main()

{

XiaoYang(a);

XiaoYang(b);

return 0;

}

轻松加愉快对不对~

你又可以愉快地喝茶水了,你所有的工作就只是叫了两次小杨。然而你已经把所有任务完成了。

是不是已经感受到“函数”的巨大好处了呢?

现在让我们来正式的认识一下函数,所谓函数,其实就是把一段经常会用到的代码,放进一个特别的代码块里面,从此它变成了我们的一个工具,我们可以随时利用它,来完成我们的工作(或者,专业地说,这是一个可重用的代码块)

可能你会想说,可是我写的代码还是那么多啊!

事实并不是这样的,就像刚刚举的例子,如果你一上午只需要打一份文件,那么的确没有什么区别,然而如果你发现你有10份文件要打呢?

而且另外一个好处是,你发现你的工作变得更加清晰,你只是叫了两次小杨而已。

而且如果小杨搞砸了,你还可以骂他,总比自己打错了强

实在不行,你还可以开除他,雇一个小玉,然后继续叫他

以上三句话并不是玩笑,这是使用函数三个实实在在的好处:

1. 可以让你的程序结构更加清晰,主程序更加简洁易懂

   这很好理解,有意义的代码块代替了一行一行零碎的代码,而主程序只负责指挥这一切

2. 可以让程序调试更加轻松,如果打印出了问题,你可以明确的知道问题出自小杨,而不是到处乱找

3. 如果函数里的东西发生了更新,对你来说仍然没什么变化。没错,就算我们换了打印机,或者干脆把小杨都开除了。我们的主程序的内容不会发生任何变化。请记住,在真正的程序开发中这非常重要,尤其是在一部分代码由一个人写,而主程序由你来写的情况下。(用专业术语来说,函数所做的,降低了程序的耦合度)

这就是我们一定要使用函数的原因。

 

Part Two 我们应该如何使用函数?

其实以上的例子已经演示了一个函数的基本结构。

首先它需要一个名字,我们叫他小杨,当然我们不能打中文,所以我们叫它XiaoYang,非常洋气,嗯

现在我们可以叫他去打印,这个过程叫做函数的调用

结果他鄙视了我们,他说他需要我们把要打的文件传给他

好了,这个过程就叫做参数的传递

刚才的程序里面,我们给了小杨一个char类型的参数,表示让他打文件a,还是文件b,还是文件c

当然,实际的时候我们可以给他各种类型的参数,比如int,float,甚至是结构体和指针(这个以后再说)

刚才的小杨非常笨,他并不会主动告诉老板,他打完了,只是把文件扔在老板桌子上就完事了

我们要教给他,让他学会打完了告诉老板一声

也就是,设置函数的返回值

当然,返回值和参数一样,也可以是各种类型的。

说了这么多可能还是有点蒙,下面我们来展示这个函数真正的样子

int XiaoYang(char x)                                              //这部分叫做声明

{

.....                                                          //这里是函数的具体代码

return 1;(1代表完成,0代表没完成)         

}

名字前面用来表示返回值的类型,名字后面的括号里面放进去参数的类型和名字,就这么简单

当然,千万不要忘记,如果你设置了一个返回值,请在所有代码的最后(或者其他任何地方),放一个return语句,来表示,我返回了。

那么,我们写好了小杨,他又应该放在哪里

你可以不费力的发现,main()其实就是老板本人

老板执行之前,小杨就必须待命了,所以,对函数小杨的声明(上面有写)一定要放在main之前。

但是,老板只关注小杨在不在,小杨会不会做是小杨自己的事,所以,具体代码可以不放在老板前面,反正他也不关心。

所以你的程序有两种写法:

第一种:

int XiaoYang(char x)

{

  ……

}

Int main()

{

 ……

}

或者是:

int XiaoYang(char x) ;           //请不要忘了分号的存在

Int main()

{

……

}

int XiaoYang(char x)

{

  ……

}

以上两种都可以正常工作,那么,你明白了吗?

在调用的时候,只要写函数名+括号,括号里写参数名就行了,返回值类型和参数类型都不用写了

当然,如果你想要把返回的值留下,可以这样写:result = XiaoYang(x);

请注意,之前我一直用了一个模棱两可的词,主程序,也就是老板main()

你有没有发现,main的后面也带了括号?还有你之前用的printf(),scanf()

现在我们来思考一个哲学问题,小杨为老板工作,那么老板为谁工作

答案是,老板为了伟大的人类和平而工作

算了吧……我只是想说,其实printf,scanf都是C语言的发明人已经写好的函数,前辈们希望他们能辅佐你。main函数也是函数,他是整个程序最初开始执行的那个函数,也就是程序的主体,或者我们说的老板。要知道,我们的程序也是为了解决一个问题,而main函数,就是解决问题的那个方法。只不过他指派了更多的人。同样,小杨也可以继续指派别人,这叫做函数的嵌套。

所以一个程序至少有几个函数?一定有一个main函数。所以,不管你怎么说,之前你所有的程序,都用过函数了。

Part Three 晕乎乎的形式参数问题

你可以已经在形式参数还是实际参数的问题中蒙比了

那么让我来解救你

其实这个事情很简单,假如你给小王换了一个差事,他不再是打印文件了,而是变成了你的贴身秘书,负责修改你的发言稿。

如果我是小杨(其实我就是),我就会聪明一些,我绝对不会直接在老板的原件上瞎改一通,否则老板如果觉得我改的和翔一样,我就可以走人了

我一定会复印一份,然后改副本的

没错,你给函数传入的参数x,函数会自动创建一份副本,虽然你在函数里面的代码的时候仍然叫他x,但是事实上原件已经被聪明的小杨放进抽屉里了

那就是说,你在函数中对x所做的任何操作,对原件,都没有任何影响!

这里面的副本就叫做实际参数,而原件就是形式参数。

除非,你认为你改的非常好,准备把他给老板,那么你写了一句,return x;这时候副本才会真的被老板看见。

否则,随你怎么改

当然,也有一种方式可以直接更改原件的值,那就是把指针作为参数(指针是一种神奇的魔法,以后会学到)

现在我想你应该大概明白了。

对了,再说一件事,在函数里面定义的变量,就只在函数里面能用。这个变量不是那个自动生成的副本。

而是类似小杨自己拿的A4纸,我们就可以写成这样的声明, A4 paper1;这和int paper1没什么区别。那么我要是小杨,这张纸我就不给小王用,所以,这个paper1的变量对外是无法访问的。

Part Four 让我们来看一道题吧

7.3 用函数编程计算两整数的最大值,在主函数中调用该函数计算并输出从键盘输入的两个整数的最大值。

这是一道书上的原题。现在我来讲一下这个题我们应该如何入手来做,弄懂了这个,大家可以看看剩下的。

首先题里指定了函数编程。这里面到底应该怎么设置函数,谁是老板,谁是小杨。

我们先来看看题里有几项工作吧。从键盘输入,计算最大值,然后输出。三项工作。

三项工作中,输入输出的函数,发明C的大神已经帮我们写好了,我们不用管了。

那么唯一需要我们自己写的函数,就用来计算最大值。名字随意,我们叫他findMax()

应该返回什么呢?当然返回最大值 int findMax()

参数是什么?当然是两个数,so……int findMax(int a,int b) 这就是这个函数的样子

主函数什么样?只需要定义变量,调用函数

int main()

{

Int a,b;        //两个数

Int result;     //求得最大值

printf(“请输入两个整数,空格分隔:);

scanf(“%d %d”,&a,&b);

Result = findMax(a,b);

printf(“最大值是:%d”,result);

return 0;

}

非常清晰是不是?

那么那个函数怎么写?

如何找到两个函数的最大值?顶多就三种可能嘛,a比b大,那么a最大。b比a大,那么b最大。俩一样大,都最大。

好了,就是三个if语句,也不涉及什么形式参数的问题

Int findMax(int a,int b)

{

Int max;                  //这个max对外不开放

if(a>=b)               //这里的a和b已经是副本了

{

    max = a;

}

if(a<b)

{

    Max = b;

}

return max;

}

Part Five 传说的速成清单

1.什么是函数:函数就是一些可能反复重用的代码,写在特定的代码块里,并可以被其他函数调用

2.为什么要用函数?

重用代码,减少编程工作量

让程序结构更清晰

降低调试难度

更改程序时其他部分不受影响

3.函数怎么用?

声明时:返回值类型+函数名+(参数类型+参数名)

调用时:函数名+(参数名)

具体函数代码的声明可以写在主函数前也可以写在主函数后

4.什么是形式参数?什么是实际参数?

形式参数是传入的参数名,实际参数是函数运行中生成的副本,修改的是副本,原件不受影响,除非返回副本

函数内定义的变量对外不公开。

5.scanf和printf等已经是现成的函数了,main函数也是函数。

 

好了,这就是有关函数的全部了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值