【C语言基础】函数(2)

news2025/6/7 13:41:54

 

        在函数(1)中我们已经讲过了函数的定义,形参与实参,函数的调用,局部变量与栈内存      接下来还有几个要强调的函数相关知识。

一、静态函数

        静态函数是在函数声明前加上关键字 static 的函数。静态函数在C语言中具有以下特点和用法:

        1.作用域限定

        静态函数的作用域仅限于定义它的源文件内部,即只能在同一个源文件中进行调用,无法被其他源文件访问。

        2.隐藏性

        静态函数对于其他源文件是不可见的,因此静态函数可以用于实现私有的辅助函数或内部功能,而不暴露给外部调用者。

        3.避免命名冲突

        使用静态函数可以避免与其他源文件中的同名函数发生命名冲突。

        4.代码模块化

        静态函数可以帮助将代码模块化,将相关的功能和逻辑封装在一个源文件中,提高代码的可读性和维护性。

        示例演示:

#include <stdio.h>

// 静态函数声明
static int add(int a, int b);

int main() {
    int result = add(5, 3);  // 调用静态函数
    printf("结果:%d\n", result);
    
    return 0;
}

// 静态函数的定义
static int add(int a, int b) {
    return a + b;
}

        总结起来,就两点:

        (1)静态函数主要是为了缩小函数的可见范围,减少与其他文件中重名函数冲突的概率。
        (2)静态函数一般被定义在头文件中,然后被各个源文件包含。

二、递归函数

        递归函数是一种函数调用自身的技术,通俗点说,如果一个函数内部,包含了对自身的调用,则该函数称为递归函数。它在解决问题时将复杂的问题分解为相同或类似的子问题。

        1.递归函数的特点如下:

        (1)只有能被表达为递归的问题,才能用递归函数解决。
        (2)递归函数必须有一个可直接退出的条件,否则会进入无限递归。
        (3)递归函数包含两个过程,一个逐渐递进的过程,和一个逐新回归的过程。

        2.递归函数在解决问题时具有的优点和适用场景:

        (1)可读性:递归函数可以以一种自然的、易于理解的方式表达问题的解决方法,特别是对于一些基于自然逻辑的问题。

        (2)代码简洁:递归函数可以用较少的代码来实现复杂的问题。它能够将问题分解为更小的子问题,减少了代码的冗余和重复。

        (3)解决问题的能力:一些问题的最优解可能是通过递归算法实现的。例如,树的遍历、图的搜索等问题常常使用递归来解决。

        示例:

 三、回调函数

        学习回调函数之前需要彻底明白:函数的声明和定义、函数的地址、函数指针的定义、赋值和调用,以及函数指针类型的匹配这些知识点。如果你掌握的不够,先去看看再回来学习回调函数。

        我们先来看一幅图。

         如果仅靠看这幅图就能理解回调函数,那么你一定是天生注定的程序员大牛了,可以直接call一下阿里。开个玩笑,接下来我会让你彻底明白回调,这也是在工中最容易遇到的分工合作实现的前提之一。

        回调函数是一种函数指针的应用,它允许我们将一个函数作为参数传递给另一个函数,从而在需要的时候调用这个函数。回调函数通常用于实现灵活的、可定制的行为,将控制权交给调用者,以便在适当的时候执行特定的操作和传入参数调用相应代码。

        回调函数的一般使用方法或者说流程:

        (1)定义回调函数:首先需要定义一个回调函数,它具有特定的参数和返回值。回调函数的具体功能根据需要来确定。

        (2)传递回调函数:将回调函数作为参数传递给另一个函数。这个函数通常被称为高阶函数或回调函数的调用者。

        (3)回调函数的执行:在适当的时候,高阶函数会调用传递进来的回调函数,以实现特定的操作。

        接下来让我们用一个实例来实践一下,让你彻底掌握回调函数:

#include <stdio.h>

