1、函数的定义:
在维基百科中对函数的定义:子程序
1、在计算机科学中,子程序是一个大型程序中的某部分代码,由一个或多个语句组成。他负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。(如生活中一个大的项目,我们通常把它分成一个个小的模块,分配人员完成)
2、一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。(如:库函数:size_t strlen(const char *str),我们知道strlen是求字符串长度的,但是不知道是怎么具体实现的。)
总结:
①函数可以把相对独立的某个功能抽象出来,使之成为程序中的一个独立实体。可以在一个程序或其他程序中重复使用。
②函数对于构建程序并不是必需的,但却是非常重要的,它极大地增强了代码的模块性,使程序变得更简短、更清晰、更易于开发和维护,提高了代码的重用性。
③提供对过程的封装和细节的隐藏
④函数是C程序的基本功能单元,编写C程序实际上主要就是编写各种各样的函数
特点:简化代码,代码复用
2、函数的分类
(1)库函数
C语言的基础库中提供了一系列库函数,方便程序员进行软件开发。
注:使用C语言库函数时,要用预编译命令“#include”将对应的“头文件”包含到用户源文件中。
就如:生活中你使用别人的东西,要先打招呼!
(2)自定义函数
如果库函数就能把所有事做了,那还要程序员干什么?
所以更加重要的是:自定义函数
自定义函数和库函数一样,有函数名,返回类型和函数参数。
函数的组成:
ret_type fun_name(para,*)
{
statement;//语句项
}
ret_type:返回类型
fun_name:函数名
para:函数参数(注:函数参数之间用逗号隔开)(*就是等等的意思)
函数体:由{}括起来的
3、函数调用
(1)传值调用
实参按照值的方式传递,形参是实参的一份临时拷贝,修改形参不会影响外部的实参
(2)传址调用
实参按照指针方式传递,形参是实参地址的一份临时拷贝,形参指向的是实参,修改形参指针指向的内容,就是在操作实参
总结:传值调用-->形参不影响实参,传址调用-->形参可以影响实参
我们回顾完,接下来用例题来加深理解:
1、乘法口诀
实现一个函数,打印乘法口诀表,口诀表的行数和列数自己指定
如:输入9,输出9*9口诀表,输出12,输出12*12的乘法口诀表。
分析:打印乘法口诀表
①行控制列,
②一行有几列:列数等于行数
③形参不影响实参
所以参数我们只需要传行变量即可
思路:
1、设计函数原型:
①函数(返回)类型:void,不需要返回值,只要打印即可
②函数名:print_table
③参数:int line(line表示乘法口诀总共有多少行)(传值调用)
2、函数体:设定两层循环
①外层循环控制总共有多少行
②内层循环控制每行有几列以及表达式中的内容
代码实例:
#include<stdio.h> //自定义函数--实现打印乘法口诀表 void print_table(int line) { //打印几行 for (int i = 1; i <= line; i++) { //每行打印几列以及表达式内容 for (int j = 1; j <= i; j++) { printf("%d*%d=%d ", i, j, i * j); } //打印完一行换行 printf("\n"); } } int main() { int line = 0;//行 //输入 scanf("%d", &line); //调用函数打印乘法口诀表 print_table(line); return 0; }
2、交换两个整数
实现一个函数来交换两个整数的内容。
分析:
1、形参影响实参(传址调用)
2、函数原型 :
①函数类型:void(只需要互换即可,不需返回值)
②函数名:Swap
③实参:int *a,int *b(传址调用)
3、函数体:实现两个数互换:就如生活中酱油和醋互换
需要注意的就是:要一个中间变量,不能直接互换
代码实例:
#include<stdio.h> //自定义函数--实现两个数的互换 void Swap(int* a, int* b) { int t = *a; *a = *b; *b = t; } int main() { int a = 0; int b = 0; //输入 scanf("%d %d", &a, &b); //调用函数实现互换a与b Swap(&a, &b); //打印交换后的ab printf("%d %d\n", a, b); return 0; }
传值:形参是实参的一份拷贝,函数运行起来后,形参是形参,实参是实参,形参和实参没有任何关联性,改变形 参时,不会对实参造成任何影响。
传地址:形参是实参地址的一份拷贝,形参指向的实体是实参,对形参解引用后,拿到的内容就是实参,因此对形 参解引用之后的内容进行修改,改变的就是实参
代码2:利用全局变量(注意不要传参)
#include<stdio.h> int a = 0; int b = 0; void Swap() { int t = a; a = b; b = t; } int main() { scanf("%d %d", &a, &b); Swap(); printf("%d %d\n", a, b); return 0; }
不建议代码2:因为全局变量在工程中到处都可以使用,很难保证数据的正确性和安全性
3、函数判断闰年
实现函数判断year是不是润年。
思路:
1、函数原型设计:bool is_leap_year(int year)
①函数类型:布尔类型,必须要有返回值,才知道是不是闰年
②函数名:is_leap_year
③参数:int year(形参不影响实参,传值调用)
2、函数体:判断是不是闰年
闰年的判断条件:
①四年一闰百年不闰:即如果year能够被4整除,但是不能被100整除,则year是闰年。
②每四百年再一润:如果year能够被400整除,则year是闰年
加油站:布尔类型
1、布尔类型是C99中引入的
2、布尔类型就是专门用来表示真假的类型
3、真:true(本质是1),假:false(本质是0)
4、头文件:“stdbool.h”
代码实例:
#include<stdbool.h>//预处理,对bool的声明 #include<stdio.h> //自定义函数--实现判断year是不是闰年 bool is_leap_year(int year) { if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { return true; }//是闰年返回true else { return false; }//不是闰年返回false } int main() { int year = 0;//年份 //输入 scanf("%d", &year); //调用函数判断year是否为闰年 bool ret = is_leap_year(year); if (ret) { printf("%d是闰年\n", year); } else { printf("%d不是闰年\n", year); } return 0; }
4、函数判断素数
实现一个函数,判断一个数是不是素数。
利用上面实现的函数打印100到200之间的素数。
知识点:
1、质数:只能被1和它本身整除的数
2、判断质数的方法:试除法,判断n是否为质数
①n是否能整除2到n-1
②第二大的因数i<=n/2:n是否能整除2到i
③n是否能整除2到开平方n
以上三种方法均可判断素数。
思路:
1、设计函数原型:bool is_prime(int n)
①函数类型:布尔类型,函数调用完要返回true或false才知道是不是素数
②函数名:is_prime
③参数:int n(传值调用)
2、函数体:判断n是否为素数(我们就选用方法③为例)
代码实例:
#include<stdio.h> #include<stdbool.h> #include<math.h> //自定义函数--判断一个数是不是素数 bool is_prime(int n) { //n是否能整除2到开平方n for (int i = 2; i <= sqrt(n); i++) { if (n % i == 0) { return false; }//能整除返回假, } //都不能被整除,说明是素数,返回真 return true; } int main() { int i = 0; //从100遍历到200 for (i = 100; i <= 200; i++) { //调用函数判断当前数据是否为素数,是则打印 if (is_prime(i)) { printf("%d ", i); } } //打印完换行 printf("\n"); return 0; }