既然一维数组和二维数组都介绍过了,那我们就在来一个C语言中的重点,那就是函数,函数在C语言中是非常重要的,它是设计大型程序的基础。
函数的基础概念
什么是函数
- 函数就是被定义的有特定功能的一小段独立程序。函数也被称之为方法。
- 函数是C语言的基本构成单位。
- 函数都是平等的,没有谁比谁更高一级的说法,只有main()稍微特殊一点。
函数可以分为:
标准定义的标准函数
- 符合标准的C编译器必须提供这些函数,函数的行为也要符合标准C语言的定义。
第三方函数库
- 由其他厂商自行开发的C语言函数库,不在标准范围内,能扩充C语言的功能
自定义函数
- 自己编写的函数包装后,也可以称为函数库,供别人使用
学习库函数的时候,我们主要学习的是函数的功能,参数的含义,今天我们主要学习函数是如何定义出来的。
函数的定义
函数的定义规则:
返回值类型 函数名 (参数类型 形式参数名1,参数类型 形式参数名2,...)
{
函数语句
return 返回值;
}
说明:
1.返回值类型:函数调用表达式的值类型,需要和return之后的数据类型一致。假如函数没有返回值,则可以写void在此处。
2.函数类型:形式参数的数据类型,调用函数的时候,可以给函数参数据类型。
3.形式参数名:接到外部数据的变量,可以在函数内部直接使用。加如没有参数的情况,写一个voie即可。
4.return语句:有两个作用,第一个适用于结束函数,第二个是将返回值传递出函数。注:假如函数没有写return,则函数在最后一个}
时结束。
5.返回值,就是函数会返回给调用者的一个数据。假如返回值类型是void的,那么就不用写返回值了,有没有返回值这都是设计者决定的。
我们实现一个函数的一般规则:
1.你必须要明确你实现这个函数的功能是什么???
例如:GetMax的功能就是获取两个数最大值。
2.实现这个功能,我需要些什么参数??
既然是获取两个数中的最大值,我们最起码要给函数两个整数作为参数
3.功能实现完毕,如何告知调用者??
通过return的方式,也可以通过指针。
int GetMax(int numA,int numB)
{
if(numA>numB)
{
return numA;
}
else
{
return numB;
}
}
int main()
{
printf("%d",GetMax(5,7));
return 0;
}
注:什么情况下我么不需要写返回值?结果如何显示?
首先,C语言的语法是支持没有返回值的。
其次,从设计者的角度看,有可能结果就是直接打印到屏幕上,没有什么需要返回的。
比如如下情况:
void fun(void)
{
printf("fun:hello World!!");
}
int main()
{
printf("%d",6+7);
fun();
return 0;
}
函数的调用
按函数在程序中出现的位置来分,可以用以下3种函数调用方式。
函数语句
- 吧函数都调用作为一语句。这是不要求韩素华带返回值,只要求函数完成一定的操作。
函数表达式
- 函数出现在一个表达式中,这种表达式称为函数表达式。这时要求函数待会一个确定的值以参加表达式的运算。
函数参数
- 函数调用作为一个函数的实参
例:当定义在调用之前的时,调用者不需要声明即可调用。
int print_mes(int nNumb,int nNumA)
{
int nTem = nNumb;
nNumb = nNumA;
nNumA = nTem;
return 0;
}
int main()
{
int nNumb = 12,nNumA = 10;
//1.当定义在调用之前时,调用者不需要声明即可调用。
print_mes(nNumb,nNumA);
//2.当函数定义在调用之后的时候,我们需要在调用之前的位置进行函数声明
int FUN(int n,int b,int c);
//可以没有变量的名字,但是必须写出类型int FUN(int ,int int);
//函数调用
FUN(1,print_mes(nNumb,nNumA),3);
//这里将print_mes函数的返回值作为参数传递给了FUN
return 0;
}
int FUN(int n,int b,int c)
{
return 0;
}
函数调用注意事项:
在一函数中调用另一函数的需要满足以下条件;
1.首先我们调用的函数是已经存在的函数(自己定义的或者库中的函数),这是其中条件之一,单单满足这个条件还不够。
2.如果我们调用的函数是库函数,我们需要在预处理的位置将相关的库使用#include
调用相关的库,将函数信息包含到当前文件。
3.如果调用的函数是我们自定义的函数,如果函数定义在我们调用之前,可以直接调用,但是在我们调用之后,我们需要在调用之前进行函数声明。
4.如果我们调用的函数仅仅有声明但是没有实现,在我们编写代码的时候不会报错,但是在编译的时候会报错(无法解析的外部符号)。
5.如果我们使用一个函数的返回值作为另一个函数的参数的时候,我们需要保证函数返回值的类型和参数类型相同。
函数的返回值
通过函数调用使主函数能得到一个确定的值,这就是函数的返回值。
- 函数的返回值是通过函数中的return传递的。
- return语句将被调用的函数中一个确定的值返回主调函数中去。
- 函数指的类型
- 既然返回的是一个值,那就有一个确定的类型,所以在我们定义函数的时候如果有返回值,就一定要指定返回值的类型。
注:return后面可以是变量、常量、表达式、函数。
int print_mes(int nNumb,int nNumA,int nNumB)
{
int nSum = nNumb+nNumA+nNumB;
return nSum;
//如果有返回值,return后面必须要有表达式或变量。
}
int main()
{
int print_mes(int nNumb,int nNumA,int nNumB);
//这里是函数声明
//我们将函数的返回值复制给一个变量
int nSumA = print_mes(12,12,12);
return 0;
}
3.我们定义函数返回值类型的时候,一个情况下都和return值的类型一致。
- 如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以进行自动转换,所以函数类型决定返回值的类型。
int print_mes(int nNumb,int nNumA,int nNumB)
{
int nSum = nNumb+nNumA+nNumB;
//nSum本身的值是一个int类型的值,
//但是返回值的类型定义的是float,所以这个值就自动转换为float类型。
return nSum;
}
int print_mes_a()
{
float fNumb = 20.23,fNumB = 30.22;
return fNumb+fNumB;
//表达式相加时候是float类型,但是相加完return之后就是int类型。
}
int main()
{
float fSumA = print_mes(12,12,12);
int i = print_mes(12,12,12);
int nSumA = print_mes_a();//精度丢失
return 0;
}
- 对于那些不要返回值的函数,我们在对函数进行定义的时候直接定义为void(无类型,空类型)。这样定义后这个函数就不会带任何返回值,即系统禁止函数返回值的使用。
## 形式参数和实际参数
- 我们调用函数的大多数情况主调函数和被调函数之间都会有数据传递。我们在定义函数时候,函数名括号里数据类型加名称的数据称为“形式参数”,简称形参。在我们调用函数的时候,函数名后面括号里跟的是“实际参数”,简称“实参”。
例:
int print_mes(int nNumb,int nNumA)
{
//这里的nNumb,nNumA,nNumB都是形式参数,参数的值由调用函数的时候给定,在没有被调用时候不确定
int nSum = nNumb+nNumA+nNumB;
return nSum;
}
int print_mes_a()
{
float fNumb = 20.23,fNumB = 30.22;
return fNumb+fNumB;
//表达式相加时候是float类型,但是相加完return之后就是int类型。
}
int main()
{
int nNumb = 12,nNumbA = 10,nNumB = 90;
float fSumA = print_mes(nNumb,nNumbA,nNumB);
//此处的nNumb,nNumA,nNumB为实际参数。
//在函数传参的时候,我们传递的可以是变量,表达式,常量或是函数的返回值。
//我们需要注意的是我们的实际参数和定义的形式参数的类型需要一致,
//如果不一致就会强制转换,还有可能会导致报错。
float fSumb = 222.122
//fSumb为float类型,形参为int类型,挥
return 0;
}
2.形式参数和实际参数说明
1.我们定义的形式参数在没有发生函数调用的时候,它不占内存中的存储单元。在发生函数调用的时候,他们才会占用内存中的存储单元,在函数调用结束的时候,形参所占用的空间也被释放。
注:因为当进入被调函数的时候,形参他也是变量,变量需要开辟空间。函数结束形参所占用的内存就被释放。
2.实参可以是变量,常量或表达式。但是他们必须都有确定的值。在函数调用的时候,将实参的值赋值给形参。
3.在被定义的函数中,必须指定形参类型。
4.实参和形参的类型必须形同或者可兼容。
5.实参向形参发生数据传递的时候是“值传递”,单向传递,只由实参传递给形参,不能由形参传递给实参。内存中,实参占用的内存单元和形参占用的内存单元不同。在函数调用的时候,给形参分配存储单元,将实参的值传递到形参,调用结束之后,形参的存储单元被释放,实参不变。因此在调用一个函数的时候,形参如果发生改变,并不会影响主调函数中的实参。
例:通过函数尝试两个数的交换&nNumb的地址为:0x10010
&nNumbA的地址为:0x10005
int print_mes(int nNumb,int nNumbA)
{
int nTem = nNumb;
nNumb = nNumbA;
nNumbA = nTem;
return 0;
}
int main()
{
int nNumb = 12,nNumbA = 10;
print_mes(nNumb,nNumbA);
//最终结果是两个值没有交换
}