前言:如果把所有的程序代码都写在一个主函数(main函数)中,就会使主函数变得庞杂、头绪不清,使阅读和维护程序变得困难。此外,有时程序中要多次实现某一功能,如果重新编写实现此功能就会使得程序冗长、不精炼。
怎样定义函数
为什么要定义函数
C语言要求,在程序中所用到的所有函数,必须“先定义,后使用”。例如max函数去求两个数的较大者,必须事先先按规范对它进行定义,指定它的名字、函数返回值类型、函数实现的功能以及参数的个数与类型,将这些信息通知编译系统。这样,在程序执行max时,编译系统就会按照定义时所指定的功能执行。如果事先不定义,编译系统怎么能知道max是什么、要实现什么功能。
定义函数应包括以下几个内容:
- 指定函数的名字,以便以后按名调用
- 指定函数的类型,即函数的返回值类型
- 指定函数的参数的名字和类型,以便在调用函数时向它们传递数据。对无参函数不需要这项。
- 指定函数应当完成什么操作,也就是函数是做什么的,即函数的功能。这是最重要的,是在函数体中解决的。
定义函数的方法:
- 定义无参函数
注:函数名后面括号内的void表示"空",即函数没有参数。
函数体内包括声明部分和语句部分。
- 定义有参函数
类型名 函数名()
{
函数体
}
函数体包括声明部分和语句部分
或
类型名 函数名(void)
{
函数体
}
以下定义的max函数是有参函数:
int max(int x,int y) { int z; //声明部分 z = x > y? x:y; return z;
类型名 函数名(形式参数列表)
{
函数体
}
函数体包含声明部分和语句部分
- 定义空函数
void dummy() //类型名:void,函数名:dummy {}
调用函数
函数调用的形式
函数调用一般形式为:
函数名(实参列表)
- 函数调用语句
把函数调用单数作为一个语句。例如:
void print() { printf("***********\n"); } int main() { print();//此时函数不带回任何值 return 0; }
- 函数表达式
函数调用出现在另一个表达式中,例如c=max(a,b);
max(a,b)
是一次函数调用,它是赋值表达式的一部分。这时函数带回一个确定的值以参加运算。例如:
c = max(a,b);//将a和b中的较大值赋给c值
3.函数参数
函数调用作为另一个函数调用时的实参。例如:
m = max(a,max(b,c));//将b,c中的较大值与a比较,在将他们的最大值赋值给m
函数调用时的数据传递
1.形式参数和实际参数
在调用有参函数时,主调函数和被调用函数之间有数据传递关系。从前面已知:在定义函数时函数名后面括号中的变量名称为"形式参数"(简称形参)或"虚拟参数"。在主函数中调用一个函数时,函数名后面括号中的参数称为"实际参数"(简称实参)。实际参数可以是常量、变量或表达式。
2. 实际参数和形参间的数据传递
在调用函数的过程中,系统会把实参的值传递给被调用函数的形参。或者说,形参从实参得到了一个值。该值在函数调用期间有效,可以参加该函数的运算。
例题:输入两个整数,要求输出其中值较大者。要求用函数来找到大数。
int Max(int x, int y) { return x > y ? x : y; } int main() { int a = 0; int b = 0; scanf("%d %d", &a, &b); int ret = Max(a, b); printf("max = %d\n", ret); return 0; }
运行结果:
函数调用的过程
- 在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数max的形参才被临时分配内存单元。可以通俗的理解成,形参是对实参的一份临时拷贝。
- 将实参的值传递给对应的形参。
- 在执行max函数期间,由于形参已经有值,就可以利用形参进行有关的运算。
- 通过return语句将函数值带回主调函数。且应当注意返回值的类型与函数类型一致。如果函数不需要返回值,则不需要return语句。这时函数的类型定义为void类型。
- 调用结束,形参单元被释放。注意:实参单元仍保留并维持原值,没有改变。
函数的返回值
通常,希望通过函数调用使用主调函数能得到一个确定的值,这就是函数值(函数的返回值)。
- 函数的返回值是通过函数中的return语句获得的。
- 函数值的类型。既然函数有返回值,这个值当然应属于某一个确定的类型,应当在定义函数时指定函数值的类型。
- 在定义函数时指定的函数类型一般应该和return语句中的表达式一致。
习题练习
例题1:写两个函数分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数并输出结果。
int common_divisor(int x, int y) { int max = x > y ? x : y; int min = x < y ? x : y; while (min) { if (x % min == 0 && y % min == 0)//将它们两个数的较小的数往下除 { return min; } min--; } } int common_multiple(int x, int y) { int n = 1; while (n * x % y != 0)//最小公倍数一定是他们两个的倍数 { n++; } return n * x; } int main() { int num1 = 0; int num2 = 0; scanf_s("%d %d", &num1, &num2); int divisor = common_divisor(num1, num2);//最大公约数 int multiple = common_multiple(num1, num2);//最小公倍数 printf("divisor = %d multiple = %d\n", divisor,multiple); return 0; }
运行结果:
例题2:写一个判素数的函数,在主函数输入一个整数,输出是否为素数的信息。
void prime_number(int x)//素数只有1和它本身能被整除 { int flag = 0; int i = 0; if (x == 1)//如果该数是1就直接返回素数 { printf("是素数\n"); } else if (x == 0)//是0就返回不是 { printf("不是素数\n"); } else { for (i = 2; i < x; i++)//从2开始到它本身看是否有能被整除的数 { if (x % i == 0) { flag = 1; break; } } if (flag) { printf("不是素数\n"); } else { printf("是素数\n"); } } } int main() { int n = 0; scanf_s("%d", &n); prime_number(n); return 0; }
运行结果:
例题3:写一个函数,使输入的一个字符串按反序存放,在主函数中输入和输出字符串。
void reverse_arr(char* str, int len)//逆序字符串 { char* left = str;//保存左边的地址 char* right = str + len - 1;//保存右边的地址 while (left < right)//两两进行交换 { char tmp = *left; *left = *right; *right = tmp; left++; right--; } } int main() { char arr[100] = { 0 }; gets(arr); printf("initial:%s\n", arr); int len = strlen(arr); reverse_arr(arr,len); int i = 0; printf("reverse:%s\n", arr); return 0; }
运行结果:
结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。