说明:这个C语言专题,是学习iOS开发的前奏。也为了让有面向对象语言开发经验的程序员,能够快速上手C语言。如果你还没有编程经验,或者对C语言、iOS开发不感兴趣,请忽略
前面已经说过,C语言中的函数就是面向对象中的"方法",C语言的函数可以大概分为3类:
1.主函数,也就是main函数。每个程序中只能有一个、也必须有一个主函数。无论主函数写在什么位置,C程序总是从主函数开始执行
2.开发人员自定义的函数,可有可无,数目不限
3.C语言提供的库函数,例如stdio.h中的输出函数printf()和输入函数scanf()
虽说C中的函数类似于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方法
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编译器)
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函数就知道这个函数的存在,就可以调用这个函数。究竟这个函数是做什么用,还要看函数的定义。如果只有函数的声明,而没有函数的定义,那么程序将会在链接时出错。
下面我们将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> 运行程序
大家都知道#include的功能是拷贝内容,因此上面的代码等效于:
这么一看,语法上是绝对没有问题的,但是绝对运行不起来,在链接时会出错。原因:编译器会编译所有的.c源文件,这里包括main.c、sum.c,编译成功后生成sum.obj、main.obj文件,当链接这两个文件时链接器会发现sum.obj和main.obj里面都有sum函数的定义,于是报"标识符重复"的错误。
在定义函数时,函数名后面的()中定义的变量称为形式参数(形参);在调用函数时传入的值称为实际参数(实参)。
// 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的值。
上述代码的输出结果为: