函数

函数 ==》C 语言的重点
函数概念:
在C语言中,具有一定功能,相对独立的程序段(也称为模块)称为函数,函数可有可无返回值
函数作用:
1、提高代码复用率,使代码模块化。
2、规范代码逻辑,控制代码中异常范围。
函数的分类:
1、系统函数
1.1 系统调用函数 ==》open() read() write()
==》man 2 xxx;
1.2 系统库函数 ==》printf() scanf() getchar()
==》man 3 xxx;
2、用户自定义函数 ===》自己编写的函数
函数的组成:
函数的声明、函数的定义

函数的学习重点:
1、函数的定义格式;
2、函数的调用规则;
3、函数的声明语句;
4、函数的参数传递;

函数的定义格式

1、函数的定义格式:
<存储类型> 数据类型 函数名称(形参列表)
{
函数体;
}
eg: int main(int argc ,char * argv[])
{
printf(“nihao\n”);
return 0;
}
注意事项:
1、函数定义的时候,{} 不能省略。
2、函数名称的命名必须符合C语言命名规范。
3、函数的数据类型可以没有,
如果没有则函数体中不需要return xxx,最好在函数定义的时候加 void 说明;
如果有数据类型,就必须加return xxx,而且要保证xxx 的类型与函数数据类型兼容。
函数无法返回数组。
4、函数的参数也可以没有,
如果没有参数,则写void或者什么都不写。
如果有参数,要写参数的类型和名称,如果多个参数用’,'依次隔开。注意函数参数的类型可以不一样。
5、每个xxx.c的源代码文件中只能有一个main函数表示程序执行的入口位置。
6、函数在执行过程中遇到return 关键字则跳出当前函数
*****如果在main函数中return则程序结束。
7、函数在定义过程中尽量不要嵌套定义,一般一个函数
都是独立成为模块。

函数的调用规则

1、函数的定义格式:
<存储类型> 数据类型 函数名称(形参列表)
{
函数体;
}
eg: int main(int argc ,char * argv[])
{
printf(“nihao\n”);
return 0;
}
注意事项:
1、函数定义的时候,{} 不能省略。
2、函数名称的命名必须符合C语言命名规范。
3、函数的数据类型可以没有,
如果没有则函数体中不需要return xxx,最好在函数定义的时候加 void 说明;
如果有数据类型,就必须加return xxx,而且要保证xxx 的类型与函数数据类型兼容。
函数无法返回数组。
4、函数的参数也可以没有,
如果没有参数,则写void或者什么都不写。
如果有参数,要写参数的类型和名称,如果多个参数用’,'依次隔开。注意函数参数的类型可以不一样。
5、每个xxx.c的源代码文件中只能有一个main函数表示程序执行的入口位置。
6、函数在执行过程中遇到return 关键字则跳出当前函数
*****如果在main函数中return则程序结束。
7、函数在定义过程中尽量不要嵌套定义,一般一个函数
都是独立成为模块。

函数的声明语句

C语言中如果调用函数在定义函数之前,在编译的时候会出现错误信息。
为了避免定义前调用的问题,解决方法有两种:
<1> 使每个函数的定义都出现在其调用之前。
<2> 在调用前声明每个函数。
函数声明使得编译器可以先对函数进行概要浏览,而函数的完整定义以后
再出现。

声明的格式:
<存储类型> 数据类型 函数名称(形参列表) ;
eg: extern int printf(const char * format ,…);
注意:
一般函数的声明都在固定的xxx.h文件中,xxx.h一般对应的有一个xxx.c的源文件。
函数的声明过程中可以没有形参名称但是不能没有类型。
函数的声明之后必须有;

ctags

为了解决一个工程文件中的函数快速找到,使用ctags
ctags使用方法
1、在当前工程文件的最上层创建ctags文件
ctasg -R (R递归)会生成tags文件
2、打开要查询的文件vim xxx vim ./xxx/yyy/zzz
3、查找我们当前所需查找的函数名
4、光标移动至要追踪的函数名上,追踪 ctrl+]
5、退回 ctrl+t

return语句

非void的函数必须使用return语句来指定将要返回的值。格式如下 return 表达式;
表达式可以是常量或变量或复杂表达式。 如果return语句中表达式的类型和函数的返回类型不匹配,那么系统
将会把表达式的类型隐士转换成返回类型。
如果没有给处表达式,return语句可以出现在返回类型为void的函数中。

函数传参数

函数传参数
1、 按值传递
2、 按地址传递
3、 按数组传递 ==》特列
4、 全局变量

1、按值传递 ===》形参 每次拷贝 实参的数据值并在函数内部处理
===>数据值的拷贝
*****
适用范围: 每次都是在函数内部对于该数据做运算不需要修改数据本身的值。

2、按地址传递 ===》
将实参的地址传递给形参,在函数内部使用地址形式修改地址相关的变量的内容。本质上还是值传递,只不过传递的值不是数据值而是地址值。
===》swap.c
2.1 用于数据传入:swap(&a,&b); ==>swap要远程操作a地址和b地址的数据。
2.2 用于数据传出 fun_addpoint.c ==>将函数的输入模块封装事先定义变量,在函数中为变量赋值。方便数据传出。

