《小菜狗 C 语言入门 + 进阶笔记》(10)函数入门 -- 保证入门

文章目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介

暂时无法在飞书文档外展示此内容

1、函数背景引入(可略)

1.1、 数学中的函数 与 C 语言中的函数

数学中我们知道函数的概念,如:⼀次函数 y=kx+b , k 和 b 都是常数,给⼀个任意的 x,y 就得到⼀个值。

  • 数学中有 y = f(x)
  • C 语言中有 y = sizeof(x);

你看它们是何其相似,都是通过一定的操作或规则,由一份数据得到另一份数据。

总结就是:

C 语⾔中的函数就是完成某项特定的功能的⼀小段代码一个程序多个函数组成,可以理解为「一个程序由多个小的功能叠加而成」

1.2、使用函数的优势

C 语言提供了很多功能,例如输入输出、获得日期时间、文件操作等,我们只需要一句简单的代码就能够使用。但是这些功能的底层都比较复杂,通常是软件和硬件的结合,还要要考虑很多细节和边界,如果将这些功能都交给程序员去完成,那将极大增加程序员的学习成本,降低编程效率。 好在 C 语言的开发者们为我们做了一件好事,他们已经编写了大量代码,将常见的基本功能都完成了,我们可以直接拿来使用。但是现在问题来了,那么多代码,如何从中找到自己需要的呢?一股脑将所有代码都拿来显然是非常不明智的。 这些代码,早已被分门别类地放在了不同的文件中,并且每一段代码都有唯一的名字。使用代码时,只要在对应的名字后面加上 ( ) 就可以。这样的一段代码能够独立地完成某个功能,一次编写完成后可以重复使用。

  • 读者可以认为,函数就是一段可以重复使用的代码。

总结就是两点:

  1. 分解任务:C 语⾔的程序其实是由⽆数个小的函数组合⽽成的,也可以说:使用函数可以把大的计算任务分解成若干个较小的函数(对应较小的任务)完成。
  2. 代码复用:⼀个函数如果能完成某项特定任务的话,这个函数也是可以复用的,提升了开发软件的效率。
1.3、函数的分类

在 C 语⾔中我们⼀般会见到两类函数:

1.3.1、库函数

C 语言自带的函数称为库函数(Library Function)。库(Library)是编程中的一个基本概念,可以简单地认为它是一些列函数的集合,在磁盘上往往是一个文件夹。C 语言自带的库称为标准库(Standard Library),其他公司或个人开发的库称为第三方库(Third-Party Library)。

我们前⾯内容中学到的 printf 、 scanf 、 getchar 、 putchar 等都是库函数。

库函数的也是函数,不过这些函数已经是现成的,我们只要学会使用就能直接使用了,只要包含函数需要的头⽂件即可。

1.3.2、自定义函数

库函数再好,提供的功能还是有限的;日常写代码的需求是千变万化的,所以还是需要程序员写各种各样的代码,这些代码也是由⼀个个函数组成。

因此,我们自己设计和实现的函数,称为自定义函数main 函数也算是自定义函数

2、函数概念巧记!

  1. 在 C 语言中,有的语句使用时不能带括号,有的语句必须带括号 ( )
我们可以这样认为,其中带括号的语句称为 函数(Function)。
  1. 函数的一个明显特征就是使用时必须带括号( )如果函数有参数的话,括号中还可以包含待处理的形参数据。

例如:

printf("Hello, World! \n");

使用了一段具有输出功能的代码,这段代码的函数名字printf, "Hello, World! \n" 是要交给这段代码处理的形参数据

  • 如果函数需要处理多个数据,那么它们之间使用逗号 , 分隔。

例如:

pow(10, 2);      // 该函数用来求10的2次方
  1. 函数的另一个明显特征就是一组一起执行一个任务的语句,包含在 {} 里。

{} 之间的代码是函数要实现的功能

{} 之间的代码也是函数的作用域

  1. 使用函数在编程中有专业的称呼,叫做 函数调用(Function Call)。后面会再解释。

  2. 接下来我们就可以来了解函数的定义

3、函数的定义

3.1、C 语言中的函数定义的一般形式
return_type function_name ( [parameter list] )
{
    body of the function
}

也就是:

返回类型 函数名 ( [参数列表] )
{
    函数主体
}

[ ] 说明此参数是可省略的。

