7.c语言函数
7.1.1 初见函数
- 引入:
- 将代码中重复操作的部分,定义为自己的函数,在下面代码中进行操作.
//求出1到10,20到30,35到45的三个和: #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { int i; int sum; for (i = 1, sum = 0; i <= 10; i++) { sum += i; } printf("%d到%d的和是%d\n", 1, 10, sum); for (i = 20, sum = 0; i <= 30; i++) { sum += i; } printf("%d到%d的和是%d\n", 20, 30, sum); for (i = 35, sum = 0; i <= 45; i++) { sum += i; } printf("%d到%d的和是%d\n", 35, 45, sum); return 0; }
ps:代码复制是代码质量不良的表现,并且不容易修改.
可写成:
void sum(int begin, int end)
{
int i;
int sum = 0;
for (i = begin; i <= end; i++) {
sum += i;
}
printf("%d到%d的和是%d\n", begin,end, sum);
}
int main()
{
sum(1, 10);
sum(20, 30);
sum(35, 45);
return 0;
}
ps:调试时用f8单步进入
7.1.2 函数的定义和使用
- 什么是函数?
- 函数是一块代码,接收零个或者多个参数,做一件事情,并返回零个或一个值.
- 可以想象为数学中的函数:y=f(x)
- 函数定义:
- void(
返回类型
) sum(函数名
)(int begin, int end)(参数表
)
//第一行为函数头
{
int i;
int sum = 0;
for (i = begin; i <= end; i++) {
sum += i;
}
printf(“%d到%d的和是%d\n”, begin,end, sum);
}// {}里面内容为函数体
//void表示不返回任何东西
- void(
- 调用函数:
函数名(参数值);
- ()起到了表示函数调用的重要作用
- 即使没有参数也需要()
- 如果有参数,则需要给出正确的数量和顺序
- 这些值会被按照顺序依次来初始化函数中的参数
#include<stdio.h>
//void表示返回类型为空
//()里是空的,表示这个函数不接受任何参数
void cheer()
{
printf("cheer\n");
}
int main()
{
cheer;//结果并没有任何输出
cheer();
return 0;
}
int max(int a,int b)
{
int ret;
if (a > b) {
ret = a;
}
else {
ret = b;
}
return ret;
}
int main()
{
int a, b, c;
a = 5;
b = 6;
c = max(10, 12);
c = max(a, b);
c = max(c, 23);
printf("%d\n", max(a, b));
return 0;
}
- 一个函数里面可以出现很多return语句,但不符合单一出口,而且修改起来麻烦
int max(int a,int b)
{
int ret;
if (a > b) {
return a;
}
else {
return b;
}
}
- 从函数中返回值:
- 可以赋值给变量
- 可以再传递给函数
- 甚至可以丢弃
- 没有返回值的函数:
- void函数名(参数表)
- 不能使用带值的return
- 可以没有return
- 调用的时候不能做返回值的赋值
- 如果函数有返回值,则必须使用带值的return
7.2.1 函数原型
- 构成:
- 由
函数头
以分号";
"结尾
- 由
- 目的:
- 告诉编译器这个函数长什么样子
- 名称
- 参数(数量及类型)
- 返回类型
- 告诉编译器这个函数长什么样子
- 函数先后关系:
- 像这样把sum()写在上面,是因为:
- C的编译器自上而下顺序分析你的代码
- 在看的sum(1,10)的时候,它需要知道sum()的样子,也就是说sum()要几个参数,每个参数的类型如何,返回什么类型,这样它才能检查你对sum()的调用是否正确
- 如果不知道:
- 把函数放到下面会出错
形式:
void sum(int begin, int end)
{
int i;
int sum = 0;
for (i = begin; i <= end; i++) {
sum += i;
}
printf("%d到%d的和是%d\n", begin,end, sum);
}
int main()
{
sum(1, 10);
sum(20, 30);
sum(35, 45);
return 0;
}
- 形式改变:
void sum(int begin, int end);//`原型声明(声明不是函数,只是告诉编译器sum是个函数)
int main()
{
sum(1, 10);//到里面后根据声明来判断对sum的调用是否正确
sum(20, 30);
sum(35, 45);
return 0;
}
//函数定义
void sum(int begin, int end)
{
int i;
int sum = 0;
for (i = begin; i <= end; i++) {
sum += i;
}
printf("%d到%d的和是%d\n", begin,end, sum);
}
//声明可用来检查是否与下面内容是否一致
7.2.2 参数传递
- 如果函数有参数,调用函数时必须传递给它数量,类型正确的值
- 可以传递给函数的值是表达式的结果,这包括:
- 字面量
- 变量
- 函数的返回值
- 计算的结果
int a,b,c; a=5; b=6; c=max(10,12);//10,12字面量 c=max(a,b);//a,b变量 c=max(c,23); c=max(max(23,45),a);max(23,45)函数的返回值 c=max(23+45,b);//23+45计算的结果
- 类型不匹配?
- 调用函数时给的值与参数的类型不匹配是C语言传统上最大的漏洞
- 编译器总是替你把类型转换好,但这很可能不是你所期望的
#include<stdio.h>
void cheer(int i)
{
printf("cheer%d\n", i);
}
int main()
{
cheer(2.4);
return 0;
}//结果cheer2
- 后续的语言,C++/Java在这方面很严格
- 调用函数的时候传过去的是什么?
- C语言在调用函数时,永远只能传值给函数
#include<stdio.h>
void swap(int a, int b);
int main()
{
int a = 5;
int b = 6;
swap(a, b);//swap交换
printf("a=%d b=%d\n", a, b);
return 0;
}
void swap(int a, int b)
{
int t = a;
a = b;
b = t;
}
- 传值:
- 每个函数有自己的变量空间,参数也位于这个独立的空间中,和其他的函数没有关系
- 过去,对于函数参数表中的参数,叫做"
形式参数
",调用函数时给的值,叫做"实际参数
" - 由于容易让初学者误会实际参数就是在函数中进行计算的参数,误会调用函数的时候把变量而不是值传进去了,所以并不建议用这种古老的 方式来称呼它们
- 我们认为,它们是
参数
和值
的关系
7.2.3 本地变量
- 函数的每次运行,就产生了一个独立的变量空间,在这个空间中的变量,是函数这次运行所独有的,称作本地变量
- 定义在函数内部的变量就是本地变量
- 参数也是本地变量
- 变量的生存期和作用域:
- 生存期:
- 什么时候这个变量开始出现了,到什么时候它消亡了
- 作用域:
- 在(代码)什么范围内可以访问这个变量(这个变量可以起作用,)起作用的领域
- 对于本地变量,这两个问题的答案是统一的:大括号内-块
#include<stdio.h>
void swap(int a, int b);
int main()//有自己的变量空间,下面是进入swap的变量空间,对本空间的值进行操作,并不会影响下面的
{
int a = 5;
int b = 6;
swap(a, b);//swap交换
printf("a=%d b=%d\n", a, b);
return 0;
}
//ab存在,xy不存在;进入swap里面xy存在,ab留在原地,作为生存来说还在,就作用来说不在
void swap(int x, int y)//进入大括号里了
{
int swap;
int t = x;//
x = y;
y = t;
}
- 规则:
- 本地变量是定义在快内的
{
int a = 5;
int b = 6;
swap(a, b);
if (a < b)
{
int i = 10;//在这个块内i的生存期和作用域都存在,但受ab影响
}
printf("a=%d b=%d\n", a, b);
return 0;
}
-
- 它可以是定义在函数的快内
- 也可以定义在语句的快内
- 甚至可以随便拉一堆大括号来定义变量
- 程序运行进入这个块之前,其中的变量不存在,离开这个块,其中的变量就消失了
- 在块外面定义的变量在里面任然有效
- 块
里面
定义了和外面同名的变量则掩盖
了外面的 - 不能在同一个块里定义同一个变量
{ int a = 5; int b = 6; swap(a, b); if (a < b) { int i = 10; printf("%d", a); //int a=0; ///int a=10; } printf("a=%d b=%d\n", a, b); return 0;
}
``
-
- 本地变量不会被默认初始化
- 参数在进入函数的时候就被初始化了,调用函数的时候给参数一定的值,那个值在进入函数的时候来初始化参数.
7.2.4 参数庶事
- 没有参数时
void (void);
(一般写这个) 还是void ();- 在传统c中,它表示f函数的参数表未知,并不表示没有参数
#include<stdio.h> void swap(void); int main()//有自己的变量空间,下面是进入swap的变量空间,对本空间的值进行操作,并不会影响下面的 { int a = 5; int b = 6; swap(a, b); if (a < b) { int i = 10; //printf("%d", a); } printf("a=%d b=%d\n", a, b); return 0; } //ab存在,xy不存在;进入swap里面xy存在,ab留在原地,作为生存来说还在,就作用来说不在 void swap(int x, int y)//进入大括号里了{ int swap; int t = x;// x = y; y = t; }
- 逗号运算符
- 调用函数时的逗号和逗号运算符怎么区分?
- 调用函数时的圆括号里的逗号是标点符号,不是运算符
- f(a,b)//标点符号
- f((a,b))//逗号运算符
- 调用函数时的逗号和逗号运算符怎么区分?
- 函数里的函数?
- c语言不允许函数嵌套定义,只能放另一个函数声明,不能放定义
- 这是什么?
- int i,j,sum(int a,int b);//定义了int型的变量ij,声明说sum函数要两个int作为参数,并且返回一个int(不建议,但是可以这样写)
- return (i);//不要这么写
- 关于main
- int main()也是一个函数
- 要不要写成int main(void)?-可以写
- return的0有人看吗?
- 对于不同软件结果显示不一样,是有效果的
- Windows:if error level 1…
- Unix Bash:echo $?
- CSh:echo$status
- 一个程序返回0,表示说他正常的运行结束了,返回非0的值表示在这个程序运行过程中出现了错误