3、传数组 ==》传地址的变形,本质还是传地址。
定义格式: xxx(数组名[], 数组大小);
等价: xxx(指针);
调用格式: xxx(数组名称,大小);
代码:fun_array*.c
4、全局变量 ==》不是传参数,但是能达到同样的效果。
使用环境: 全局开关控制。
一. 全局变量(外部变量)
声明在任何函数体之外的变量是全局变量。
函数可以通过全局变量进行交流。
二. 全局变量的性质
1. 静态存储期限
就如同声明为static的局部变量一样。外部变量拥有静态存储期限。在程序执行期间,存储在全局变量中的值会一直保留。
2. 作用域范围
外部变量拥有文件作用域,从变量声明处开始一直到文件的末尾。跟随在外部变量声明后的所有函数都可以访问此变量。
三. 外部变量的利与弊
在多个函数必须共享一个函数时或者少数几个函数共享大量变量时外部变量是很有作用的。但通过形参进行函数间交流比全局变量的方法更好。原因:
1. 在程序修改期间,如果改变外部变量,那么将需要检查同 一文件中的每个函数,以确认该变化对函数的影响。
2. 如果外部变量被赋予了错误的值,那么它可能很难确定这个有错误值的函数。
3. 很难在其他程序中复用依赖于外部变量的函数。因为依赖全局变量的函数不独立。
注意:
使用外部变量时,要确保他们的名字有意义。

#include <stdio.h>
int test(int a[],int szie,int n)
{
    if(n > size)    return -1;
    if(a == NULL)   return -2;
    int i = 0;
    for( i = 0;i < szie;i++)
        printf("a[%d] = %d \n",i,a[i]);
    return 0;
}
int main(int argc,const char *argv[])
{
    int a[10] = {0,1,2,3,4,5,6,7,8,9};
    int n = 0;
    scanf("%d");
    int ret = test(a,sizeof(a),n);
    if(ret == -1)
        printf("input num error!\n");
    else if(ret == -2)
        printf("diao yong can shu error\n");
    else
        printf("ret = %d\n",ret);
    return 0;
}

szie a.out
txt 文本段
data(以初始化的全剧变量) bss(未初始化的全局变量) 静态区

主函数传参

主函数的写法:
int main(void)
int main()
int main(int argc,const char *argv[])
int main(int argc,const char **argv)

int atoi(const char* nptr);
#include <stdlib.h>
功能:将字符串转换为整形数字
参数:字符串的地址
返回值:成功 整形的数字

函数的递归调用

函数的递归:
在调用一个函数的过程中出现直接或间接调用该函数本身,称为函数的递归

  1. 将一个大的问题分解成比较小的、有着相同形式的问题。“相同形式”是这个定义
    中的关键。递归的特殊之处在于子问题有着和初始问题相同的形式。

  2. 递归解决方案经常称为 分而治之 策略。

    1. 递归算法一般用于解决三类问题:

      <1> 数据定义是按递归定义的。
      <2> 问题解法按递归算法实现。
      <3> 数据的结构形式是按递归定义的。

    2. 递归算法的组成

      一般来说,递归需要有边界条件、递归前进段和递归返回段。

      当边界条件不满足时递归前进;当边界条件满足时,递归返回。,

    3. 递归的基本原理
      <1>每一级的函数调用都有自己的变量。 <2>每一次函数调用都会有一次返回。 <3>递归函数中位于递归调用前的语句和各级被调函数具有相同的执行顺序。
      <4>递归函数中位于递归调用后的语句的执行顺序和各个被调函数的顺序相反。
      <5>虽然每一级递归都有自己的变量,但是函数代码不会得到复制。 <6>递归函数中必须包含终止递归调用的语句。
      01recur_definition.c

    4. 尾递归
      递归调用语句放在函数结尾,return 语句之前,递归调用语句出现在函数部。

例子:
阶乘: factor.c
7. 递归和反向计算
整形数据转换成二进制: binary.c
8. 迭代和递归的区别和各自的优点和缺点

迭代用重复结构,而递归用选择结构。

迭代是逐渐逼近,用新值覆盖旧值,直到满足条件后结束,不保存中间值,空间利用率高。
递归是将一个问题分解为若干相对小一点的问题,遇到递归出口再原路返回,因此必须保
存相关的中间值,这些中间值压入栈保存,问题规模较大时会占用大量内存。

递归的优缺点:
优点:
为某些编程问题提供了最简单的解决方法。
缺点:
一些递归算法会耗尽计算机的内存空间。
一般使用递归的程序难以阅读和维护。

看递归和迭代求1*2*3...*n的过程。
mul(5)
5*mul(4)
5*4*mul(3)
5*4*3*mul(2)
5*4*3*2*mul(1)
5*4*3*2*1
5*4*3*2
5*4*6
5*24
120

使用迭代
1 * 2 = 2
2 * 3 = 6
6 * 4 = 24
24* 5 = 120
#include <stdio.h>

int digui(char *s)
{
    if(*s!='\0')
    {
        s++;
        dufui(s);
     }
     printf("%c",s);
     return 0;
}

int main(int argc,const char* argv[])
{
    char buff[128]={0};

    printf("Please intput string\n");
    scanf("%s",buff);
    digui(buff);
    return 0;
}
int main()
{
    fanzhuan();printf("\n");
    return 0;
}

void fanzhuan()
{
    char c;
    scanf("%c",&c);
    if(c!='\n')
    {
        fanzhuan();
        printf("%c\n",c);    
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值