栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【C语言基础学习笔记】函数

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【C语言基础学习笔记】函数

文章目录
  • 1. 函数是什么?
  • 2. C语言中函数的分类
    • 2.1 库函数
    • 2.2自定义函数
  • 3.函数的参数
    • 3.1实际参数(实参)
    • 3.2形式参数(参数)
  • 4.函数调用
    • 4.1传值调用
    • 4.2传址调用
    • 4.3 练习
  • 5.函数的嵌套调用和链式访问
    • 5.1 嵌套调用
    • 5.2链式访问
  • 6. 函数的声明和定义
    • 6.1 函数声明
    • 6.2 函数的定义
  • 7. 函数递归
    • 7.1 函数递归的定义
    • 7.2 递归的2个必要条件
    • 7.3 递归与迭代

1. 函数是什么?
  • 一般有输入参数和返回值
  • 函数相较于其他代码,具备相对的独立性
  • 函数是一个大型程序中的某部分代码,负责完成某项特定的任务
2. C语言中函数的分类
  1. 库函数
  2. 自定义函数
2.1 库函数

为什么会有库函数?

  1. 避免代码冗余
  2. 标准化,试想以下每个人都自己写一个printf会怎样
  3. 提高开发效率

库函数怎么学习?推荐以下链接:

  1. https://en.cppreference.com/w/ (C++官网)
  2. https://cplusplus.com/
2.2自定义函数
  1. 找两个数的最大值的函数
  2. swap函数
3.函数的参数 3.1实际参数(实参)

实参:真实传给函数的参数
可以是:

  • 变量
  • 常量
  • 表达式
  • 函数
3.2形式参数(参数)

形式参数:函数被调用的时候被调用,用完就销毁,局部变量来的
形参实例化候就是实参的拷贝

4.函数调用 4.1传值调用
  • 对形参的改变不会改变实参
4.2传址调用
  • 让函数和函数外部的参数建立联系,函数内部可以直接操作函数外的参数
4.3 练习

** 1. 写一个判断一个数是不是素数**

// 练习:写一个函数判断一个数是不是素数
// 0表示是不是素数
// 1表示是素数
int is_prime(int n)
{
    int j = 0;
    for (j = 2; j < n; j++)
    {
        if (n % j == 0)
        {
            return 0;
        }
    }
    return 1;
}

int main()
{
    int i = 0;
    // 打印100~200之间的素数
    for (i = 100; i <= 200; i++)
    {
        if (is_prime(i) == 1)
        {
            printf("%d ", i);
        }
    }

    return 0;
}

** 2. 写一个函数判断一年是不是闰年**
注意:

  • 函数的功能设计尽量要单一,不要在函数里面加其他东西,比如打印之类的
int is_leap_year(int n)
{
    if (((n % 4 == 0)&&(n % 100 != 0))||(n % 400 == 0))
        return 1;
    else
        return 0;
}
int main()
{
    int i = 0;
    // 打印1000~2000之间的闰年
    for (i = 1000; i <= 2000; i++)
    {
        if (is_leap_year(i) == 1)
        {
            printf("%d ", i);
        }
    }
}
**3. 写一个函数,实现一个整型有序数组的二分查找**

注意:
函数传参的时候是传的数组的地址,不是整个数组,所以一定要传数组的大小进binary_search里面,不能在这个函数里面求数组的大小。

// 找不到返回-1
// 找到返回对应的位置
int binary_search(int arr[], int k, int sz)
{
    int left = 0;
    int right = sz - 1;

    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (arr[mid] < k)
        {
            left = mid + 1;
        }
        else if (arr[mid] > k)
        {
            right = mid - 1;
        }
        else
        {
            return left;
        }
    }
    return -1;
}
int main()
{
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int sz = 0;
    sz = sizeof(arr) / sizeof (arr[0]);
    int ret = binary_search(arr, 7, sz);
    if (-1 == ret)
    {
        printf("找不到n");
    }
    else
        printf("找到了,位置是:%d", ret);
    return 0;
}

** 4. 写一个函数,每调用一次这个函数,就会将num的值+1**

void test(int *p)
{
    *p = *p + 1;
}

int main()
{
    int num = 0;
    test(&num);
    printf("%dn",num);
    return 0;
}
5.函数的嵌套调用和链式访问 5.1 嵌套调用