//函数声明
int calc(int (*p)(int, int), int n1, int n2);
int add(int n1, int n2);
int sub(int n1, int n2);


 
int main(int argc, char *argv[])
{
	int ret;
	
	// 做加法运算
	ret = calc(add, 10, 20);
	printf("ret = %d\n", ret);
	
	
	// 做减法运算
	ret = calc(sub, 100, 20);
	printf("ret = %d\n", ret);
	
	return 0;
}
  • 在程序的开头,我们进行了函数声明。声明了三个函数:calcaddsub。这是为了确保在 main 函数中使用这些函数时,编译器已经知道它们的存在和类型。

  • main 函数中,我们定义了一个整数变量 ret,用于存储函数计算的结果。

  • 然后,我们通过调用 calc 函数进行加法运算。将 add 函数作为回调函数传递给 calc 函数,并传入两个操作数 10 和 20。calc 函数会执行传递进来的回调函数,并返回计算结果。最后,我们使用 printf 函数打印结果。

  • 接着,我们通过调用 calc 函数进行减法运算。将 sub 函数作为回调函数传递给 calc 函数,并传入两个操作数 100 和 20。calc 函数会执行传递进来的回调函数,并返回计算结果。最后,我们使用 printf 函数打印结果。

    //回调函数
    // int (*p)(int, int)  函数指针,接收一种算法的函数地址
    // int n1	是函数指针指向函数的第1个参数
    // int n2	是函数指针指向函数的第2个参数
    int calc(int (*p)(int, int), int n1, int n2)
    {
    	return p(n1, n2);
    }
    
    int add(int n1, int n2)
    {
    	printf("-------%s-----------\n", __FUNCTION__);
    	return n1+n2;
    }
    
    int sub(int n1, int n2)
    {
    	printf("-------%s-----------\n", __FUNCTION__);
    	return n1-n2;
    }

  • calc 函数是一个回调函数,它接受一个函数指针 p,以及两个整数 n1n2。该函数将传递进来的函数指针 p 所指向的函数作为回调函数,并传入 n1n2 作为参数,执行回调函数并返回结果。

  • add 函数是一个加法运算的具体实现,接受两个整数 n1n2,并返回它们的和。在这个函数内部,我们打印了一条提示信息。

  • sub 函数是一个减法运算的具体实现,接受两个整数 n1n2,并返回它们的差。在这个函数内部,我们打印了一条提示信息。

        最后总结一下:回调函数是一种函数指针的应用,允许将一个函数作为参数传递给另一个函数,并在需要的时候调用该函数。通过回调函数,可以实现灵活的、可定制的行为,将控制权交给调用者,以便在适当的时候执行特定的操作。回调函数通常用于实现事件处理、异步编程和定制化操作等场景。

四、变参函数

        变参函数是一种特殊类型的函数,它可以接受不定数量的参数。通常,在函数声明时,我们需要指定函数的参数列表,但是对于变参函数,参数列表可以是可变的。

        实现变参函数的一种常见方法是使用标准库提供的stdarg.h头文件中的宏。这个头文件中定义了一些宏,可以在函数内部访问变参列表。

        下面以一个示例来说明变参函数的实现过程:

#include <stdio.h>
#include <stdarg.h>

// 变参函数的实现
int sum(int count, ...)
{
    int result = 0;

    // 定义一个va_list类型的变量,用于存储变参列表
    va_list args;

    // 使用宏va_start初始化变参列表
    va_start(args, count);

    // 通过va_arg宏访问变参列表中的每个参数,并进行相应的操作
    for (int i = 0; i < count; i++)
    {
        int num = va_arg(args, int);
        result += num;
    }

    // 使用宏va_end清理变参列表
    va_end(args);

    return result;
}

int main()
{
    // 调用变参函数sum并传入不定数量的参数
    int total = sum(5, 1, 2, 3, 4, 5);
    
    printf("总和为:%d\n", total);

    return 0;
}

        这个示例中,我们定义了一个名为 sum 的变参函数。该函数的第一个参数 count 表示传入的参数数量,后面使用省略号表示可变数量的参数。

        在函数内部,我们首先声明了一个 va_list 类型的变量 args,用于存储变参列表。然后,使用宏va_start 初始化变参列表,传入 args 和 count 作为参数。接下来,我们使用宏 va_arg 来访问变参列表中的每个参数,并进行相应的操作。在这个示例中,我们将所有参数相加得到结果。最后,我们使用宏 va_end 清理变参列表。

        在 main 函数中,我们调用了 sum 函数并传入5个参数。这些参数会被传递给变参函数 sum 进行求和操作。然后,我们打印出结果。

        通过使用 stdarg.h 头文件中提供的宏,我们可以在变参函数中访问传入的参数,并对其进行相应的处理。

        今天的分享就到这里啦~

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/729504.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

