【C语言】04-函数
一、函数的分类
前面已经说过,C语言中的函数就是面向对象中的"方法",C语言的函数可以大概分为3类:
1.主函数,也就是main函数。每个程序中只能有一个、也必须有一个主函数。无论主函数写在什么位置,C程序总是从主函数开始执行
2.开发人员自定义的函数,可有可无,数目不限
3.C语言提供的库函数,例如stdio.h中的输出函数printf()和输入函数scanf()
二、函数的声明和定义
虽说C中的函数类似于Java中的方法,但在使用上还是有区别的。
1.在Java中,每个方法的定义顺序没有限制,在前面定义的方法内部可以调用后面定义的方法

1 public void test() {
2 int c = sum(1, 4);
3 }
4
5 public int sum(int a, int b) {
6 return a + b;
7 }

第1行定义的test方法可以调用在第5行定义的sum方法
2.在标准C语言中,函数的定义顺序是有讲究的,默认情况下,只有后面定义的函数才可以调用前面定义过的函数

1 int sum(int a, int b) {
2 return a + b;
3 }
4
5 int main()
6 {
7 int c = sum(1, 4);
8 return 0;
9 }

第5行定义的main函数调用了第1行的sum函数,这是合法的。如果调换下sum函数和main函数的顺序,在标准的C编译器环境下是不合法的(不过在Xcode中只是警告,Xcode中用的是GCC编译器)
3.如果想把其他函数的定义写在main函数后面,而且main函数能正常调用这些函数,那就必须在main函数前面作一下函数的声明

1 // 只是做个函数声明,并不用实现
2 int sum(int a, int b);
3
4 int main()
5 {
6 int c = sum(1, 4);
7 return 0;
8 }
9
10 // 函数的定义(实现)
11 int sum(int a, int b) {
12 return a + b;
13 }

我们在第2行做了sum函数的声明,然后在第6行(main函数中)就可以正常调用sum函数了。
函数的声明格式:
返回值类型 函数名 (参数1, 参数2, ...)
可以省略参数名称,比如上面的sum函数声明可以写成这样:
int sum(int, int);
只要你在main函数前面声明过一个函数,main函数就知道这个函数的存在,就可以调用这个函数。究竟这个函数是做什么用,还要看函数的定义。如果只有函数的声明,而没有函数的定义,那么程序将会在链接时出错。
4.在大型的C程序中,为了分模块进行开发,一般会将函数的声明和定义(即实现)分别放在2个文件中,函数声明放在.h头文件中,函数定义放在.c源文件中
下面我们将sum函数的声明和定义分别放在sum.h和sum.c中
sum.h文件

sum.c文件

然后在main.c中包含sum.h即可使用sum函数

其实sum.h和sum.c的文件名不一样要相同,可以随便写,只要文件名是合法的
运行步骤分析:
1> 在编译之前,预编译器会将sum.h文件中的内容拷贝到main.c中
2> 接着编译main.c和sum.c两个源文件,生成目标文件main.obj和sum.obj,这2个文件是不能被单独执行的,原因很简单:
* sum.obj中不存在main函数,肯定不可以被执行
* main.obj中虽然有main函数,但是它在main函数中调用了一个sum函数,而sum函数的定义却存在于sum.obj中,因此main.obj依赖于sum.obj
3> 把main.obj、sum.obj链接在一起,生成可执行文件
4> 运行程序
说到这里,有人可能有疑惑:可不可以在main.c中包含sum.c文件,不要sum.h文件了?

大家都知道#include的功能是拷贝内容,因此上面的代码等效于:

这么一看,语法上是绝对没有问题的,但是绝对运行不起来,在链接时会出错。原因:编译器会编译所有的.c源文件,这里包括main.c、sum.c,编译成功后生成sum.obj、main.obj文件,当链接这两个文件时链接器会发现sum.obj和main.obj里面都有sum函数的定义,于是报"标识符重复"的错误。
有人可能觉得分出sum.h和sum.c文件的这种做法好傻B,好端端多出2个文件,你把所有的东西都写到main.c不就可以了么?
- 没错,整个C程序的代码是可以都写在main.c中。但是,如果项目做得很大,你可以想象得到,main.c这个文件会有多么庞大,会严重降低开发和调试效率。
- 要想出色地完成一个大项目,需要一个团队的合作,不是一个人就可以搞的定的。如果把所有的代码都写在main.c中,那就导致代码冲突,因为整个团队的开发人员都在修改main.c文件,张三修改的代码很有可能会抹掉李四之前添加的代码。
- 正常的模式应该是这样:假设张三负责编写main函数,李四负责编写一系列的自定义函数,张三需要用到李四编写的某个函数,怎么办呢?李四可以将所有的函数声明在一个.h文件中,比如lisi.h,然后张三在他自己的代码中包含lisi.h文件,接着就可以调用lisi.h中声明的函数了,而李四呢,可以独立地在另外一个文件中(比如lisi.c)编写函数的定义,实现那些在lisi.h中声明的函数。这样子,张三和李四就可以相互协作、不会冲突。
三、函数的形参和实参
在定义函数时,函数名后面的()中定义的变量称为形式参数(形参);在调用函数时传入的值称为实际参数(实参)。