函数可以嵌套调用,但是不能嵌套定义

5.2链式访问

把一个函数的返回值作为另一个函数的参数
例如:将strlen()的返回值作为printf的参数

// 链式访问
int main()
{
    printf("len = %d",  strlen("absd"));
}
6. 函数的声明和定义 6.1 函数声明
  1. 函数形参的名字可以省略
  2. 函数要先声明后使用
  3. 函数的声明一般放到头文件中

例子:Add函数定义在了后面,要在main函数之前声明Add函数才不会报错
一般实际开发不会这样写,这样是我们写比较短的程序的时候才会这样写。

// 函数的声明
int Add(int x, int y);

int main()
{
    int a = 10;
    int b = 20;
    int sum = Add(10, 20); // 函数的使用
    printf("%dn", sum);
    return 0;
}

// 函数定义
int Add(int x, int y)
{
    return x + y;
}

实际开发的时候会这样写:
1.主函数调用add.h头文件,自己定义的头文件用双引号去引

#include "add.h"

int main()
{
    int a = 10;
    int b = 20;
    int sum = Add(a, b);
    printf("%dn", sum);
    return 0;
}

2.在add.h头文件里面声明Add函数

#ifndef TEST_07_07_ADD_H
#define TEST_07_07_ADD_H
// 函数的声明
int Add(int x, int y);

#endif

3.在add.c里面定义Add函数

int Add(int x, int y)
{
    return x + y;
}

如果不愿意公开代码,可以编译成lib文件

6.2 函数的定义

函数的具体实现,交代函数的功能实现

7. 函数递归 7.1 函数递归的定义

1.函数调用自身的变成技巧叫递归
2.一个过程或函数在其定义或说明过程中直接或间接调用自身的一种方法
3.将大事化小,大大减小代码量

7.2 递归的2个必要条件

1.递归结束的条件,满足这个条件的时候,递归就不再继续
2.每次递归调用结束的时候都无限的接近这个结束条件
练习1:接受一个整型值(unsigned),按照顺序打印它的每一位。
分析:print函数用来实现题目要求的功能
思路:比如打印123,那么就先print(12)然后后面再打印一个3,以此类推

void print(int n)
{
    if (n > 9)
    {
        print(n / 10);
    }
    printf("%d ", n % 10);
}
int main()
{
    unsigned int num = 0;
    scanf("%d", &num);
    print(num); // print函数可以把num的每一位按照顺序打印出来
}

练习2:编写函数不允许创建临时变量,求字符串长度

int my_strlen(char *str)
{
    if (*str != '')
    {
         return 1 + my_strlen(str+1);
    }
    else
        return 0;
}

int main()
{
    char arr[] = "abcdef";
    int len = my_strlen(arr);

    printf("%dn", len);
    return 0;
}
7.3 递归与迭代

练习3:求n的阶乘(不考虑溢出)
递归写法

int fac1(int n)
{
    if (n <= 1)
        return 1;
    else
        return n * fac1(n - 1);
}
int main()
{
    int n =0;
    scanf("%d", &n);
    int ret = fac1(n);
    printf("%dn", ret);
    return 0;
}
**非递归(迭代)写法**
int fac(int n)
{
    int i = 0;
    int ret = 1;
    for (i = 0; i < n; i++)
    {
        ret = ret * i;
    }
    return ret;
}
int main()
{
    int n =0;
    scanf("%d", &n);
    int ret = fac(n);
    printf("%dn", ret);
    return 0;
}

练习4:求第n个斐波那契数
斐波那契数:这个数是前面两个数的和
递归实现
缺点:运行的时间需要很长,有大量重复的计算

int fib(int n)
{
    if (n <= 2)
        return 1;
    else
        return fib(n - 1) + fib(n - 2);
}

int main()
{
    int n = 0;
    scanf("%d", &n);
    int ret = fib(n);
    printf("%dn", ret);
    return 0;
}

迭代实现
从前往后算,考虑清楚要有多少次循环

int fib(int n)
{
    int a = 1;
    int b = 1;
    int c = 1;
    
    while (n > 2)
    {
        c = a + b;
        a  = b;
        b  = c;
        n--;
    }
    return c;
}

int main()
{
    int n = 0;
    scanf("%d", &n);
    int ret = fib(n);
    printf("%dn", ret);
    return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1012949.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号