函数
函数,迭代开发,封装成函数,有利于代码的复用性和维护性
要求:内部要尽量少的调用,函数要有独立性
函数调用进行的操作
①通过函数名找到函数入口地址
②给形参分配内存空间
③传值:把实参变量对应空间的值传给形参
④执行函数体里的语句
一.函数三要素:
1.函数名:动词 + 名词 下滑线连接的字符不要超过5个
自注释性(提高代码的可读性)、
2.形参
函数参数的传递
如何确定传值还是传地址?
读(不修改)实参变量对应内存空间的值时,传实参变量名
写(修改)实参变量对应内存空间的值时,传实参变量的地址
3.返回值
3.1函数返回值类型的确定
传整型变量 用整型变量来接
传字符变量 用字符变量来接
传一维数组的地址 用数组元素指针来接
传二维数组的地址用一维数组指针来接
传一维数组的地址用二维数组指针来接
2.不能返回局部变量的地址或指针
3.如何返回多个结果?
利用传出参数
利用全局变量 :因为全局变量的作用域为定义变量开始到程序结束,对于编写多个返回值的C语言函数,我们可以把返回的多个值定义成全局变量,当调用函数时,全局变量被修改,再把修改后的全局变量的值应用于主调函数中,即多个返回值。但使用全局变量时应注意,全局变量的作用域为全局,所以程序范围内都可以修改它的值,如果出现错误,难以发现,而且全局变量增加程序间模块的耦合,所以要慎用
传递数组指针:把多个返回值作为数组元素定义成一个数组的形式,并使该数组的地址作为函数形参,以传址的方式传递数组参数。函数被调用后,形参数组元素改变倒置实参改变,从改变的实参数组元素取得多个返回值。
传递结构体指针:如果返回多个值得数据类型不一样,除使用全局变量以外,也可以是使用结构体。使用方法类似数组指针。
例,编写函数求一维整型数组的最大值与最小值,并把最大值和最小值返回给主调函数(传递数组指针)
#include<stdio.h>
void max_min(int *ret);
int main()
{
int i;
int ret[8];
printf("Please input the param:\n");
for(i = 0;i < 8 ;i++)
{
scanf("%d",&ret[i]);
}
printf("befor int array = ");
for(i = 0;i < 8 ;i++)
{
printf("%d ",ret[i]);
}
putchar('\n');
max_min(ret);
printf("after int array = ");
for(i = 0;i < 8 ;i++)
{
printf("%d ",ret[i]);
}
putchar('\n');
printf("the max param = %d\n",ret[0]);
printf("the min param = %d\n",ret[7]);
return 0;
}
void max_min(int *ret)
{
int i;
for(i = 0; i < 8; i++)
{
ret[0] = (ret[0] > ret[i + 1]) ? ret[0] : ret[i + 1];
ret[7] = (ret[8] < ret[i + 1]) ? ret[8] : ret[i + 1];
}
}
4.return VS exit
return
char *func()
{
char *src = "hello worid";
return src;
}
int main()
{
char *ptr =func();
printf("ptr = %s\n",ptr);
return 0;
}
PS:此程序的src 保存在全局数据区的rodata段,生命周期为程序结束后,不会乱码
若char src[100] = "hello world"; 数组保存在栈空间,生命周期为函数结束后,会有乱码。
主函数的返回值return 0;0 是反馈给系统 主函数结束前返回0,这是一个规范要求 ,可以提高运行效率
exit 用来异常处理时结束整个程序 1 是反馈给用户 命令行敲 echo ¥? 可以打印当前程序结束前的返回值
4.企业级函数的编写
函数的编码规范
十分重要的几点:
对所调用函数的错误返回码要仔细全面的处理
防止将函数的参数作为工作变量
为简单功能编写函数
不要编写依赖于其他函数内部实现的函数
检查所有参数的有效性
函数的入口参数检查
if(src == NULL || dst == NULL)
{
printf("the param is error!\n");
exit(1);
}
函数的返回值异常处理
exit
5.函数指针 函数指针数组
回调函数:函数指针做形参,函数指针指向的函数
引申:用C语言如何实现面向对象:封装 结构体
继承 结构体的包含关系
多态:函数指针
6.函数的可变参数
C语言编程中有时会遇到一些参数个数可变的函数,例如,printf( )函数的函数原型为
int printf( const char* format, ...);
它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的(用三个点“…”做参数占位符),实际调用时可以有以下的形式。
printf("%d",i);
printf("%s",s);
printf("the number is %d ,string is:%s", i, s);
一个简单的可变参数的C函数。先看例子程序,该函数至少有一个整数参数,其后是占位符“…”,表示后面参数的个数不定。在这个例子里,所有的输入参数必须都是整数,函数的功能只是打印所有参数的值,函数代码如下。
示例代码:可变参数函数的使用。
#include <stdio.h>
#include <stdarg.h>
void simple_va_fun(int start, ...)
{
va_list arg_ptr;
int nArgValue =start;
int nArgCout="0"; //可变参数的数目
va_start(arg_ptr,start); //以固定参数的地址为起点确定变参的内存起始地址
do
{
++nArgCout;
printf("the %d th arg: %d",nArgCout,nArgValue); //输出各参数的值
nArgValue = va_arg(arg_ptr,int); //得到下一个可变参数的值
} while(nArgValue != -1);
return;
}
int main(int argc, char* argv[])
{
simple_va_fun(100,-1);
simple_va_fun(100,200,-1);
return 0;
}
下面解释一下这些代码。从这个函数的实现可以看到,我们使用可变参数应该有以下步骤。
(1)在程序中将用到以下这些宏。
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
va在这里是variable-argument(可变参数)的意思,这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件。
(2)函数里首先定义一个va_list型的变量,这里是arg_ptr,这个变量是存储参数地址的指针,因为得到参数的地址之后,再结合参数的类型,才能得到参数的值。
(3)然后用va_start宏初始化(2)中定义的变量arg_ptr,这个宏的第二个参数是可变参数列表的前一个参数,即最后一个固定参数。
(4)然后依次用va_arg宏使arg_ptr返回可变参数的地址,得到这个地址之后,结合参数的类型,就可以得到参数的值。
(5)设定结束条件,这里的条件就是判断参数值是否为-1。注意被调的函数在调用时是不知道可变参数的正确数目的,程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目,在看完这几个宏的内部实现机制后,自然就会明白。