嵌入式软件--C语言高级 DAY 8 函数

news2025/1/1 22:46:28

函数是C语言尤为重要的知识点,再嵌入式的学习过程中,对51和32的单片机的学习是重中之重。

一、函数的基本概念

1.介绍

函数是一种可重复使用的代码块,用于执行特定的任务或操作。

函数允许我们将代码逻辑组织成独立的单元,从而提高了代码的可读性、可维护性和重用性。

一个C程序可以由一个或多个源文件构成(C文件扩展名是“.c”),一个源文件是一个编译单位。一个源文件可以由若干个函数构成,函数之间可以相互调用。也就是说,函数是C程序基本的组成单位。

2.作用

  1. 封装功能,将一个完整的功能封装成函数,提高代码的结构化和复用性。
  2. 代码模块化,将程序按照功能拆分成若干模块单元,有助于降低复杂度。
  3. 增强可维护性,如果需要修改某项功能,只需要调整对应的函数代码。
  4. 隔离细节,通过函数调用可以隐藏实现细节,只关心输入输出。

3.分类

C语言中,从使用的角度,函数可以分类两类。

  1. 库函数,也称为标准函数,是由C系统提供的,用户不必自己定义,可直接使用它们,使用库函数,必须包含 #include 对应的头文件。
  2. 自定义函数,解决具体需求而自己定义的函数,需先定义再使用。

二、基本语法

1.结构

返回类型 函数名(参数列表)

{

    函数体语句1;

    函数体语句2;

    … 函数体语句n;

    return 返回值;

}

2.代码演示

#include <stdio.h>

// 声明函数
void func()
{
    printf("hello func\n");
}

// 实现两个数字相减
int minus(int m, int n)
{
    return m - n;
}

// 取两个数字中的最大值
int max(int a, int b)
{
    int c;
    c = a > b ? a : b;
    return c;
}

// 主函数
int main()
{
    return 0;
}

3.函数不能嵌套

C程序中的所有函数都是互相独立的,一个函数并不从属于另一个函数,即函数不能嵌套声明。

//错误演示

int func1(int a,int b) //第1个函数的定义

{  

    ...

    int func2(int c,int d)  //第2个函数的定义

    {  

       ...

    }

    ...

}

有些编译器的扩展允许函数嵌套声明,但这不是C标准的一部分,代码的可移植性可能会受到影响,强烈不建议。

三、调用函数

函数名后面加上圆括号即是函数的调用,参数写在小括号中,函数每调用一次,函数体语句都会执行一遍。

如果把参数当成是原汁原味的水果,那函数体就是把水果加工成果汁的榨汁机,返回值就是最终的果汁。

#include <stdio.h>
int max(int a,int b)
{
    return a>b?a:b;
}
int main()
{
    //调用函数
    printf("%d",max(10,19));
    return 0;
}

四、函数的返回值

函数调用后数能得到一个确定的值,这就是函数的返回值,返回值常常是一个计算的结果,或是用来作为判断函数执行状态的标记。

函数返回值分为以下三种情况:

  1. 无返回值类型:针对函数无返回值或明确不需返回值的情况,使用void(即空类型)表示。
  2. 有返回值类型:指明具体的类型,比如,int、float、char等。需要在函数体内与return语句搭配使用。
  3. 如果返回值类型不是void,但函数中没有return语句,则函数会返回一个不确定的值。
#include <stdio.h>

// 无返回值
void fun01()
{
    printf("fun01\n");
}

// 有明确的返回值
double fun02()
{
    return 3.14;
}

// 函数返回一个不确定的值
int fun03()
{
    10 + 20;
}

// 返回类型与return的值类型不一致,可能造成精度损失
int fun04()
{
    return 20.89;
}

int main()
{
    fun01();
    printf("%f \n", fun02());
    printf("%d \n", fun03()); // 返回一个不确定的值
    printf("%d \n", fun04()); // 返回值有精度损失

    return 0;
}

输出结果:

fun01

3.140000

10

20

五、函数的参数

函数的参数分为形参与实参:

  • 形参:在定义函数时,函数名后面括号()中声明的变量称为形式参数,简称形参。
  • 实参: 在调用函数时,函数名后面括号()中的使用的常量、变量、表达式称为实际参数,简称实参。