如之前的文章(2.2)基本程序结构中的 C 实例 -- Hello World就是一个标准的函数定义模版。如下:

#include <stdio.h>                 //头文件
                                   //空白行
/* 我们的第一个 C 程序 */            //注释
int main()                         //函数
{                                  //函数体开始
   printf("Hello, World! \n");     //输出语句
   return 0;                       //结束并返回语句
}                                  //函数体结束

在 C 语言中,函数由一个函数头和一个函数主体组成。

下面列出一个函数的所有组成部分:

3.2、返回类型

一个函数可以返回一个值 或者 不返回

3.2.1、函数的返回值
  • **函数的返回值**是指函数被调用之后,执行函数体中的代码所得到的执行结果,并且这个结果通过 return 语句返回。

例如:

size_t len = sizeof(int);

解释说明:

sizeof(int) 的处理结果是 size_t字节长度,我们通过 len 变量来接收。

3.2.2、返回类型
  • 返回类型 是使用函数后,返回值数据类型

函数返回值有固定的数据类型(int、char、float 等),用来接收返回值的变量类型要一致。

例如:

size_t len = sizeof(int);

解释说明:

sizeof(int) 的返回值的变量类型是 size_t ,所以 len 变量也是 size_t

3.2.3、return 的用法详解

return 语句的一般形式为:

return 表达式;

或者:

return (表达式);

有没有( )都是正确的,为了简明,一般也不写( )。例如:

return max;
return (100+200);

对 C 语言返回值的说明:

  1. 没有返回值的函数为空类型,在这种情况下,return_type 是关键字 void,用void表示。例如:
void func() {
    printf("bobo study! \n");
}

一旦函数的返回值类型被定义为 void,就不能再接收它的值了。

为了使程序有良好的可读性并减少出错, 凡不要求返回值的函数都应定义为 void 类型

  1. 同一个函数里 return 语句可以有多个,可以出现在函数体的任意位置,但是每次调用函数只能有一个 return 语句被执行,所以只有一个返回值(少数的编程语言支持多个返回值,例如 Go 语言)。例如:
int func() {
    printf("bobo \n");
    return 0;
    printf("study! \n");
}

此时输出的内容为 bobo ,为什么,马上看以下第三点!

  1. 函数一旦遇到 return 语句就立即返回,后面的所有语句都不会被执行到了。从这个角度看,return 语句还有强制结束函数执行的作用。

例如:

int func() {
    printf("bobo \n");
    return 1;
    printf("study! \n");
    return 2;
}

第 4 行和第 5 行代码就是多余的,永远没有执行的机会。

return 语句是提前结束函数的唯一办法。

总之:

return 后面可以跟一份数据,表示将这份数据返回到函数外面;return 后面也可以不跟任何数据,表示什么也不返回,仅仅用来结束函数。

3.3、函数名称

这是函数的实际名称,一个合法的用户自定义标识符,函数名尽量要根据函数的功能起的有意义。

看底下章节的例子:3.6、函数头的定义举例

3.4、参数列表

参数就像是占位符,当函数被调用时,就会向函数传递一个值。

参数列表和返回类型可以简单理解为输入和输出,参数列表传参进来,返回类型返回值出去。

3.4.1、参数列表基本形式

type1 param1, type2 param2, type3 param3 ... 是参数列表。

相当于

类型1 变量名1,类型2 变量名2,类型3 变量名3,... 是参数列表。

3.4.2、函数的参数

函数的参数是可选的,也就是说:

  • 函数可能不包含参数,但括号不可省略;
  • 也可以只有一个参数
  • 也可以有多个,多个参数之间由 , 分隔。

参数本质上也是变量,定义时要指明类型和名称,使用方式和普通变量一样。

与无参函数的定义相比,有参函数的定义仅仅是多了一个参数列表。

3.4.3、形参和实参简单简介
  • 函数定义时给出的参数称为形式参数,简称形参;
  • 函数调用时给出的参数(也就是传递的数据)称为实际参数,简称实参。函数调用时,将实参的值传递给形参,相当于一次赋值操作。

原则上讲,实参的类型和数目要与形参保持一致。如果能够进行自动类型转换,或者进行了强制类型转换,那么实参类型也可以不同于形参类型,例如将 int 类型的实参传递给 float 类型的形参就会发生自动类型转换。

(强转以后会讲解)

总结:

数据通过参数传递到函数内部进行处理,处理完成以后再通过返回值告知函数外部。

3.5、函数主体

函数主体包含一组定义函数执行任务的语句,实现特定的算法或功能。

  1. 有可能函数体内无语句,空的函数体便于以后扩充。
  2. 函数体内不可以出现其他函数的定义,即函数不能嵌套定义(底下章节**6、函数不能嵌套定义**)。
  • 若返回值类型不是 void 类型,则函数体内一定要配合使用 return 表达式; 语句。
  • 若返回值类型 void,则在需要返回的点使用 return ; 语句,建议编程者采用这种方式,也可以没有 return 语句,则执行到函数体的右大括号结束。
3.6、函数头的定义举例:
函数的功能描述函数定义的首部
求两个整数之间的较大值int FindMax ( int x, int y)
求两个实型数的和double Add ( double a, double b)
判断一个整数是否为质数int JudgePrime ( int n )
画出一条由 30 个减号组成的横线void DrawLine( )
求两个整数的最大公约数int Gcd ( int a , int b)
统计出 m 到 n 之间的水仙花数int CountNarcissus ( int m , int n )
求出 m 到 n 之间所有的同时能被 5 和 7 整除的奇数和int SumOdd ( int m , int n )

4、函数调用

创建 C 函数时,会定义函数做什么,然后通过调用函数来完成已定义的任务。

也就是说:

函数调用(Function Call),就是使用已经定义好的函数。

函数调用的一般形式为:

functionName (param1, param2, param3 ...);

functionName 是函数名称,param1, param2, param3 ...是实参列表。实参可以是常数、变量、表达式等,多个实参用逗号,分隔。

调用过程文字理解:

当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。(具体例子请看章节**5、函数先定义再使用**)

如下例子: 在 C 语言中,函数调用的方式有多种,例如:

  1. 函数作为一个单独的语句。
printf("%d", a);
scanf("%d", &b);
  1. 函数作为表达式中的一项出现在表达式中。
z = max(x, y);
m = n + max(x, y);
  1. 函数作为调用另一个函数时的实参。
printf( "%d", max(x, y) );
total( max(x, y), min(m, n) );

5、函数先定义再使用

定义一个函数是为了调用,函数调用有两种类型

  • 一是 先定义,后调用,这要求函数定义和调用语句在同一个文件内,编译器能从函数定义中提取函数的参数列表、输出类型等接口信息。
  • 二是 函数声明+函数调用,大多数情况下,函数的定义与函数的调用并不在一个文件内,即使在一个文件中也有可能调用在前而定义在后,这时需要在调用之前先对函数声明,告诉编译器有这么一个函数存在。函数原型声明将在后面讨论。

下面我们来写一个先定义、后调用的例子:

写⼀个加法函数,完成 2 个整型变量的加法的代码,并输出最后的值!

  1. 先写一个基本框架
