C学习笔记(十二)函数详解

来源:互联网 发布:知乎 女神 豆瓣 编辑:程序博客网 时间:2024/05/17 02:51

函数

 

函数,迭代开发,封装成函数,有利于代码的复用性和维护性

要求:内部要尽量少的调用,函数要有独立性

 

函数调用进行的操作

①通过函数名找到函数入口地址

②给形参分配内存空间

③传值:把实参变量对应空间的值传给形参

④执行函数体里的语句

 

一.函数三要素:

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。注意被调的函数在调用时是不知道可变参数的正确数目的,程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目,在看完这几个宏的内部实现机制后,自然就会明白。










0 0
原创粉丝点击