注意:实参的数量要与形参的数量一致,否则报错。

六、主函数

1.主函数的作用

主函数是程序的入口函数,即所有的程序一定要包含一个主函数,程序总是从这个函数开始执行,如果没有该函数,程序就无法启动。主函数中可以调用其它函数,但其它函数不能反过来调用主函数,主函数也不能调用自己。

2.主函数的返回值

C语言约定,主函数返回值0表示运行成功,如果返回其它非零整数,就表示运行失败。默认情况下,如果主函数里面省略return 0 这一行,编译器会自动加上,即 main() 的默认返回值为0。但是为了保持统一的代码风格,不建议省略。

3.主函数的参数

主函数的声明中可以带有两个参数,格式如下:

int main(int argc, char *argv[])

{

    // 函数体

}

其中,形参argc,全称是argument count,表示传给程序的参数个数,其值至少是1;而argv,全称是argument value,argv[]是一个指针数组(12.3.2小节会具体讲解),我们可以暂时将 argv 理解为是一个数组,数组的每个元素都是字符串。

这种方式可以通过命令行的方式执行源代码接收指定的字符串传给参数argv。

我们创建一个名为 demo.c 的源文件,代码如下:

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("argc = %d\n", argc);
    // 函数体
    for (int i = 0; i < argc; i++)
    {
        printf("%s\n", argv[i]);
    }

    return 0;
}

七、函数原型

默认情况下,函数必须先声明,后使用。由于程序总是先运行main() 函数,导致所有其它函数都必须在main() 函数之前声明。

如果想将函数声明写在后面,可以在程序开头处给出函数原型。函数原型,就是提前告诉编译器,每个函数的返回类型和参数类型。其它信息都不需要,也不用包括函数体,具体的函数实现可以后面再补上。

#include <stdio.h>

// 使用函数原型进行声明
int fun(int);//可以不能定义确定的变量

// 主函数
int main()
{
    printf("%d\n", twice(100));
    return 0;
}

// 函数定义
int fun(int num)
{
    return 2 * num;
}

结果:200

八、作用域

1.概念

作用域用于确定在代码中某个标识符(如变量、标识符常量、数组等)的可见性和访问范围,它决定了在程序的哪些部分可以引用或访问该标识符。

作用域可以分为全局作用域局部作用域块级作用域

同一个作用域中不能声明同名的标识符。

2.全局作用域

在函数和代码块(分支语句、循环语句等)以外定义的变量、标识符常量、数组等具有全局作用域,在程序的任何地方都可以被访问,通常称它们为全局变量、全局常量、全局数组等。

3.局部作用域

在函数内定义的变量、标识符常量、数组等具有局部作用域,只有在该函数内部才能被访问,通常称它们为局部变量、局部常量、局部数组等。需要注意的是,函数的形参也是局部变量。

4.块级作用域

块级作用域是C99标准引入的概念,在代码块(分支语句、循环语句等)中定义的变量、标识符常量、数组等具有块级作用域,只有在该代码块内部才能被访问,代码块通常具有花括号 {} 结构。

这些被称为块级变量、块级常量、块级数组等,同时也可以被称为局部变量、局部常量、局部数组,且与函数中的局部变量、局部常量、局部数组具有相同的特性。

5.作用域和内存

(1)栈区域

局部变量、局部数组等通常存储在栈(Stack)区,这些局部数据的内存分配和释放是自动管理的,它们的生命周期受限于其定义的函数或块级作用域,当函数返回或块级作用域结束时,这些变量的内存会被自动释放。

函数每调用一次就创建一次局部数据,调用结束就销毁;下次调用再创建新的局部数据。

(2)全局静态区域

全局变量、全局数组等存储在全局静态区,这些全局的数据在程序的整个生命周期内都存在,它们在程序启动时被分配,在程序结束时才被释放。

(3)变量生命周期演示

#include <stdio.h>
// 定义全局变量
int a = 10;
// 定义全局数组
int arr[3] = {10, 22, 34};
// 定义全局函数
void fun(int num)
{
    // 定义局部变量
    int b = 230;
    printf("%d", num + b);
}
int main()
{
    fun(20);

    // 遍历数组
    for (int i = 0; i < 3; i++)
    
        {
         printf("%d ", arr[i]);
        
        }
        printf("\n");

   // 再次调用函数
     fun(60);
    return 0;
}

