任何一个C语言程序都是由一个或者多个程序段(小程序)构成的,每个程序段都有自己的功能,我们一般称这些程序段为“函数”。所以,你可以说C语言程序是由函数构成的。
比如你用C语言编写了一个MP3播放器程序,那么它的程序结构如下图所示:
从上图可以看出:函数就是用来实现某个功能的程序段,每一个函数都有自己的功能。因此,你应该把实现某个功能所需的代码都写在函数中。比如,有个函数的功能是播放MP3,那么播放MP3的代码都应该写到这个函数中。
当调用(执行)一个函数时,计算机就会按顺序执行函数中的所有代码,从而展示函数所实现的功能。
一般来说,我们会将不同的功能交给不同的函数去实现。比如,将暂停播放MP3的代码写到一个函数中,将停止播放MP3的代码写到另一个函数中。因 此,一个C程序中可能会有很多的函数。为了方便调用和区分这些函数,我们需要为每一个函数都起一个唯一的名称,函数的命名必须按照标识符命名规则。利用函数名就可以调用到对应的函数。
回到顶部
定义函数的目的就是为了写清楚你这个函数是干啥用的,里面包含了哪些代码。函数的定义格式如下:
1 返回值类型 函数名(形式参数列表)2 {3 函数体4 }
比如定义一个函数用来计算两个整数的和。那么可以写成下面这样:
1 #include <stdio.h> 2 3 int sum(int a, int b) 4 { 5 int c = a + b; 6 return c; 7 } 8 9 int main()10 {11 int d = sum(10, 11);12 13 printf("d is %d", d);14 return 0;15 }
分别在第3行、第9行定义了sum函数、main函数,其中sum函数的作用是计算两个整数的和。
函数定义好后,并不会马上执行函数内部的代码,要有人调用它才会执行内部的代码。就好像你的手机虽然有打电话的功能,但是只有按了拨号键,才会执行打电话的功能。
程序运行时就会先调用main函数,按顺序执行第11~14行代码,因为main函数是程序的入口
第11行的sum(10, 11)是调用sum函数,sum函数被调用了,就会分配存储空间给形式参数列表中的所有参数,也就是第3行中的变量a和变量b,它们都是“形式参数”
第11行中的10、11称为“实际参数”,它们将分别赋值给变量a、变量b,也就是相当于
1 int a = 10;2 int b = 11;
既然调用了sum函数,就会按顺序执行sum函数中的代码,也就是第5~6行代码。
第5行将a+b的值21赋值给了变量c,第6行使用return关键字将变量c返回给了函数调用者,也是说,第11行sum(10, 11)的值是21。那么变量d的值就是21。
第13行的输出结果为:
d is 21
第3~7行中的变量a、b、c都只有在调用sum函数时,才会分配存储空间,当sum函数执行完毕后,变量a、b、c就会被释放存储空间。因此,它们的作用域仅限于sum函数内部。
第3行sum左边的int称为“返回值类型”,第6行return关键字后面跟着的数值称为“返回值”,因此第6行的变量c就是返回值,返回值的数据类型应该跟“返回值类型”保持一致。
回到顶部
1> 形式参数:在定义函数时,函数名后面的小括号()中定义的变量称为形式参数,简称形参
2> 实际参数:在调用函数时传入的值称为实际参数,简称实参
1 int sum(int a, int b, int c) 2 { 3 return a + b + c; 4 } 5 6 int main() 7 { 8 sum(10, 9, 7); 9 return 0;10 }
第1行中sum函数中有3个形参,因此在第8行调用sum函数时,需要传入3个实参
1 #include <stdio.h> 2 3 int test(char a) 4 { 5 a = 10; 6 7 return 0; 8 } 9 10 int main()11 {12 char b = 5;13 14 test(b);15 16 printf("b的值是%d", b);17 18 return 0;19 }
在第3行定义了test函数,只有一个形参a
在第14行调用了test函数,接着就会分配内存给变量a。这里将变量b当做实参,那么变量b的值将传递给变量a。这个时候,内存中大致如下图所示:
(其实在内存中存储的是二进制数据,这里我写成10进制是为了直观性)
执行完第5行代码后,变量a的值变成了10,但是变量b的值依然是5
第16行代码的输出结果是:
b的值是5
因此,在函数内部修改了形参的值,并不会影响到外面的实参。
定义一个函数时是可以没有形参的,比如下面的函数
1 #include <stdio.h> 2 3 int test() 4 { 5 printf("调用了test函数"); 6 return 0; 7 } 8 9 int main()10 {11 test();12 return 0;13 }
在第3行定义了test函数,可以发现,它的形参列表是空的,也就是没有形参
那么在第11行调用test函数时,就不用传递任何实参
其实,第9行定义的main函数也是没有形参的
回到顶部
1 double pi() 2 { 3 return 3.4; 4 } 5 6 int main() 7 { 8 double a = pi(); 9 return 0;10 }
第1行定义了一个pi函数,返回值类型是double,因此用return返回的数值应该是double类型的,这里返回的是3.14
第8行pi函数调用完毕后,函数调用者得到的值就是3.14,因此,变量a的值是3.14
1 #include <stdio.h> 2 3 void test() 4 { 5 printf("调用了test函数"); 6 return; 7 } 8 9 int main()10 {11 test();12 return 0;13 }
在第3行定义了一个test函数,它是没有返回值的,所以第6行的return后面没有跟上任何数值
在第11行调用了test函数
所以,上面的test函数可以简化成:
1 void test()2 {3 printf("调用了test函数");4 }
1 sum(int a, int b)2 {3 return a + b;4 }
可以看到,第1行定义的sum函数没有明确写出返回值类型,那么这个sum函数的返回值类型就是int。因此,第3行return后面跟随的是int类型数据
回到顶部
1 int sum(int a, int b) 2 { 3 return a + b; 4 } 5 6 int main() 7 { 8 int c = sum(5, 8); 9 return 0;10 }
第3行使用了return语句,将a+b的值返回给了函数调用者,因此第8行变量c的值是13
1 int max(int a, int b)2 {3 if (a>b)4 {5 return a;6 }7 8 return b;9 }
这个max函数可以用来求出两个整数中的最大值
如果a大于b,就执行第5行代码,直接将a返回,函数就会停止执行。也就是说,后面的第8行代码就不会被执行
如果a不大于b,就执行第8行代码,将b返回
回到顶部
默认情况下,函数的名字必须唯一。下面的写法是错误的:
1 void test(int a)2 {3 4 }5 6 int test()7 {8 return 10;9 }
第1、6行定义的函数的名称都是test,编译器会直接报错
下面的写法是错误的:
1 int main()2 {3 void test()4 {5 6 }7 8 return 0;9 }
在第3行把test函数定义在了main函数内部,这是错误的写法
从第一个C语言程序开始,就认识了这个main函数。main函数是整个C程序的入口,有了main函数,C程序才能运行成功,而且整个C程序中只能有一个main函数。
main函数的简单定义如下:
1 int main()2 {3 4 return 0;5 }
它可以没有形式参数,返回值是int类型。它的返回值用于说明程序的退出状态:如果返回0,则代表程序正常退出,否则代表程序异常退出
你可能已经注意到,平时一直在使用的printf其实也是一个函数,这是系统自带的函数
1 #include <stdio.h>2 3 int main()4 {5 6 printf("我要学习iOS开发");7 8 return 0;9 }
在第6行调用了printf函数,传入的参数是一个字符串常量:"我要学习iOS开发"
printf函数的作用是在屏幕上输出内容
注意第1行代码,如果你使用了printf函数,就要加上这一句,至于原因,会在后面的章节详细介绍