让计算机讲话

std ::cout是什么&#xff1f; 首先 std是命名空间后面会讲。STD&#xff08;standard标准&#xff09; cout和printf就呢让计算机说话 最早的使用打印机&#xff0c; std::cout相当于调用了一个特殊的函数。 后面需要加<<隔开。 知道最基本的知识就OK了 c的风格 函数…

API接口在软件开发中扮演着重要的角色

随着互联网的快速发展&#xff0c;API&#xff08;Application Programming Interface&#xff09;接口在软件开发中扮演着重要的角色。调试API接口是确保系统正常运行的关键步骤之一。本文将介绍如何选择适合的方法进行API接口调试&#xff0c;以确保开发过程的高效进行和应用…

20.光敏传感器

1.光敏传感器介绍&#xff1a; 光敏二极管(光敏电阻),作为光敏传感器&#xff1b;光敏二极管也称光电二极管&#xff1b;光敏二极管与半导体二极管在结构上类似&#xff0c;其管芯是一个具有光敏特征的PN结&#xff0c;具有单向导电性&#xff0c;因此工作时需要加上反向电压。…

【ECharts系列】ECharts 鼠标悬停线格式化

问题描述&#xff1a; 折线图有很多数据&#xff0c;鼠标悬停时&#xff0c;针对X轴&#xff0c;Y轴数据进行格式化&#xff0c;例如X的时间戳&#xff0c;格式化为时分秒&#xff0c;Y轴保留两位小时 希望效果图&#xff1a; 方案1&#xff1a; 在这个示例中&#xff0c;X轴依…

指针进阶(二)

目录 函数指针数组 指向函数指针数组的指针 回调函数 回调函数模拟实现qsort&#xff08;快速排序&#xff09; 整型数组的排序 结构题排序 按年龄排序 按名字排序 模拟实现qsort函数&#xff08;冒泡排序&#xff09; 函数指针数组 数组是一个存放相同类型数据的存储空…

【Linux】gcc/g++的使用 自动化构建工具make/makefile的使用

一.gcc的使用 在学习C语言时&#xff0c;我们了解了预处理阶段要做的事&#xff1a;->预处理 这其中会经历两个阶段&#xff1a;编译和链接 而编译又分为三个阶段&#xff1a;预编译&#xff0c;编译&#xff0c;汇编 通过不同的选项&#xff0c;可以让gcc停在以上相应的阶段…

ArcGis Pro如何通过C#进行插件开发?

文章目录 0.引言1.开发工具准备2.VS&#xff08;C#&#xff09;创建ArcGIS Pro模块加载项3.编译并使用ArcGis Pro插件 0.引言 ArcGIS Pro插件&#xff08;Add-ins&#xff09;可以让用户更加容易的自定义和扩展ArcGIS Pro应用程序&#xff0c;它创建一系列自定义工具提供了一个…

ISO文件boot、dvd、minimal的区别

在centos的下载中&#xff0c;有分为boot、dvd、minimal的iso文件&#xff0c;那么他们之间有什么区别呢&#xff1f; boot.iso 这个版本大小不会超过1G ,只有最基本的启动引导等内容&#xff0c;各类包均需从线上下载&#xff0c;需要快速安装且有可靠网络的前提下&#xff0c…

linux中的数据库

目录 1.安装MySQL 2.创建数据库 3.删除数据库 4.查询创建数据库的语句 5使用数据库的语句 6.查询当前默认的数据库 7.查询使用的编码方式和校验规则 8.创建表的语句 9.表的物理存储结构 10.表的数据类型 11.总结 引言&#xff1a; 数据库是现代应用开发中不可或缺的组…

获取视频 RTMP 推流web播放

工作需要研究下市面上显示实时视频方案。这里介绍下RTMP协议。 需求获取USB摄像头&#xff0c;手机谁摄像头。显示到web网页上。 一、 采集摄像头 这个使用opencvSharp来采集&#xff1a; nuget: var task Task.Run(() >{var capture new VideoCapture(0);VideoCaptur…

