首页 > 其他分享 >菜鸟日记 之函数

菜鸟日记 之函数

时间:2024-07-13 11:26:10浏览次数:16  
标签:return 函数 int 菜鸟 ret 内存 printf 日记

  • 在C语言中,函数至关重要,函数意味着功能模块,一个典型的C语言程序就是由一个个的功能模块拼接而成的整体。也因为如此,C语言被称为模块化语言。
  • 函数的概念

  • 对于函数的使用者,可以将函数理解为黑箱子,使用者只管按照规定给黑箱一些输入,就会得到一些输出,而不必理会黑箱子里面的运行细节。

  • 函数的定义

函数由函数头和函数体两部分组成。

函数头:相当于函数对外的接口

语法说明

返回值类型 函数名称(输入参数列表) {    C语句,函数功能的具体的实现(函数体)                        ...... } 1.函数名称:命名规则与变量一致,一般取与函数功能相符合的、顾名思义的名称。

2.参数列表:即黑箱的输入数据列表,一个函数可有一个或多个参数,也可以不需要参数。

3. 返回类型:即黑箱的输入数据类型,一个函数可不返回数据,但最多只能返回一个数据

函数体:函数功能的内部实现

  • 示例
写一个函数:求两个给定整数的最大

/*

     max : 求给定两个整数的最大值

    @ a

    @ b

    返回值:

         最大值

*/

int max(int a, int b)

{

      return a > b ? a : b;

}

  • 语法汇总:
1. 当函数的参数列表为 void 时,表示该函数不需要任何参数。 2. 当函数的返回类型为 void 时,表示该函数不返回任何数据。 3. 关键字 return 表示退出函数。①若函数头中规定有返回数据类型,则 return 需携带一个类型与之 匹配的数据;②若函数头中规定返回类型为 void ,则 return 不需携带参数
  • 函数调用

语法说明

函数名(实参列表)//实参:传给函数的值

以取两个数的最大值为例:

#include <stdio.h>
int max(int a, int b)
{
    return a > b ? a : b;
}
int main()
{
    int max_val = max(3, 5);
    printf("最大值是:%d\n", max_val);
    return 0;
}
  • 行参与实参

实参:函数调用时传给被调函数的参数,如上述例子中max(3,5),3,5就是实参。

形参:用于接受调用函数所传数据的参数,如上述例子中max(int a,int b),a,b就是形参。

  • note
  • 形参与实参的类型和个数必须一一对应。
  • 形参的值由实参初始换。
  • 形参与实参位于不同的内存空间,彼此独立。
  • 内存分布

每个C语言进程都拥有一片结构相同的虚拟内存,所谓的虚拟内存,就是从实际物理内存映射出来的地址规范范围,最重要的特征是所有的虚拟内存布局都是相同的,极大的方便内核管理不同的进程。而每个虚拟内存都拥有以下四个区域:

  • 栈(stack)

  • 堆(heap)

  • 数据段 .rodata .data .bss

  • 代码段: .init .text

  • 栈内存

存在于栈内存的有:环境变量,命令行参数,局部变量。

处于栈内存里的变量,空间随函数的释放而释放,栈内存的分配和释放都是由系统规定的,我们无法干预。

  • 静态数据

c语言中,静态数据有两种:

  • 全局变量:定义在函数外的变量

  • 静态局部变量:定义在函数内部,且被static修饰的变量

  • note:

  • 若定义时未初始化,则系统会将所有的静态数据自动初始化为0

  • 静态数据初始化语句,只会执行一遍。

  • 静态数据从程序开始运行时便已存在,直到程序退出时才释放

  • 数据段和代码段
  • 数据段细分成如下几个区域:

    • .bss 段:存放未初始化的静态数据与全局变量,它们将被系统自动初始化为0

    • .data段:存放已初始化的static静态数据与全局变量

    • .rodata段:存放常量数据

  • 代码段细分成如下几个区域:

    • .text段:存放用户代码

    • .init段:存放系统初始化代码

数据段和代码段内存的分配和释放,都是由系统规定的,我们无法干预。

  • 堆内存
  • 堆内存基本特征:

    • 相比栈内存,堆的总大小仅受限于物理内存,在物理内存允许的范围内,系统对堆内存的申请不做限制。

    • 相比栈内存,堆内存从下往上增长。

    • 堆内存是匿名的,只能由指针来访问。

    • 自定义分配的堆内存,除非开发者主动释放,否则永不释放,直到程序退出。

  • 相关函数:

    • 申请堆内存:malloc() / calloc()

    • 清零堆内存:bzero()

    • 释放堆内存:free()

  • 函数指针与指针函数数组

