C编程中的函数是可重复使用的代码块,使程序更易于理解,测试,并且可以在不更改调用程序的情况下轻松进行修改。 函数对代码进行划分,并对程序进行模块化,以获得更好,更有效的结果。 简而言之,将较大的程序分为各种各样的子程序。这些子程序称为函数。函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。
您可以把代码划分到不同的函数中。每个函数执行一个特定的任务来进行的。
函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。
C 标准库提供了大量的程序可以调用的内置函数。例如,函数 strcat() 用来连接两个字符串,函数 memcpy() 用来复制内存到另一个位置。
将大块的程序划分为各个小函数时,可以轻松地分别管理每个函数。 每当程序中发生错误时,您都可以轻松研究故障函数并仅仅更正该函数内的那些错误。
您也可以在需要时轻松调用和使用函数,从而自动节省时间和空间。
C语言的函数类型分为两类,一是库函数,二是用户定义函数。
库函数和用户定义函数之间的区别在于,我们不需要为库函数编写代码。 它已经存在于头文件中,我们始终将其包含在程序的开头。 您只需要键入函数的名称,然后将其与正确的语法一起使用即可。 Printf,scanf是库函数的示例。
而用户定义的函数必须由用户自己编写函数的主体,并在需要函数的时候执行某些操作调用该函数。
用户定义的函数始终由用户编写,但以后可以成为用户本身项目的库函数的一部分。 这是“ C”编程的主要优点。
在C语言中,编程功能分为三个活动,例如,
- 函数声明
- 函数定义
- 函数调用
函数声明
函数声明是指编写程序的名称。 函数声明会告诉编译器函数名称及如何调用函数。当您在一个源文件中定义函数且在另一个文件中调用函数时,函数声明是必需的。 在函数声明中,我们仅指定要在程序中使用的函数名称和类型;该声明和变量声明一样。 除非在程序中声明了函数,否则我们无法使用它。 函数声明也称为“函数原型”。
语法
return_data_type function_name (data_type arguments);
- return_data_type: 函数的数据类型, 该类型和调用语句所需要的值的数据类型是一样的;
- The function_name: 函数名,后面是小括号
- Arguments 参数 – 名称及其数据类型声明可以选择放在括号内。
在函数声明中,参数的名称并不重要,只有参数的类型是必需的.当您在一个源文件中定义函数且在另一个文件中调用函数时,函数声明是必需的。在这种情况下,您应该在调用函数的文件顶部声明函数。
请记住,函数不一定返回值。 在这种情况下,将使用关键字void。例如,output_message函数声明该函数未返回值, 就可以使用:void output_message();
函数定义
C 语言中的函数定义的一般形式如下:
return_type function_name( parameter list ) { body of the function }
在 C 语言中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:
- 返回类型:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void。
- 函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
- 参数:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
函数主体:函数主体包含一组定义函数执行任务的语句。
函数定义意味着只编写函数的主体。 函数的主体由要执行特定任务的语句组成。 函数主体由一个或一个语句块组成。 它也是函数的必需部分。
实例:
int add(int a,int b) //function body { int c; c=a+b; return c; }
调用函数
创建 C 函数时,会定义函数做什么,然后通过调用函数来完成已定义的任务。每当我们调用函数时,它都会执行为其设计的操作。 函数调用是程序中的可选部分。
当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。
result = add(4,5);
函数定义,函数声明,函数调用的完整的代码:
#include <stdio.h> int add(int a, int b); //function declaration int main() { int a=10,b=20; int c=add(10,20); //function call printf("Addition:%d\n",c); getch(); } int add(int a,int b) //function body { int c; c=a+b; return c; }
函数参数 (Function Arguments)
函数的参数用来通过函数调用接收必要的值。 它们按位置匹配: 第一个参数传递给第一个参数,第二个参数传递给第二个参数,依此类推。
默认情况下,参数按值传递,在该值中将数据副本提供给被调用函数。 实际传递的变量不会更改。我们考虑以下程序,该程序演示了按值传递的参数:
int add (int x, int y); int main() { int a, b, result; a = 5; b = 10; result = add(a, b); printf("%d + %d\ = %d\n", a, b, result); return 0; } int add (int x, int y) { x += y; return(x); }
请记住,传递给add函数的a和b的值不会更改,因为仅将其值传递给了参数x。
实参(argument):
全称为”实际参数”是在调用时传递给函数的参数. 实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。
形参(parameter):
全称为”形式参数” 由于它不是实际存在变量,所以又称虚拟变量。是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数.在调用函数时,实参将赋值给形参。因而,必须注意实参的个数,类型应与形参一一对应,并且实参必须要有确定的值
1. 形参变量只有在被调用时bai才分du配内存单元,在调用结束时,即刻释放所zhi分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。
2. 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。
3. 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。
4. 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
后面需要添加内容例如变量范围,静态变量等。
递归函数
一个函数在它的函数体内调用它自身称为递归调用,这种函数称为递归函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层,当最内层的函数执行完毕后,再一层一层地由里到外退出。
考虑一个数字的阶乘,其计算公式如下6! = 6 * 5 * 4 * 3 * 2 * 1。
重复计算fact*(fact-1)直到fact等于1。
#include <stdio.h> int factorial(int number); int main() { int x = 6; printf("The factorial of %d is %d\n", x, factorial(x)); return 0; } int factorial(int number) { if (number == 1) return (1); /* exiting condition */ else return (number * factorial(number - 1)); }
factorial() 就是一个典型的递归函数。调用 factorial() 后即进入函数体,只有当 n==1 时函数才会执行结束,否则就一直调用它自身。
由于每次调用的实参为 n-1,即把 n-1 的值赋给形参 n,所以每次递归实参的值都减 1,直到最后 n-1 的值为 1 时再作递归调用,形参 n 的值也为1,递归就终止了,会逐层退出。
A. 声明一个函数,该函数接受一个整数参数并返回该参数的阶乘。此函数将调用自身并减少参数值直到退出或达到基本条件为止。 当条件为真时,先前生成的值将彼此相乘,并返回最终的阶乘值。
B. 声明并初始化一个值为“ 6”的整数变量,然后通过调用阶乘函数来打印其阶乘值
考虑下图,以更深入地了解递归机制,该机制包括调用函数自身直至达到基本情况或停止条件,然后再收集先前的值:
数组名作函数参数
数组名可以作函数的实参和形参。如:
main()
{int array[10];
……
……
f(array,10);
……
……
}
f(int arr[],int n);
{
……
……
}
array 为实参数组名,arr 为形参数组名。在学习指针变量之后就更容易理解这个问题了。数组名就是数组的首地址,实参向形参传送数组名实际上就是传送数组的地址,形参得到该地址后也指向同一数组。这就好象同一件物品有两个彼此不同的名称一样。
同样,指针变量的值也是地址,数组指针变量的值即为数组的首地址,当然也可作为函数的参数使用。
举例
float aver(float *pa); main() { float sco[5],av,*sp; int i; sp=sco; printf("\ninput 5 scores:\n"); for(i=0;i<5;i++) scanf("%f",&sco[i]); av=aver(sp); printf("average score is %5.2f",av); } float aver(float *pa) { int i; float av,s=0; for(i=0;i<5;i++) s=s+*pa++; av=s/5; return av; }