11.函数(核心中的核心)
11.1.明确:任何C程序,C源文件都包含两部分内容:一堆的变量(包括数组)和一堆的函数)
11.2.函数概念:函数就是一堆语句的组合,用以实现一些相对独立并且具有一定通用性的功能
问:为何需要函数这个技术?
答:举例子
用户要求:实现两个正数相加
vim main1.c
int main(void)
{
int a;
int b;
int sum = 0;
scanf("%d%d", &a, &b);
if(a < 0 || b < 0) {
printf("请重新输入正数.\n");
return -1; //让程序结束,不能继续运行
}
//只有输入的数是正数才能加
sum = a + b;
printf("sum = %d\n", sum);
return 0;
}
vim main2.c
int main(void)
{
int a;
int b;
int sum = 0;
scanf("%d%d", &a, &b);
if(a < 0 || b < 0) {
printf("请重新输入正数.\n");
return -1; //让程序结束,不能继续运行
}
//只有输入的数是正数才能加
sum = a + b;
printf("sum = %d\n", sum);
return 0;
}
vim add2.c ....add250.c :以上代码写250遍(有病!)
分析结论:明显以上代码极其的繁琐啰嗦,代码重复重复的编写,加大开发的工作量
期望:只需将以上重复的代码写一遍即可,其他文件只需使用即可,减少开发的工作量
问:如何实现呢?
答:目前采用函数这个技术
终极解决方案:
vim add.c
//编写一个加法函数add
int add(int x, int y)
{
if(x < 0 || y < 0) {
printf("请重新输入正数.\n");
return -1; //让程序结束,不能继续运行
}
//只有输入的数是正数才能加
sum = a + b;
printf("sum = %d\n", sum);
return sum;
}
vim main1.c
int main(void)
{
int a;
int b;
int sum = 0;
scanf("%d%d", &a, &b);
sum = add(a, b);
return 0;
}
vim main2.c
int main(void)
{
int a;
int b;
int sum = 0;
scanf("%d%d", &a, &b);
sum = add(a, b);
return 0;
}
vim main3.c ....main250.c 只需很轻松的用add函数即可
11.3.函数特点:
a.由一条或者多条语句组成
b.可以重复使用
11.4.函数使用三步骤(剑客):
a)函数声明:
1.函数声明的功能:告诉gcc编译器,将来这个函数可以给别人或者自己使用
函数声明是不分配内存空间的
2.函数声明的语法:extern 返回值数据类型 函数名(形参表);
建议:函数声明加extern(提高代码的可读性),理论上可以不加
3.函数声明特点:
a.如果函数定义在函数调用之前,可以省略函数声明,否则必须声明
b.该声明的没有声明,那么编译器gcc就会给个默认的函数什么,形式:
extern int 函数名(); //以后别这么干
c.函数名的命名遵循标识符的命名规则
b)函数定义:
1.函数定义功能:就是一个函数的具体实现过程,里面会包含一堆的语句
将来可以给别人或者自己使用
函数定义会分配内存
2.函数定义的语法:bd
返回值数据类型 函数名(形参表)
{
一堆的函数体语句;
} //花括号的作用就是圈语句用
例如:
int add(int x, int y) //x=100,y=200
{
return x + y;
}
x = 250; //报错
y = 251; //报错
int main(void)
{
sum = add(100, 200) = 300; //main函数使用add函数
return 0;
}
3.函数定义特点:
1.返回值数据类型:就是函数运行完毕要给使用这个函数的代码返回一个数字
那么这个数组必然有对应的数据类型
如果函数没有返回值,返回值数据类型用void关键字
2.形参表:就是一堆的变量定义,这些变量只能在这个函数体内部使用,出了函数就不能用
形参的值由使用这些函数的代码来赋值,形参的变量有多个,用逗号,分开
如果使用函数的代码不想给函数传递参数,函数定义的时候形参表写void
建议:形参表变量定义的个数不要超过4个,要小于等于4个,否则影响函数使用效率
例如:
int add(int x, int y, int z, int m) {} //漂亮
int add(int x, int y, int z, int m, int n) {} //代码的执行效率降低
3.函数的返回值:
如果函数需要返回一个数字,用关键字return,例如:return 返回值
切记:如果忘记了写return 返回值,gcc将来会返回一个随机数(非常可怕)
注意:返回值的数字的类型和函数定义时的返回值数据类型要一致。如果不一致,会进行隐式转换,可能造成数据的丢失
例如:int add(int x, int y)
{
int sum = x + y;
return sum;
}
如果函数没有返回值,可以不用写return或者写return后面不加内容!
例如:void add(int x, int y)
{
printf("%d\n", x+y);
return; //或者不写
}
c)函数调用:
1.函数调用功能:俗称使用函数,调用函数,访问函数
2.函数迪用语法:接收函数返回值的变量 = 函数名(实参表);
3.函数调用特点:
实参表:就是给函数的形参表赋的值
例如: sum = add(100, 200);//100,200就是实参,将来给add函数的x,y
实参的内存空间和形参的内存空间是独立的,地址是不一样的,但是里面存储的数据是一样的!
d)函数使用的形式:
形式1:无参无返回值
例如: void 函数名(void)
{
函数语句;
}
形式2:无参有返回值
例如:int 函数名(void)
{
函数语句;
}
形式3:有参(1个形参)无返回值
例如:void 函数名(int x)
{
函数语句;
}
形式4:有参(多个形参,建议小于等于4个)无返回值
例如:void 函数名(int x, int y, int m, int n)
{
函数语句;
}
形式5:有参有返回值
例如:int 函数名(int x, int y, int m, int n)
{
函数语句;
}
形式6:参数不定有返回值(不建议这么做)
例如:int 函数名()
{
函数语句;
}
e)return关键字和exit函数
return关键字:实现函数返回
exit函数:让程序强制结束,为了使用此函数需要添加头文件:#include <stdlib.h>
f)实参和形参的关系
形参就是实参的一份拷贝,实参给形参传递参数时,就是将实参里面的数字拷贝一份给形参