PHP实战开发25-电商网站系统缓存设计方案系统讲述

文章目录 一、前言-缓存的作用1.1 提高性能1.2 减轻服务端压力1.3 减少网络流量1.4 改善用户体验1.5 支持离线访问1.6 降低数据传输成本 二、浏览器缓存2.1 强缓存2.2 协商缓存 三、CDN 缓存3.1 使用CDN缓存的好处3.1.1 加速网站加载时间3.1.2 节省服务器带宽3.1.3 提高可用性和…

快速计算多项式相乘系数 FFT快速傅里叶变换

快速计算多项式相乘系数 FFT快速傅里叶变换 快速傅里叶变换(FFT)——有史以来最巧妙的算法&#xff1f; 正常求两个多项式乘积 A ( x ) ∑ i 0 n A i x i , B ( x ) ∑ i 0 n B i x i C ( x ) ∑ i 0 n ∑ j 0 n A i B j x i j A(x)\sum_{i0}^{n}{A_ix^i},B(x)\sum_{…

Java多线程基础-11:工厂模式及代码案例之线程池

在Java中&#xff0c;xx池的概念是很常见的&#xff0c;比如之前遇到过的常量池、数据库连接池等等。 线程池是一种常用的多线程处理方式&#xff0c;它可以重复利用已创建的线程&#xff0c;从而减少线程的创建和销毁开销&#xff0c;并提高程序的性能。 通俗来说&#xff…

【Windows】Redis集群部署

集群是如何进行工作的 Redis采用哈希槽来处理数据与节点之间的映射关系&#xff0c;一个集群共有16384 个哈希槽&#xff0c;每个key通过 CRC16算法计算出一个16bit的值&#xff0c;再对16384取模&#xff0c;得到对应的哈希槽&#xff0c;集群通过维护哈希槽与节点的关系来得…

flutter聊天界面-Text富文本表情emoji、url、号码展示

flutter聊天界面-Text富文本表情emoji、url、号码展示 Text富文本表情emoji展示&#xff0c;主要通过实现Text.rich展示文本、emoji、自定义表情、URL等 一、Text及TextSpan Text用于显示简单样式文本 TextSpan它代表文本的一个“片段”&#xff0c;不同“片段”可按照不同的…

Verilog学习笔记2:反相器

代码&#xff1a; //反相器 timescale 1ns/10ps module inv( A,y); input A; output y; assign y~A; endmodule //testbench module inv_tb;reg A; wire YY;inv inv(.A(A),.y(YY));initial beginA<0;#10 A<1;#10 A<0; #10 A<1;#10 A<0; #10 A<1;#10 A<0;…

从小白到大神之路之学习运维第54天--------ELK日志收集分析

第三阶段基础 时 间&#xff1a;2023年7月6日 地 点&#xff1a;2304教室 授课人&#xff1a;李凤海 参加人&#xff1a;全班人员 内 容&#xff1a; ELK技术堆栈 目录 服务器设置&#xff1a; 部署elasticsearch集群&#xff1a; 配置elasticsearch集群&#xff…

怎样寻找SEO服务商,需要注意那些问题?

网上提供SEO服务的公司或个人多如牛毛&#xff0c;随便在搜索引擎上搜索一下&#xff0c;成千上万的公司就在眼前。大部分网站设计公司也兼职SEO服务&#xff0c;寻找合适的SEO服务商并不简单&#xff0c;鉴别合格的SEO服务商是关键。 1、确定外包任务 如果没有SEO团队&…

C++类相关概念

1. 函数形参默认值 &#xff08;1&#xff09; 建议函数&#xff08;不仅仅是构造函数&#xff09;形参默认值只在函数声明中指定&#xff1b; &#xff08;函数声明和定义写在同一个文件中&#xff0c;则函数声明、定义两者之一或两者都可指定形参默认值&#xff0c;两者都指定…

mybati执行流程源码分析

MyBatis执行流程源码分析 前言 由于之前写过关于mybatis源码的文章,但是感觉还是不够细致,不够完善.没有把一些具体的流程应用写下来,至此又写了一篇.内容可能比较长,希望大家可以打开源码跟着这篇文章一起看源码保证可以收获许多. 1.mybatis基础开发流程 1.引入mybatis相关…