(4)static 和 extern 关键字

static关键字可以声明静态变量和静态函数,以控制变量和函数的作用范围和生存周期。

<1>静态局部变量

使用static关键字修饰的局部变量,称为静态局部变量,静态局部变量与全局变量一样存储在内存中的全局静态区。静态局部变量具有如下特点:

  1. 静态局部变量只在函数第一次调用时初始化一次并将生命周期延长到整个程序的执行期间
  2. 静态局部变量如果声明时没有初始赋值,系统会自动初始化为零,同全局变量的初始化规则一致。
<2>多文件编译

C 编译器可以将多个源文件编译成一个可执行文件。创建两个源文件,分别命名为file01.c和 file02.c。

VS Code 默认是无法同时编译多个源文件的,我们使用命令行终端进行编译,打开VS Code 内置终端,运行如下命令:

gcc file01.c file02.c -o main.exe

运行之后,会生产 main.exe 可执行文件,再次通过命令行运行 mian.exe 即可。

./main.exe

运行完会显示“Hello file02”。

<3>extern

如果想要使用外部文件中定义的变量,我们可以使用 extern 关键字声明外部链接。

<4>静态全局变量

使用 static 关键字修饰的全局变量称为静态全局变量。

普通全局变量对整个工程可见,其他文件中,使用extern外部声明后,可以直接使用。静态全局变量仅对当前文件可见,其他文件不可访问,其他文件中可以定义与其同名的变量,两者互不影响。

静态全局变量对于需要编译多个源代码文件的程序,能够有效地降低源文件之间的耦合,避免不同文件同名变量的冲突。

此外static关键字还可以修饰函数(静态函数)、全局数组、全局常量等,功能作用与静态全局变量一致。

九、课后练习题

1.定义函数,实现求两个double数字的最大值,并返回。

#include <stdio.h>
double max(double a,double b)
{
    return a>b?a:b;
}
int main()
{
    double a1,b2;
    //输入浮点数
    scanf("%lf",&a1);
    scanf("%lf",&b2);
    //调用函数
    printf("%lf",max(a1,b2));
    return 0;
}

2.定义函数,求出三个int 类型数的和,并返回。

#include <stdio.h>
//定义函数
int sum(int a,int b,int c)
{
    return a+b+c;
}
int main()
{
    int num1,num2,num3;
    //输入
    scanf("%d",&num1);
    scanf("%d",&num2);
    scanf("%d",&num3);
    //调用函数
    printf("%d",sum(num1,num2,num3));
    return 0;
}

3.定义函数,判断一个数字是否是质数。

#include <stdio.h>
int fun(int a)
{
    int count=2;
    for(int i=2;i<a;i++)//输入比这个数小的所有整数,除了1和它本身。
    {
        if(a%i==0)
        {
            count++;//只要有多余的整除因数,就可以终止
            break;
        }

    }
    if(count==2)//符合条件的返回1
    {
 return 1;
    }
   
}
int main()
{
    int num1;
    //输入
    scanf("%d",&num1);
    //调用函数
    if(fun(num1)==1)
    {
    printf("%d是质数",num1);
    }else{
        printf("%d不是质数",num1);
    }

    return 0;
}

4.函数可以没有返回值案例,编写一个函数,从终端输入一个整数打印出对应的金字塔,函数可以传入金字塔层数。

#include<stdio.h>

//函数可以没有返回值案例,编写一个函数,从终端输入一个整数(层)打印出对应的金子塔。 
//层数n是通过形参传入 
void Star(int n) { 
	int i,j,k; 
	for(i = 1; i <= n; i++) {//控制层 
	//输出空格, 使用 k 控制空格的循环 
		for (k=1; k <= n - i; k++) { 
			printf(" "); 
		}

		for(j = 1; j <= 2 * i - 1; j++) { 
			if(j == 1 || j == 2 * i - 1 || i == n) { 
				printf("*"); 
			} else { 
				printf(" "); 
			} 
		}
		printf("\n"); 
	} 
}