概念:

函数指针变量就是用来保存函数地址的变量。

int func(int a, int b);
// 函数指针,指向的函数类型为返回值为int 参数为(int,int)的函数
int (*pfunc)(int a, int b);

给函数改别名:
以上用来保存函数地址的变量看起来非常冗余复杂,采用改别名的方式可以增强代码的易读性。

eg:
// 此时fptr就相当于void (*fptr)(int *a, int *b)的类型
typedef void (*fptr)(int *a, int *b);// 类似于 int类型 int a = 10

// 函数指针数组,数组存放的是指向返回值为 int 参数为int int类型的函数地址
int (*pfbuf[]) (int,int);

相关习题:

typedef 定义函数指针数组,初始化 sub(减法) div(除法) rem(取余数)

#include <stdio.h>
typedef int (*fpbuf[3])(int, int);
int sub(int a, int b)
{
    return a - b;
}
int div(int a, int b)
{
    return a / b;
}
int rem(int a, int b)
{
    return a % b;
}
int main(int argc, char const *argv[])
{
    int(*pbuf[3])(int ,int) = {sub, div, rem};
    int a, b;
    fpbuf fbuf={sub, div, rem};
    printf("请输入:");
    scanf("%d%d", &a, &b);
    printf("sub=%d\n", pbuf[0](a, b));
    printf("div=%d\n", fbuf[1](a, b));
    printf("rem=%d\n", pbuf[2](a, b));
    return 0;
}

  • 回调函数(钩子函数)

调用一个函数,这个函数传递函数指针,被调用的的这个函数通过这个函数指针进行调用其他函数,我们把这种方式称为回调

eg:

将两数相加设计成回调函数:

callback.c:

#include <stdio.h>
#include "callback.h"
int callback(p_callback_add func)
{
    int a = 10, b = 20;
    return func(10, 20);
}

callback.h:
 

typedef int ( (*p_callback_add)(int,int));//改别名
extern int callback(p_callback_add func);

main.c:

#include <stdio.h>
#include "callback.h"
int add(int a,int b)
{
    return a+b;
}
int main(int argc, char const *argv[])
{
    int ret=callback(add);
    printf("ret=%d\n",ret);
    return 0;
}

  • 内联函数

内联函数的核心在于用空间换时间,当多次调用同一个函数时,很耗时间,这时就可将被调用的函数设置为内联函数以节省调用时间,加快运行效率。

inline注意事项

  • 内联函数在头文件实现,其它函数不要在头文件实现

  • 函数声明和函数实现都需要添加关键字inline,如果函数声明没有添加extern 和 inline 关键字,会报错

demo:
 通过内联函数实现获取两个数的最小值:

main.h:

int min(int a, int b);
inline int min(int a, int b)
{
    return a < b ? a : b;
}

main.c:

#include <stdio.h>
#include "main.h"
int main()
{
    int a=27,b=23;
    printf("min=%d\n",min(a,b));
    printf("min=%d\n",min(a,b));
    printf("min=%d\n",min(a,b));
    printf("min=%d\n",min(a,b));
    return 0;
}

  • 递归函数

概念:如果一个函数内部,包含了对自身的调用,则该函数称为递归函数。

note:

递归函数注意要有明显的结束条件,不然函数会进入无限递归,结束不了。

习题:
幂运算问题:

首先可以写一个非递归实现幂运算:
 

#include <stdio.h>
int main()
{
    int x, n;
    int ret = 1;
    int count = 0;//用以计数与幂指数比较
    printf("请输入:");
    scanf("%d%d", &x, &n);
    if (n == 0)
    {
        ret = 1;
    }
    else
    {
        while (1)
        {

            ret *= x;
            count++;
            if (count == n)
                break;
        }
    }

    printf("ret=%d\n", ret);
    return 0;
}

递归实现幂运算:
 

#include <stdio.h>
float Pow(int x, int n)
{

    if (x == 1 || n == 0)//结束条件
        return 1;
    else if (n == 1 || x == 1)//特殊情况
        return x;
    else
        return x * Pow(x, n - 1);
}
int main()
{
    int x, n;
    float ret;
    printf("请输入:");
    scanf("%d%d", &x, &n);
    if (n < 0)
    {
        ret = 1 / Pow(x, -n);
    }
    else
        ret = Pow(x, n);
    printf("ret=%.4f\n", ret);
    return 0;
}

