于灵动的变量变幻间:函数与计算逻辑的浪漫交织(下)
大家好啊,我是小象٩(๑òωó๑)۶
我的博客:Xiao Xiangζั͡ޓއއ
很高兴见到大家,希望能够和大家一起交流学习,共同进步。
这一节我们主要来学习单个函数的声明与定义,static和extern…
这里写目录标题
- 一、单个函数的声明与定义
- 1.1 单个文件
- 1.2 多个文件
- 二、static和extern
- 2.1 作用域和生命周期
- 2.2 static
- 2.3 static修饰局部变量
- 2.4 static修饰全局变量(extern声明外部符号)
- 2.5 static修饰函数
- 三、结尾
一、单个函数的声明与定义
1.1 单个文件
一般我们在使用函数的时候,直接将函数写出来就使用了。
咱们举之前练习过的一个例子来看,比如写一个函数判断一年是否是闰年。
#include<stdio.h>
int pan_duan_run_nian(int x)
{if ((x % 4 == 0) && (x % 100 != 0) || (x % 400 == 0))return 1;elsereturn 0;
}int main()
{int year = 0;scanf("%d", &year);int a = pan_duan_run_nian(year);if (a == 1){printf("%d为闰年", year);}else{printf("%d不是闰年");}return 0;
}
在这个代码中,这一部分代表的是**函数的定义**:
关于函数的定义:
在C语言中,函数定义是编程中的一个核心概念,它允许你将代码组织成可重用和可维护的模块。函数定义的作用主要包括以下几个方面:
1、代码重用:通过定义函数,你可以避免在多个地方重复编写相同的代码。当你需要在程序中多次执行某个任务时,只需调用定义好的函数即可,从而提高了代码的重用性。
2、模块化编程: 函数将程序划分为多个逻辑模块,每个模块负责完成特定的任务。这种结构化的编程方式使得程序更易于理解和维护。
3、提高可读性:将复杂的程序逻辑分解为多个函数,每个函数都有明确的目的,这可以提高代码的可读性。阅读和理解一个由多个简单函数组成的程序,比阅读一个包含大量复杂逻辑的单体程序要容易得多。
4、便于调试: 模块化编程使得在程序出现问题时更容易定位错误。你可以单独测试每个函数,确定哪个函数存在错误,从而减少了调试的复杂性。
5、增强代码的可维护性: 当需要修改程序时,只需修改相关的函数,而不需要在整个程序中搜索和修改代码。这大大简化了维护过程,降低了维护成本。
6、促进代码协作:在大型项目中,多个开发人员可以独立地编写和测试各自的函数。通过定义清晰的函数接口,开发人员可以协同工作,确保代码的正确性和一致性。
7、实现递归(后面会学): 函数定义允许函数自身调用自身(递归),这是解决某些类型问题(如排序、搜索等)的有效方法。
#include<stdio.h>
int pan_duan_run_nian(int x)
{if ((x % 4 == 0) && (x % 100 != 0) || (x % 400 == 0))return 1;elsereturn 0;
}
而这一部分代表着**函数的调用`**:
int a = pan_duan_run_nian(year);
然后,如果我们把函数的定义放在函数调用的后面,像这样:
int main()
{int year = 0;scanf("%d", &year);int a = pan_duan_run_nian(year);if (a == 1){printf("%d为闰年", year);}else{printf("%d不是闰年");}return 0;
}#include<stdio.h>
int pan_duan_run_nian(int x)
{if ((x % 4 == 0) && (x % 100 != 0) || (x % 400 == 0))return 1;elsereturn 0;
}
这个代码在VS2022上编译,会出现下面的警告信息:
这是因为C语言编译器对源代码进行编译的时候,第一行往下扫描的,当遇到pan_duan_run_nian函数调用的时候,并没有发现前面有pan_duan_run_nian的定义,就报出了上述的警告。
把怎么解决这个问题呢?就是函数调用之前先声明一下pan_duan_run_nian这个函数,声明函数只要交代清楚:函数名,函数的返回类型和函数的参数。
如:pan_duan_run_nian(int x);这就是函数声明,在C语言中,函数声明(Function Declaration) 是 告诉编译器有关函数的存在、其返回类型、函数名以及参数类型和数量的声明 。函数声明通常位于函数定义之前或在其他文件中,以便编译器在函数调用之前知道函数的签名(即函数的接口)。函数声明中参数只保留类型,省略掉名字也是可以的。
函数声明的作用:
1、提前通知编译器:编译器在编译代码时,需要知道函数的签名,以便在函数调用时进行类型检查。函数声明提供了这一信息,使得编译器可以在函数实际定义之前进行编译。
2、避免链接错误:在多个文件的项目中,函数声明允许编译器在编译单独的源文件时知道其他文件中定义的函数的存在。这样,链接器(Linker)可以在链接阶段找到这些函数的实际定义。
3、提高代码可读性:函数声明提供了函数的接口信息,有助于其他程序员理解如何使用该函数。
所以我们给上面的函数加上声明,就会变成下面这样:
pan_duan_run_nian(int x);#include<stdio.h>
int main()
{int year = 0;scanf("%d", &year);int a = pan_duan_run_nian(year);if (a == 1){printf("%d为闰年", year);}else{printf("%d不是闰年");}return 0;
}int pan_duan_run_nian(int x)
{if ((x % 4 == 0) && (x % 100 != 0) || (x % 400 == 0))return 1;elsereturn 0;
}
结果便正常了
函数的调用一定要满足,先声明后使用;
函数的定义也是一种特殊的声明,所以如果函数定义放在调用之前也是可以的。
1.2 多个文件
一般在企业中我们写代码时候,代码可能比较多,不会将所有的代码都放在⼀个文件中;我们往往会根据程序的功能,将代码拆分放在多个文件中,也就是模块化处理。
注意:虽然一个工程会有多个文件,但main函数只能有一个
⼀般情况下,函数的声明、类型的声明放在头文件(.h)中,函数的实现是放在源文件(.c)文件中。
我们来举个例子,我们用test.c来调用其它模块代码进行测试,我们用leap.h和leap.c分别来对于函数的声明和函数的定义
像这样:分别创建test.c和leap.c源文件,leap.h头文件
我们来举一个加法的例子:
我们先来看函数测试的雏形:
#include<stdio.h>
#include"leap.h" //你的头文件是leap.h
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);int c = add(a, b);printf("%d", c);return 0;
}
我们把它放在test.c中
这里我们要注意要把leap.h头文件也包含进去#include"leap.h"
接着,我们看函数的声明:
int add(int x, int y);//函数的声明
我们把它放在leap.h头文件中
最后是函数的定义:
int add(int x, int y)//函数的定义
{int d = x + y;return d;
}
我们把它放在leap.c的源文件中
这样我们就写完了,运行看看结果:
没有问题
二、static和extern
static 和 extern 都是C语言中的关键字。
2.1 作用域和生命周期
**作用域(scope)**是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效(可用)的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
- 局部变量的作用域是变量所在的局部范围。
- 全局变量的作用域是整个工程(项目)。
生命周期指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的一个时间段。
- 局部变量的生命周期是:进入作用域变量创建,生命周期开始,出作用域生命周期结束。
- 全局变量的生命周期是:整个程序的生命周期(就是程序从开始运行到结束)。
2.2 static
在C语言中,static关键字有多种用途,其中之一是用于修饰函数。当static关键字用于函数声明时,它改变了函数的链接属性(linkage)。
static函数的特点:
1、内部链接(Internal Linkage):
当一个函数被声明为static时,它的链接属性变为内部链接。这意味着该函数只能在声明它的源文件(.c文件)内部被访问。其他源文件无法直接调用这个函数,即使这些文件包含了该函数的声明。
这有助于封装和隐藏实现细节,防止其他文件直接访问和修改。
2、避免命名冲突:
由于static函数只能在其所在的文件内部被访问,因此不同源文件中的同名static函数不会引起命名冲突。
这允许开发者在不同的源文件中使用相同名称的函数,而无需担心命名冲突。
3、生命周期:
static关键字对函数的生命周期没有影响。函数的生命周期总是从程序开始执行到程序结束。static关键字仅影响函数的链接属性,即函数的可见性。
static 是 静态的 的意思,可以用来:
• 修饰局部变量
• 修饰全局变量
• 修饰函数
2.3 static修饰局部变量
我们先来看个例子:
#include<stdio.h>
void test()
{int i = 0;i++;printf("%d", i);
}int main()
{int i = 0;for (i = 0; i < 5; i++){test();}return 0;
}
结果是这样的:
如果我们这样改:
#include<stdio.h>
void test()
{static int i = 0;i++;printf("%d", i);
}int main()
{int i = 0;for (i = 0; i < 5; i++){test();}return 0;
}
结果就会变成这样:
我们来对比代码1和代码2的效果
代码1的test函数中的局部变量i是每次进入test函数先创建变量(生命周期开始)并赋值为0,然后++,再打印,出函数的时候变量生命周期将要结束(释放内存)。
代码2中,我们从输出结果来看,i的值有累加的效果,其实test函数中的i创建好后,出函数的时候是不会销毁的,重新进入函数也就不会重新创建变量,直接上次累积的数值继续计算。
结论:static修饰局部变量改变了变量的生命周期(被static修饰后生命周期会变长),生命周期改变的本质是改变了变量的存储类型,本来一个局部变量是存储在内存的栈区的,但是被 static 修饰后存储到了静态区。 存储在静态区的变量和全局变量是⼀样的,生命周期就和程序的生命周期⼀样了,只有程序结束,变量才销毁,内存才回收。但是作用域不变的。
使用建议:未来一个变量出了函数后,我们还想保留值,等下次进入函数继续使用,就可以使用static修饰。
2.4 static修饰全局变量(extern声明外部符号)
extern 是用来声明外部符号的,如果一个全局的符号在A文件中定义的,在B文件中想使用,就可以使用 extern 进行声明,然后使用。
我们首先创建两个源文件,然后我们在其中一个源文件创建一个变量,然后另一个源文件用extern声明一下,像下面的做法一样:
int xiaofeixiang = 666;
#include<stdio.h>
int main()
{extern int xiaofeixiang;//声明一下printf("%d", xiaofeixiang);return 0;}
我们运行看看结果:
运行一切正常
如果我们这个时候在变量旁边添加static的话:
static int xiaofeixiang = 666;
这个时候我们如果运行的话,就会发现运行错误:
结论:
static相当于改变作用域一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用。
本质原因是**全局变量默认是具有外部链接属性的**,在外部的文件中想使用,只要适当的声明就可以使用;但是全局变量被 static 修饰之后,外部链接属性就变成了内部链接属性 ,只能在自己所在的源文件内部使用了,其他源文件,即使声明了,也是无法正常使用的。
使用建议:如果一个全局变量,只想在所在的源文件内部使用,不想被其他文件发现,就可以使用static修饰。
2.5 static修饰函数
直接来个例子:
int add(int x, int y)
{return x + y;
}
#include<stdio.h>
extern int add(int x, int y);
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);int c = add(a,b);//声明一下printf("%d",c );return 0;}
这里的extern是指声明外部函数的作用
我们运行一下,结果没有问题:
如果我们在函数前面加上static的话,会发生什么呢,我们来看看:
static int add(int x,int y);
看看结果,直接就报错了:
其实 static 修饰函数和 static 修饰全局变量是一模一样的,一个函数在整个工程都可以使用,被static修饰后,只能在本文件内部使用,其他文件无法正常的链接使用了。
本质是因为 函数默认是具有外部链接属性,具有外部链接属性,使得函数在整个工程中只要适当的声明就可以被使用。但是 被 static 修饰后变成了内部链接属性,使得函数只能在自己所在源文件内部使用。
使用建议:一个函数只想在所在的源文件内部使用,不想被其他源文件使用,就可以使用 static 修饰。
三、结尾
这一课的内容就到这里了,下节课继续学习递归的其他一些知识
如果内容有什么问题的话欢迎指正,有什么问题也可以问我!
相关文章:
于灵动的变量变幻间:函数与计算逻辑的浪漫交织(下)
大家好啊,我是小象٩(๑ω๑)۶ 我的博客:Xiao Xiangζั͡ޓއއ 很高兴见到大家,希望能够和大家一起交流学习,共同进步。 这一节我们主要来学习单个函数的声明与定义,static和extern… 这里写目录标题 一、单个函数…...
python实现pdf转word和excel
一、引言 在办公中,我们经常遇收到pdf文件格式,因为pdf格式文件不易修改,当我们需要编辑这些pdf文件时,经常需要开通会员或收费功能才能使用编辑功能。今天,我要和大家分享的,是如何使用python编程实现…...
Pandas使用笔记
个人学习笔记 日期转换 索引日期格式:2023-09-12 15:00:00 转换为:2023-09-12 import pandas as pd# 假设你的 DataFrame 名为 df,索引是 2023-09-12 15:00:00 # 这里创建一个示例 DataFrame 用于演示 data {value: [1, 2, 3]} index pd…...
高等数学学习笔记 ☞ 定积分与积分公式
1. 定积分的基本概念 1.1 定积分的定义 1. 定义:设函数在闭区间上有界。在闭区间上任意插入若干个分点,即, 此时每个小区间的长度记作(不一定是等分的)。然后在每个小区间上任意取,对应的函数值为。 为保证每段的值(即矩形面积)无…...
wow-agent---task2使用llama-index创建Agent
一:创造俩个函数,multiply和add作为fuction calling被LLM当做工具来使用,实现计算一个简单的计算题: from llama_index.llms.ollama import Ollama from llama_index.core.agent import ReActAgent from llama_index.core.tools …...
RabbitMQ实现延迟消息发送——实战篇
在项目中,我们经常需要使用消息队列来实现延迟任务,本篇文章就向各位介绍使用RabbitMQ如何实现延迟消息发送,由于是实战篇,所以不会讲太多理论的知识,还不太理解的可以先看看MQ的延迟消息的一个实现原理再来看这篇文章…...
Oracle 拉链式merge sort join 原理
Oracle 拉链式Merge Sort Join 的原理,我用一个生活中的比喻来解释。 --- 比喻场景:匹配快递包裹和收件人 1. 快递包裹清单 想象我们有一个快递公司送货的包裹清单,清单按照收件人的邮编(ZIP Code)排序: …...
QModbusTCPClient占用内存持续增长
最近使用QModbusTCPClient通信,需要频繁发送读写请求,发现软件占用内存一直在增减,经过不断咨询和尝试,终于解决了。 1.方案一(失败) 最开始以为是访问太频繁,导致创建reply的对象比delete re…...
代码中使用 Iterable<T> 作为方法参数的解释
/*** 根据课程 id 集合查询课程简单信息* param ids id 集合* return 课程简单信息的列表*/ GetMapping("/courses/simpleInfo/list") List<CourseSimpleInfoDTO> getSimpleInfoList(RequestParam("ids") Iterable<Long> ids); 一、代码解释&…...
Oracle数据库传统审计怎么用
Oracle数据库传统审计怎么用 审计功能开启与关闭By Session还是By AccessWhenever Successful数据库语句审计数据库对象审计查看审计策略和记录Oracle数据库审计功能分为传统审计(Traditional Auditing)和统一审计(Unified Auditing)。统一审计是从Oracle 12c版本开始引入的…...
leetcode-买卖股票问题
309. 买卖股票的最佳时机含冷冻期 - 力扣(LeetCode) 动态规划解题思路: 1、暴力递归(难点如何定义递归函数) 2、记忆化搜索-傻缓存法(根据暴力递归可变参数确定缓存数组维度) 3、严格表结构依…...
MYSQL学习笔记(三):分组、排序、分页查询
前言: 学习和使用数据库可以说是程序员必须具备能力,这里将更新关于MYSQL的使用讲解,大概应该会更新30篇,涵盖入门、进阶、高级(一些原理分析);这一篇是讲解分组、排序、分页查询,并且结合案例进行讲解;虽…...
上位机工作感想-2024年工作总结和来年计划
随着工作年限的增增长,发现自己越来越不喜欢在博客里面写一些掺杂自己感想的东西了,或许是逐渐被工作逼得“成熟”了吧。2024年,学到了很多东西,做了很多项目,也帮别人解决了很多问题,唯独没有涨工资。来这…...
【视觉惯性SLAM:十六、 ORB-SLAM3 中的多地图系统】
16.1 多地图的基本概念 多地图系统是机器人和计算机视觉领域中的一种关键技术,尤其在 SLAM 系统中具有重要意义。单一地图通常用于表示机器人或相机在环境中的位置和构建的空间结构,但单一地图在以下情况下可能无法满足需求: 大规模场景建图…...
【C++笔记】红黑树封装map和set深度剖析
【C笔记】红黑树封装map和set深度剖析 🔥个人主页:大白的编程日记 🔥专栏:C笔记 文章目录 【C笔记】红黑树封装map和set深度剖析前言一. 源码及框架分析1.1 源码框架分析 二. 模拟实现map和set2.1封装map和set 三.迭代器3.1思路…...
4.若依 BaseController
若依的BaseController是其他所有Controller的基类,一起来看下BaseController定义了什么 1. 定义请求返回内容的格式 code/msg/data 返回数据格式不是必须是AjaxResult,开发者可以自定义返回格式,注意与前端取值方式一致即可。 2. 获取调用…...
vue项目配置多语言
本文详细介绍如何在 Vue 项目中集成 vue-i18n 和 Element-UI ,实现多语言切换;首先通过 npm 安装 vue-i18n 和相关语言包,接着在配置文件中设置中文和英文的语言信息;最后在 main.js 中导入并挂载多语言实例,实现切换地…...
数据可视化大屏设计与实现
本文将带你一步步了解如何使用 ECharts 实现一个数据可视化大屏,并且如何动态加载天气数据展示。通过整合 HTML、CSS、JavaScript 以及后端接口请求,我们可以构建一个响应式的数据可视化页面。 1. 页面结构介绍 在此例中,整个页面分为几个主…...
PDF文件提取开源工具调研总结
概述 PDF是一种日常工作中广泛使用的跨平台文档格式,常常包含丰富的内容:包括文本、图表、表格、公式、图像。在现代信息处理工作流中发挥了重要的作用,尤其是RAG项目中,通过将非结构化数据转化为结构化和可访问的信息࿰…...
多监控m3u8视频流,怎么获取每个监控的封面图(纯前端)
文章目录 1.背景2.问题分析3.解决方案3.1解决思路3.2解决过程3.2.1 封装播放组件3.2.2 隐形的视频div3.2.3 截取封面图 3.3 结束 1.背景 有这样一个需求: 给你一个监控列表,每页展示多个监控(至少12个,m3u8格式)&…...
【机器学习实战入门项目】使用深度学习创建您自己的表情符号
深度学习项目入门——让你更接近数据科学的梦想 表情符号或头像是表示非语言暗示的方式。这些暗示已成为在线聊天、产品评论、品牌情感等的重要组成部分。这也促使数据科学领域越来越多的研究致力于表情驱动的故事讲述。 随着计算机视觉和深度学习的进步,现在可以…...
技术洞察:C++在后端开发中的前沿趋势与社会影响
文章目录 引言C在后端开发中的前沿趋势1. 高性能计算的需求2. 微服务架构的兴起3. 跨平台开发的便利性 跨领域技术融合与创新实践1. C与人工智能的结合2. C与区块链技术的融合 C对社会与人文的影响1. 提升生产力与创新能力2. 促进技术教育与人才培养3. 技术与人文的深度融合 结…...
【人工智能 | 大数据】基于人工智能的大数据分析方法
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈智能大数据分析 ⌋ ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘,以提取有价值的信息和洞察。它结合了大数据技术、人工智能(AI)、机器学习(ML&a…...
数字经济时代下的创新探索与实践:以“开源AI智能名片2+1链动模式S2B2C商城小程序源码”为核心
摘要:在数字经济蓬勃发展的今天,中国作为全球数字经济的领航者,正以前所未有的速度推进“数字中国”建设。本文旨在探讨“开源AI智能名片21链动模式S2B2C商城小程序源码”在数字经济背景下的应用潜力与实践价值,从多个维度分析其对…...
【English-Book】Go in Action目录页翻译中文
第8页 内容 前言 xi 序言 xiii 致谢 xiv 关于本书 xvi 关于封面插图 xix 1 介绍 Go 1 1.1 用 Go 解决现代编程挑战 2 开发速度 3 • 并发 3 • Go 的类型系统 5 内存管理 7 1.2 你好,Go 7 介绍 Go 玩具 8 1.3 总结 8 2 Go 快速入门 9 2.1 程序架构 10 2.2 主包 …...
js: 区分后端返回数字是否为null、‘-’ 或正常number类型数字。
问: 这是我的代码<CountTo v-if!isNaN(Number(item.num))> <span v-else>{{item.num}}</span> 我希望不是null的时候走countTo,是null的时候直接<span>{{item.num}}</span>显示 回答: 最终结果: …...
网络变压器的分类
网络变压器是局域网(LAN)中各级网络设备中必备的元件。它们的主要功能是传输数据,增强信号,并提供电气隔离,以防雷保护和匹配阻抗。网络变压器也被称为数据泵或网络隔离变压器。它们广泛应用于网络交换机、路由器、网卡、集线器等设备中。 网…...
SUCTF-SU_BBRE-好久不见21
哈哈哈哈哈哈,,,,纯汇编有大佬用工具反编译成伪代码吗。。。 题解: 由function2处逻辑,解rc4得到第一段flag We1com3ToReWorld,正常输入下执行完function0,程序结束,cong…...
Python 实现 NLP 的完整流程
💖 欢迎来到我的博客! 非常高兴能在这里与您相遇。在这里,您不仅能获得有趣的技术分享,还能感受到轻松愉快的氛围。无论您是编程新手,还是资深开发者,都能在这里找到属于您的知识宝藏,学习和成长…...
穷举vs暴搜vs深搜vs回溯vs剪枝系列一>N 皇后
题目: 解析: 1.决策树: 代码设计: 根据决策树剪枝设计: 代码: class Solution {private List<List<String>> ret;private char[][] path;private boolean[] checkdig1,checkdig2,checkco…...
怎么样在网站上做跳转/海南百度推广总代理
用<c:choose> <c:when> <c:otherwise>即可。 refurl:http://bluexp29.blog.163.com/blog/static/3385814820101535831912/ http://tianhandigeng.iteye.com/blog/938253...
做外贸出口衣服的网站/网站策划是干什么的
i.MX6邮票孔核心板,核心板引出146PIN脚 核心板尺寸:38mm*42mm 内存:512MDDR3 存储:8G EMMC 工作电压:5V电压供电 运行温度:-20℃ ~ 80℃ 引脚间距:1.27mm 连接方式:邮票孔 PCB&…...
具有品牌的上海网站建设/收录提交入口
2019独角兽企业重金招聘Python工程师标准>>> 目前很多云服务商,在提供系统的时候就已经替换为自家优化过的软件源(比如阿里云,腾讯云),但是自有组装或者是一些本地开发商,可能会使用官方软件源&…...
linux 网站建设模板/色盲怎么治疗
Chapter 9. Functions and Operators第九章.函数及操作符PostgreSQL为内置数据类型提供了大量函数和运算符。本章对其中大部分进行了讲解,还有些函数在其相关的章节中已出现。用户还可以定义自己的函数和运算符,如第五部分所述。psql命令\df和\do可分别用…...
云南工商注册公司网上申请入口/东莞网站建设优化排名
最近两天谷歌遇到问题,一直提示 谷歌提示adobe flash player旧版被屏蔽需要更新,每次刷新页面都会出现,特别烦,然后谷歌还更新不成功 找度娘问了好久,终于得到一个好的答案,基本没更新,分分钟搞…...
网站开发过程中遇到的问题/上海优化外包公司排名
N个城市,M条道路,每条道路有其经过的代价,每一个城市最多能够到达两次,求走全然部城市最小代价,起点随意。 三进制状压。存储每一个状态下每一个城市经过的次数。 转移方程: dp[ib[k]][k]Min(dp[ib[k]][k],dp[i][j]dis[j][k]); #include "stdio.h" #inclu…...