int main(){

	int a;
	printf("请打印金字塔层数:");
	scanf("%d",&a);
	Star(a);

}

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

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

相关文章

Python酷库之旅-第三方库Pandas(069)

目录 一、用法精讲 276、pandas.Series.dt.is_quarter_start属性 276-1、语法 276-2、参数 276-3、功能 276-4、返回值 276-5、说明 276-6、用法 276-6-1、数据准备 276-6-2、代码示例 276-6-3、结果输出 277、pandas.Series.dt.is_quarter_end属性 277-1、语法 …

知乎ip地址怎么改到别的城市去

知乎全面上线显示用户IP属地功能&#xff0c;这意味着用户可以在知乎上看到其他用户发布内容时的IP属地信息&#xff0c;这有助于增加信息的透明度和减少误解&#xff0c;但同时也容易暴露其隐私。有时出于保护隐私、避免地域限制或参与特定话题讨论的需求&#xff0c;我们可能…

【实战】文件加密器进行逆向

前言 实战可以大大提高自己&#xff0c;学习技术的目的就是能够在实战中运用。 本次实战与实际息息相关&#xff0c;该软件具有加密某文件的功能。 界面还挺好看的&#xff0c;功能很简单&#xff0c;输入文件和PIN(4位&#xff09;进加解密。 这是被加密的文件 需要将其进行…

经纬恒润荣获小米汽车优秀质量奖!

小米SU7上市已超百天&#xff0c;在品质经过客户严选的同时&#xff0c;产量与交付量屡创新高&#xff0c;6-7月连续两个月交付量均超过10000台。为奖励对小米汽车质量和交付做出卓越贡献的合作伙伴团队及个人&#xff0c;小米向质量表现突出的供应商授予了优秀质量奖。经纬恒润…

第22课 Scratch入门篇:猫咪跑步(超长背景实现方法)

猫咪跑步(超长背景实现方法) 故事背景&#xff1a; 在广阔的草坪上有一只小猫&#xff0c;按下键盘的左右键&#xff0c;小猫不停的奔跑。。。 程序原理&#xff1a; 这个小猫的奔跑&#xff0c;实际是背景的移动&#xff0c;上节课我们通过多个图片直接的切换&#xff0c;今天…

深入理解 RDMA 的软硬件交互机制

作者&#xff1a;羽京 一、前言 随着数据中心的飞速发展&#xff0c;高性能网络不断挑战着带宽与时延的极限&#xff0c;网卡带宽从过去的 10 Gb/s 、25 Gb/s 到如今的 100 Gb/s、200 Gb/s 再到下一代的 400Gb/s 网卡&#xff0c;其发展速度已经远大于 CPU 发展的速度。 为了…

谷歌25亿美金收购Character AI的幕后故事

在科技领域中&#xff0c;并购交易无疑是推动技术发展的重要手段之一。最近&#xff0c;谷歌以25亿美金的对价收购了Character AI&#xff0c;这一交易的方式和细节引起了广泛关注。本文将详细解析谷歌这一奇葩交易方式&#xff0c;探讨其背后的动机和影响。 一、交易背景 1.…

计算机毕业设计Python民宿可视化分析 民宿推荐系统 随机森林预测算法 民宿爬虫 酒店爬虫 大数据毕业设计 Django Vue.js 机器学习 深度学习

《Python民宿可视化与预测系统》开题报告 一、选题背景及研究意义 1.1 选题背景 民宿作为一种新型的住宿方式&#xff0c;近年来在全球范围内迅速崛起&#xff0c;尤其在旅游行业发达的国家和地区更是受到广大游客的青睐。民宿不仅提供了更加个性化和接地气的住宿体验&#…

高校综合管理数据库中有以下几个关系

inner join&#xff1a;理解为“有效连接”&#xff0c;两张表中都有的数据才会显示 left join&#xff1a;理解为“有左显示”&#xff0c;比如on a.fieldb.field&#xff0c;则显示a表中存在的全部数据及a、b中都有的数据&#xff0c;a中有、b中没有的数据以null显示 right j…

智慧水务项目(五)django(drf)+angular 18 配置REST_FRAMEWORK