通过对比递归比非递归,可以发现,用递归实现幂运算更为方便。

标签:return,函数,int,菜鸟,ret,内存,printf,日记
From: https://blog.csdn.net/qq_65363200/article/details/140394427

相关文章

  • C语言菜鸟学习(函数)
    引入C语言本身就是由多个函数模块组成,在C语言本身自带的头文件中,也有很多被封装好的函数,在初学C语言时,我们最先使用的就是使用printf()函数输出一个“helloworld”;而printf()函数就是被封装在#include<stdio.h>头文件中的。但是经过封装的函数我们无法看到源代码,在实际开发中......
  • 20240712总结、视图函数映射报错
    网络ip、端口,服务器人脸识别:1.接口,刚开始以为是调用消费机的接口,后来知道是消费机调用我的接口。2.对Django和Flask框架不熟悉,只会基本结构,Flask多套几层蓝图就懵了。3.对服务器、ip这些不明白,搞不懂消费机是怎么和服务器连上的。好像还用了docker4.对端口不熟悉,我对端口的理......
  • MySQL8.0 新特性函数索引
    MySQL8.0中的函数索引(Function-BasedIndex)是一种高级索引特性,它允许数据库管理员或开发者对表中的列执行表达式计算后的结果进行索引,而不是直接对列值或列的前缀值进行索引。这种索引技术可以显著提高查询性能,特别是在需要对列值进行复杂计算或转换的查询场景中。MySQL8......
  • 类的继承 虚函数 纯虚函数
    定义:classTIme:publicEnt//EntTime是Ent的子集继承Ent类的公开变量//Time可共享Ent,Ent不能共享Time类虚函数:功能:允许在子类中重写方法也就是本例子中的Time类中,在Ent类中重写virtual让它做其他事情例如:classEnt{public: virtualstd::s......
  • 【C语言】字符串与相关操作函数
    字符串思路分析在注释文章目录字符串一、字符串的定义1.使用sizeof()计算他们的长度二、sizeof和strlen的区别1.sizeof操作符2.strlen函数三、动态开辟字符串1.malloc函数2.realloc函数3.free函数4.memset函数四、几种字符串常用的API1.strncpy函数2.asse......
  • 实验9 存储过程与函数的创建管理实验
    一、实验目的:理解存储过程和函数的概念。掌握创建存储过程和函数的方法。掌握执行存储过程和函数的方法。掌握游标的定义、使用方法。二、实验内容1.某超市的食品管理的数据库的Food表,Food表的定义如表所示,Food表的定义各列有如下数据:‘QQ饼干’,‘QQ饼干厂’,2.5,‘2......
  • c语言的简易教法—— 函数递归
    文章目录一、什么是递归?1.1递归的思想1.2递归的限制条件二、递归案例2.1案例1:求n的阶层2.1.1分析2.1.2递归函数(Fact)的代码实现2.1.3测试:main函数实现2.1.4运行结果和画图推演2.1.5扩展:迭代方法求解n的阶乘2.2案例2:顺序打印⼀个整数的每⼀位2.2.1分析2.2.2打印数(p......
  • 如何在函数中使用return返回axios的请求结果
    使用场景:在添加学生上课记录的时候,需要先获取学生的剩余课时,需要通过接口获取。所以需要封装一个方法,能够通过接口获取学生的课时数量。解决方案:通过异步解决封装方法的代码如下:constgetStudentCourseCount=async()=>{letnum=0awaitaxios({method:......
  • 10个Python函数参数进阶用法及代码优化
    目录1.默认参数值:让函数更加灵活2.关键字参数:清晰的调用方式3.*args:拥抱不确定数量的位置参数4.**kwargs:处理不确定数量的关键字参数5.参数解包:简化多参数的传递6.命名关键字参数:限制关键字参数7.局部变量与全局变量:理解作用域8.高级:装饰器(@decorator)9.Lambd......
  • python每日学习4:函数的定义和各类参数定义与用法
    目录目录一、函数的定义二、参数的定义和用法1、必选参数2、默认参数3、可变参数4、关键字参数5、命名关键字参数三、参数在实际操作中的要求一、函数的定义1、函数代码块以def关键词开头,后接函数名称和圆括号()2、在圆括号内定义传入参数3、函数的第一行语句可以......