// b是test函数的形参(形式参数)
void test(int b)
{
b = 9; // 改变了形参b的值
} int main()
{
int a = 10;
printf("函数调用前的a:%d\n", a); test(a); // a是test函数的实参(实际参数) printf("函数调用后的a:%d", a);
return 0;
}

如果是基本数据类型作为函数的形参,那是简单的值传递,将实参a的值赋值给了形参b,相当于
int a = 10;
int b = a;
b = 9;
a和b是分别有着不同内存地址的2个变量,因此改变了形参b的值,并不会影响实参a的值。
上述代码的输出结果为:
【C语言】04-函数的更多相关文章
- C语言-04函数
1.参数 参数注意点 1.形式参数:定义函数时函数名后面中的参数,简称形参 2.实际参数:调用函数式传入的具体数据,简称实参 3.实参个数必须等于形参个数 4.函数体内部不能定义和形参一样的变量 5. ...
- Android C语言_init函数和constructor属性及.init/.init_array节探索
本篇文章主要介绍了"Android C语言_init函数和constructor属性及.init/.init_array节探索",主要涉及到Android C语言_init函数和c ...
- C语言pow函数编写
C语言pow函数编写 #include<stdio.h> double chaoba(double f,double q); //声明自定义函数 void main(void) { dou ...
- C语言-自定义函数
C语言自定义函数 --1-- 自定义函数定义 1.1 无参无返回值函数 1.2 无参有返回值函数 1.3 有参无返回值函数 1.4 有参有返回值函数 --2-- 函数的参数 2.1 形式参数介绍和使用 ...
- C语言printf()函数:格式化输出函数
C语言printf()函数:格式化输出函数 头文件:#include <stdio.h> printf()函数是最常用的格式化输出函数,其原型为: int printf( char ...
- C语言的函数
"函数"在英文的翻译是"function",无论在自然科学还是计算机科学都是这个词,而"function"的本意是"功能" ...
- c语言main函数返回值、参数详解(返回值是必须的,0表示正常退出)
C语言Main函数返回值 main函数的返回值,用于说明程序的退出状态.如果返回0,则代表程序正常退出:返回其它数字的含义则由系统决定.通常,返回非零代表程序异常退出. 很多人甚至市面上的一些书籍,都 ...
- Go语言示例-函数返回多个值
Go语言中函数可以返回多个值,这和其它编程语言有很大的不同.对于有其它语言编程经验的人来说,最大的障碍不是学习这个特性,而是很难想到去使用这个特性. 简单如交换两个数值的例子: package mai ...
- 【学习笔记】【C语言】函数
一. 什么是函数 任何一个C语言程序都是由一个或者多个程序段(小程序)构成的,每个程序段都有自己的功能,我们一般称这些程序段为“函数”.所以,你可以说C语言程序是由函数构成的. 比如你用C语言编写了一 ...
- 【转载】 c语言inline函数的使用
c语言inline函数的使用 转载自:http://blog.chinaunix.net/uid-21843265-id-3056446.html 大学在教科书上学习过inline函数,定义为inli ...
随机推荐
- MVC数据验证
深入浅出 MVC 数据验证 2.0 [附演示源码] 今天在这里给大家介绍一下MVC的数据验证框架. 在1.0版中,很多朋友提出了怎么使用客户端验证,今天找了一些资料,发现了客户端验证的方法. 1.MV ...
- iOS 和Android中的正则表达式简单使用
ios 中需要使用NSRegularExpression类,NSTextCheckingResult类. 下面给出最基本的实现代码 NSRegularExpression *regex = [NSRe ...
- iOS 和 Android 中的后台运行问题
后台机制的不同,算是iOS 和 Android的一大区别了,最近发布的iOS7又对后台处理做了一定的更改,找时间总结一下编码上的区别,先做个记录. 先看看iOS的把,首先需要仔细阅读一下Apple的官 ...
- Ubuntu进不去,显示error:unknown filesystem (最简单解决方案总结)
error filesysterm:文件系统错误 grub rescue:是让你拯救grub,就是你的grub坏了,引导程序坏了 要安装盘?要重装?No…… 只要几行命令就ok了 是的,这是我昨天亲自 ...
- 食物链(codevs 1074)
题目描述 Description 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A吃B,B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并 ...
- (七)STM32的RTC简单操作
简单说明: /********************************************************************************************* ...
- 昨天用的流量有点多60M
就是因为值班这里没有无线,然后自己又是受前几次的影响,没有收到微信,然后就看了热点,这是用的快的.
- centos 截图命令 screenshot
[root@ok ~]# gnome-screenshot#全屏截图 [root@ok ~]# gnome-screenshot --interactive#自定义截图
- Git Fast-forward提交
多人协同开发,使用Git经常会看到警告信息包含术语:Fast-forward, 这是何义? 简单来说就是提交到远程中心仓库的代码必须是按照时间顺序的. 比如A从中心仓库拿到代码后,对文件f进行了修改. ...
- Ubuntu小点汇总,更新中...
转自:http://blog.csdn.net/zxz_tsgx/article/details/39713627 昨天重装了Ubuntu14.04 64位版,又被一些基础操作/设置给搞怕了,以前安装 ...