#include <stdio.h>
int main()
{
    int a = 0;
    int b = 0;
    int sum = 0;

    scanf("%d %d", &a, &b);

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

解释说明:

  • scanf 函数输入变量 a 和 变量 b 的值;
  • printf 函数输出最终的和。
  1. 我们根据要完成的功能,给子函数取名:Add,函数 Add 需要接收 2 个整型类型的参数,函数计算的结果也是整型。
int Add(int x, int y)
{
    int sum = 0;
    sum = x+y;
    return sum;
}

解释说明:

  • 把传参进来的两个变量相加,赋值给 sum 变量;
  • 得到相加的结构,通过 return 语句返回。
  1. 合并两个功能代码,并在 main 函数里调用 Add 函数。
#include <stdio.h>
int Add(int x, int y)
{
    return x+y;
}

int main()
{
    int a = 0;
    int b = 0;
    int sum = 0;

    scanf("%d %d", &a, &b);
    
    sum = Add(a, b);

    printf("%d\n", sum);

    return 0;
}

解释说明:

  • main 函数里调用 Add 函数,Add 函数就会执行相加两个变量的参数;
  • Add 函数返回相加后的值给 sum 变量,再打印出来,return main 函数结束。

6、函数不能嵌套定义

强调一点,C 语言不允许函数嵌套定义:也就是说,不能在一个函数中定义另外一个函数,必须在所有函数之外定义另外一个函数。

main() 也是一个函数定义,也不能在 main() 函数内部定义新函数。

下面的例子是错误的:

#include <stdio.h>

void func1(){
    printf("bobo study! \n");

    void func2(){
        printf("C语言入门教程\n");
    }
}

这是错误的,编译时将会报错。

正确的写法应该是这样的:

#include <stdio.h>

void func2(){
    printf("C语言入门教程\n");
}

void func1(){
    printf("bobo study! \n");
}

func1()、func2()两个函数是平行的,谁也不能位于谁的内部。

  • 有些编程语言是允许函数嵌套定义的,例如 JavaScript,在 JavaScript 中经常会使用函数的嵌套定义。

7、函数签名

函数名和参数列表一起构成了函数签名。

函数名和参数列表一起构成了函数签名。意味着可以出现参数列表不同但是函数名相同的函数。比如说定义两个函数:

void print()
{
    printf("bobo study! ");
}

void print(int nums)
{
    printf("%d\n", a);
}

这是合法的。

8、函数定义的设计

如果我们需要实现⼀个函数来解决问题,我们是需要根据实际的场景,来分析函数是否需要参数需要几个参数是否需要返回值返回什么类型的值。等这些确定好后,再给⼀个函数确定⼀个有意义的名字,就可以实现这个函数了。

文章目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介

每日一更!

公众号、CSDN等博客:小菜狗编程笔记

谢谢点赞关注哈!目前在飞书持续优化更新~

日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!

内容概要: 本文档提供了一个基于C语言的双人迷宫游戏项目的源代码。该项目首先初始化了迷宫地图,包括设置迷宫的边界和随机生成出口位置。接着定义了两个玩家的初始位置,并实现了玩家通过键盘控制角色移动的功能。游戏中,两个玩家分别用不同的符号表示,玩家可以通过特定的键位控制自己的角色在迷宫中移动,当任意一名玩家到达出口时,游戏结束并显示获胜信息。 适合人群: 计算机相关专业的大一或大二学生,尤其是正在学习C语言编程和数据结构课程的学生。 使用场景及目标: 作为期中或期末课程设计项目,帮助学生巩固C语言基础知识;掌握基本的图形界面操作如光标的移动和颜色设置等。 阅读建议: 建议读者先熟悉C语言的基本语法,特别是函数定义与调用、数组操作以及条件语句等内容。在阅读代码时,可以尝试逐步理解每个函数的作用,并结合注释和调试工具来加深对程序流程的理解。此外,还可以尝试修改代码,如调整迷宫大小或者增加新的功能,以此提升编程技巧。 【后续】 1.猜数字游戏 2.学生管理系统 3.迷宫游戏(双人) 4.贪吃蛇游戏(单人) 5.贪吃蛇游戏(双人) 6.俄罗斯方块游戏1 7.俄罗斯方块游戏2 - 跨平台 并且有《小菜 C 语言入门 + 进阶笔记》,公众号、CSDN等同名小菜编程笔记
Vivado2023是一款集成开发环境软件,用于设计和验证FPGA(现场可编程门阵列)和可编程逻辑器件。对于使用Vivado2023的用户来说,license是必不可少的。 Vivado2023的license是一种许可证,用于授权用户合法使用该软件。许可证分为多种类型,包括评估许可证、开发许可证和节点许可证等。每种许可证都有不同的使用条件和功能。 评估许可证是免费提供的,让用户可以在一段时间内试用Vivado2023的全部功能。用户可以使用这个许可证来了解软件的性能和特点,对于初学者和小规模项目来说是一个很好的选择。但是,使用评估许可证的用户在使用期限过后需要购买正式的许可证才能继续使用软件。 开发许可证是付费的,可以永久使用Vivado2023的全部功能。这种许可证适用于需要长期使用Vivado2023进行开发的用户,通常是专业的FPGA设计师或工程师。购买开发许可证可以享受Vivado2023的技术支持和更新服务,确保软件始终保持最新的版本和功能。 节点许可证是用于多设备或分布式设计的许可证,可以在多个计算机上安装Vivado2023,并共享使用。节点许可证适用于大规模项目或需要多个处理节点进行设计的用户,可以提高工作效率和资源利用率。 总之,Vivado2023 license是用户在使用Vivado2023时必须考虑的问题。用户可以根据自己的需求选择合适的许可证类型,以便获取最佳的软件使用体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小菜狗编程笔记

你的鼓励将是我最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值