C语言之函数

一、函数的分类

函数主要分为两大类:库函数和自定义函数。
1.库函数

-库函数,我们可以根据它的名字来理解,即就是函数的仓库,但这个仓库比较特殊,不是我们平时可以随便乱动的,它是由程序员们自己建立的一个仓库,这个仓库里放着很多程序员们大多认为比较常用的、基础的、在开发过程中很有可能用到的函数介绍和函数代码。我们平时想用的时候就不需要自己去写详细的代码实现,而是可以直接用它的接口调用它们,这样不仅节省了我们写代码的时间,更加会缩短了代码的长度。

  • 学习库函数的网站一般有两种http://www.cplusplus.com 和 https://en.cppreference.com
  • 如我们下面用strlen这个库函数举个例子:
  • 在这里插入图片描述
    根据上面图片(在http://www.cplusplus.com中查找strlen这个库函数)显示,该函数是包在头文件<string.h>中的,返回的是一个字符串的长度。
//具体实例
#include <stdio.h>
#include <string.h>

int main()
{
    char arr[] = "hello sheena"
    printf("%d\n", strlen(arr));//结果是12.
    return 0;
}

2.自定义函数
①自定义函数的基本理解

  • 自定义函数,我们可以根据它的名字来理解,自己定义的函数,就是我们自己写的函数。
  • 自定义函数由函数名、参数、返回类型三部分组成。
  • 自定义函数与库函数不同的是,需要我们自己写函数体。
  • 如我们接下来就写一个获取两个整数的较小值的函数。
//两个数的较小值的函数的演示
#include <stdio.h>
#include <stdlib.h>

int get_min(int x, int y)
{
   return (x < y) ? (x) : (y);
}
int main()
{
   int a = 90;
   int b = 100;
   int min = 0;

   min = get_min(a, b);
   printf("较小的是:%d\n", min);//结果W为90.
   system("pause");
   return 0;
}

②自定义函数的定义与调用

  • 根据①中我们知道函数由函数的名称、函数的参数和函数的返回值类型三部分组成的,故定义一个函数需要确定这三个部分。
  • 上面我们写的获取两者之中较小值的代码中,我们写的函数如下:
int get_min(int x, int y)
{
   return (x < y) ? (x) : (y);
}

//min = get_min(a, b);
  • 这个函数的名称是 get_min
  • 这个函数的传入的参数是 int x和int y,在C语言中称为形参(形式参数:是函数名后括号中的参数,只有在函数调用的时候才会被实例化(调用的时候才开辟空间分配内存单元),在函数调用完毕后就会被销毁。)。 而我们在main函数中a和b是传给函数的参数,在C语言中称为实参(实际参数:真实传给函数的参数,在调用函数的时候,它们必须有确定的值。)。
  • 这个函数的返回值类型是 int 类型的。返回值需要一个int类型的值接收它,故我们在main函数中用int类型的min来接收该函数的返回值。

③函数的传值和传址调用

#include <stdio.h>
#include <stdlib.h>

//传值调用
void Swap1(int x, int y)
{
    int tmp = x;
    x = y ;
    y = tmp;
}

//传址调用
void Swap2(int *x, int *y)
{
    int tmp = *x;
    *x = *y;
    *y = tmp; 
}

int main()
{
   int a = 0, b = 1;
   int c = 0, d = 1;
 
   Swap1(a, b);
   Swap2(&c, &d);
   
   printf("a=%d,b=%d\n",a, b);//结果为a=0,b=1
   printf("c=%d,d=%d\n",c, d);//结果为a=1,b=0
   
   system("pause");
   return 0;
}
  • 我们知道形参是只有在函数调用的时候才会被实例化,调用的时候才会开辟空间分配内存单元。对于Swap1函数中的形参x和y它们只是在Swap1函数开始调用的时候才会被创建,它们的值是等于传进来的a和b的值0和1,但是在Swap1函数内部交换的仅仅是x和y的值,当Swap1函数运行完毕后,x和y就会销毁,a和b的值依旧等于0和1,并没有改变,x和y是两块新的独立的内存空间,与a和b并没有关系,四者之间的唯一联系就是x和a的空间里存放的值是相同的,y和b的空间里存放的值是相同的。

  • 对于Swap2函数而言,它的形参是两个指针x和y,它们也是在Swap2函数开始调用的时候才会被创建,但是它们的两个空间中存放的是a和b两个空间的地址,在Swap2函数内部交换的并不是x和y的值,而是x和y的值,先用a和b的地址找到了a和b,然后将这两个空间里的值给交换了,即使当Swap2函数运行完毕后x和y的空间被销毁也没有关系,因为a和b的值已经被交换了。

  • 总结,当函数内部要改变函数外部的某个变量,需要传地址而不可以简单的传值。

3.函数的递归

  • 函数的递归分为回溯和递推两个阶段。回溯是指一次此重复,直到一个结束条件结束重复。而递推是指回溯结束之后往回推。
  • 函数的递归是指函数自己调用自己。
  • 函数递归有两个必要条件,分别是存在限制条件(当满足这个条件时,就结束回溯,递归不再继续。)和每次递归调用之后越来越接近这个限制条件。
    如:按顺序打印一个无符号整型的每一位
#include <stdio.h>
#include <stdlib.h>

void print(int n)
{
    if(n > 9)
        print(n / 10);
    printf("%d ", n % 10);
}
int main()
{
    unsigned int a = 1234;
    print(a);//1 2 3 4
    system("pause");
    return 0;
}
  • 就上面的例子而言,当1234进入函数print后,先要执行if(n > 9),这条语句,第一次进去 1234 > 9,故执行if条件语句内部的print(n / 10)这条语句,不难发现,这条语句就是递归开始了,在print函数内部调用print函数,此时第二次调用print函数,进去的n不再是1234,而是123,依然先判断是否大于9,123 > 9,故执行if内部的语句,执行print(n / 10)这条语句。第三次调用print函数,此时进去的n是12,12依然大于9,第四次调用print函数,此时进去的n是1。因为1 < 9 ,就不在执行print(n / 10)该条语句,此时回溯结束了,开始递推。第四次调用print函数1进去后执行printf("%d “, n % 10)该条语句,打印出1,结束第四次调用。然后递推回第三次调用print函数内部的print(n / 10)该条语句处,开始往下继续执行printf(”%d “, n % 10)该条语句,因为第三次调用print函数时进去的n是12,故打印出2,结束第三次调用。继续递推回第二次调用print函数内部的print(n / 10)该条语句处,开始往下继续执行printf(”%d “, n % 10)该条语句,因为第二次调用print函数时进去的n是123,故打印出3,结束第二次调用。最后递推回第一次调用print函数内部的print(n / 10)该条语句处,开始往下继续执行printf(”%d ", n % 10)该条语句,因为第一次调用print函数时进去的n是1234,故打印出4,结束第一次调用。最终print函数调用完全结束,综合每次打印的结果,最终打印出的结果将是1 2 3 4 。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值