一、说明 建立了几个文件 二、一步一步来 1、建立json_response.py 继承了 Response&#xff0c; 一共三个函数&#xff0c;成功、详情&#xff0c;错误 from rest_framework.response import Responseclass SuccessResponse(Response):"""标准响应成功的返回…

影响LabVIEW工作效率的因素有哪些

影响LabVIEW工作效率的因素可以分为多个方面&#xff0c;涵盖硬件、软件、开发环境和编程习惯等。以下是一些常见的影响因素&#xff1a; 1. 硬件因素 处理器性能&#xff1a;处理器的速度和核心数量对LabVIEW程序的执行效率有很大影响。 内存大小&#xff1a;足够的内存可以保…

基于各种排序方法的综合比较

一. 各种排序方法总括 二. 时间性能方面 按平均的时间性能来分&#xff0c;时间复杂度为n*log阶的有快速排序&#xff0c;堆排序和并归排序其中以快速方法最好。 时间复杂度为n*n阶的有直接插入排序&#xff0c;冒泡排序和简单选择排序&#xff0c;直接以直接插入排序最优。特…

为什么会出现cmake?

为什么会出现cmake 1、 什么是CMake -- 是一个项目构建工具&#xff0c;其实cmake和makefile是差不多的&#xff0c;只不过cmake更高级&#xff0c;可以跨平台使用&#xff0c;并且使用起来更加灵活&#xff0c;更符合逻辑。 2、为什么会出现cmake&#xff1f; c程序的编译流…

「字符串」详解Trie(字典树|前缀树)并实现对应的功能 / 手撕数据结构(C++)

概述 在浏览器搜索栏里输入几个字&#xff0c;就弹出了以你的输入为开头的一系列句子。浏览器是怎么知道你接下来要输什么的&#xff1f; 来看看字典树干了什么。 字典树是一种高效记录字符串和查找字符串的数据结构。它以每个字符作为一个节点对字符串进行分割记录&#xff0c…

Flink-DataWorks第二部分:数据集成(第58天)

系列文章目录 数据集成 2.1 概述 2.1.1 离线&#xff08;批量&#xff09;同步简介 2.1.2 实时同步简介 2.1.3 全增量同步任务简介 2.2 支持的数据源及同步方案 2.3 创建和管理数据源 文章目录 系列文章目录前言2. 数据集成2.1 概述2.1.1 离线&#xff08;批量&#xff09;同步…

【文献阅读】DAVE

核心思想 文章的核心思想是提出了一种名为DAVE&#xff08;Detect-and-Verify Paradigm for Low-Shot Counting&#xff09;的少样本计数方法。DAVE旨在通过一个新颖的检测和验证范式来提高低样本情况下的对象计数性能。这种方法特别关注在只有少量标注样本&#xff08;少样本…

OpenAI Gym: Understanding `action_space` notation (spaces.Box)

题意&#xff1a;OpenAI Gym: 理解action_space表示法&#xff08;spaces.Box&#xff09; 问题背景&#xff1a; I want to setup an RL agent on the OpenAI CarRacing-v0 environment, but before that I want to understand the action space. In the code on github line…

【Nuxt】Layout 布局和渲染模式

NuxtLayout app.vue <NuxtLayout><NuxtPage/></NuxtLayout>然后默认的布局 需要 写在 ~/layouts/default.vue 下面&#xff0c;其他自定义的布局也在写在 layouts 目录下。 default.vue <template><div class"app-container"><d…

比特币使用ord蚀刻符文---简单笔记

说明 毕竟符文热度过了&#xff0c;今年四月份做的笔记分享出来 蚀刻符文需要先同步完区块数据&#xff0c;和index文件&#xff0c;不然蚀刻会失败&#xff0c;在testnet和signet网络也一样。 创建钱包&#xff08;会输出助记词&#xff09;&#xff1a; ord --bitcoin-da…

【系统架构设计师】二十五、大数据架构设计理论与实践②

目录 四、 Kappa架构 4.1 Kappa架构介绍 4.2 Kappa架构的优缺点 4.3 常见Kappa 架构变形 4.3.1 Kappa 架构 4.3.2 混合分析系统的Kappa 架构 五、Lambda 架构与 Kappa 架构的对比和设计选择 5.1 Lambda架构与Kappa 架构的特性对比 5.2 Lambda架构与Kappa 架构的设计选…