自学C语言——函数(全)

接上一篇:自学C语言——数组(二) 

1.函数的概念

C语言中:函数=子程序

C语言中的函数就是一个完成某项特定的任务的一小段代码。

2.库函数

标准库和头文件

C语言标准中规定了C语言的语法规则,C语言不提供库函数,常用的函数称为标准库。

不同的编译器厂商根据ANSI提供的C语言标准给出的一系列函数的实现,这些函数被称为库函数。

printf

功能:

参数:

返回类型:

错误处理:

注解:

示例:

参阅:

······

 库函数的使用方法

cplusplus.com

cppreference.com _C标准库头文件

例子:(函数有使用例子,使用前要把头文件放在前边)

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <math.h>
int main()
{double r = sqrt(16.0);printf("%lf\n", r);//lf.1(保留1为)return 0;
}输出:
4.000000

库函数文档的一般格式

  1. 函数原型
  2. 函数功能介绍
  3. 参数和返回类型说明
  4. 代码举例
  5. 代码输出
  6. 相关知识链接

3.自定义函数

函数的语法形式

ret_typr fun_name(   )

{

}

ret_type  函数返回类型   void表示不需要返回

fun_name 函数名

( )形式参数

{ }函数体

 例子:

//写一个加法函数,完成2个整型变量的加法操作
int Add(int x, int y)
{int z = 0;z = x + y;return z;
}int main()
{int n1 = 0;int n2 = 0;scanf("%d%d", &n1, &n2);int r = Add(n1, n2);printf("%d\n", r);return 0;
}

int main  主调函数

int Add    被调函数

简化:

{

return x + y ;

}

4.形参和实参

实参

在函数调用的时候,真实传递给函数的参数(实际参数)

例如上方的n1和n2

形参

函数定义时,函数名后边的参数就是函数的形式参数,简称形参

例如上方add中的x和y

形参和实参的关系

在调试时,形参确实得到了实参的值,但是地址不一样

在寄存器做中转,形参其实是实参的一份临时拷贝

形参是由自己独立空间的,对形参的修改,不会影响实参

  • 语法规定上,形参的名字和实参的名字可以相同
  • 形参的个数可以时没有、也可以是1个或者多个
  • 形参的个数和实参要匹配上

main函数也是函数

main函数也是被编译器指定的一个函数调用了

return 0,就是将0返回给调用main函数的那个函数

main函数中返回0表示正常返回,返回非0值表示异常返回

5.return语句

在函数设计中

  • return后边可以是一个数值,也可以是一个表达式,如果是表达式则先执行表达式,再返回表达式的结果
  • return后边也可以什么都没有,之间写return;,这种写法适合函数返回类型是void的情况
  • return返回的值和函数返回类型不一致,系统会自动将返回的值隐式转换为函数的返回类型(例如:double转化到int可能丢失数据)
  • return语句执行后,函数就彻底返回,后边的代码不再执行
  • 如果函数中存在 if 等分支的语句,则要保证每种情况下都有return返回,否则会出现编译错误(警告:“ ” 不是所有的空间路径都返回值)
void print(int n)
{if (n < 0)return;printf("hehe\n");
}int main()
{print(10);print(-10);return 0;
}
//输出
hehe
(空白)
————————————

注意:函数的返回类型如果不写的话,编译器默认int返回类型。如果返回值类型不匹配,最终返回的值的类型是不确定的。

补充:break是用在循环里的,不能代替return;

6.数组做函数参考

将数组作为参数传递给函数,在函数的内部对数组进行操作。

例:写一个函数将一个整型数组的内容,全部设置为-1,再写一个函数答应数组的内容

void set_arr(int arr[],int sz)//形参数组大小可以不写
{int i = 0;for (i = 0; i < sz; i++){arr[i] = -1;}
}void print_arr(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//写一个函数将数组arr的内容,全部置为-1int sz = sizeof(arr) / sizeof(arr[0]);//计算数组内元素个数print_arr(arr, sz);//先打印一边原函数set_arr(arr,sz);//打印数组内容print_arr(arr, sz);return 0;
}

 输出:

1 2 3 4 5 6 7 8 9 10
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1

问:1.为什么形参的数组不指定大小?

        答:数组传参,其实传递的是数组的地址,在形参部分访问数组的时候,其实操作的就是主调函数中的数组。

        2.set_arr中修改的数组是主函数中的arr吗?

        答:数组传参的时候,在形参的部分不会新建数组。

数组作为参数传递时,应该如何设计函数

  • 函数的形式参数要和函数的实参个数匹配
  • 函数的实参是数组,形参也可以写成数组形式的
  • 形参如果是一维数组,数组的大小可以省略不写
  • 形参如果是二维数组,行可以省略,但是列不能省略
  • 数组传参,形参是不会创建新的数组的
  • 形参操作的数组和实参的数组是同一个数组

 7.嵌套调用和链式访问

嵌套调用

嵌套调用就是函数之间的相互调用,正是应为函数之间的相互调用,才组成了大型的程序。

例:计算某年某月有多少天?

//假设我们计算某年某月有多少天?
//31 28 31 30 31 30 31 31 30 31 30 31
//   29闰年int is_leap_year(int y)//bool也行
{if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))return 1;elsereturn 0;
}int get_days_of_month(int y, int m)
{int days[13] = {0 , 31 ,28 , 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };//              0   1   2    3    4   5   6   7   8   9  10  11  12int d = days[m];if (is_leap_year(y) && m == 2)//判断是否为闰年,如果是闰年返回1,不是闰年返回0d += 1;return d;}int main()
{int year = 0;int month = 0;scanf("%d %d", &year, &month);int day = get_days_of_month(year, month);printf("%d\n", day);return 0;
}

如果想使用 bool ,需要添加头文件 #include <stdbool.h> 

链式访问

链式访问就是将一个函数的返回值作为另一个函数的参数,像链条一样将函数串起来就是函数的链式访问。

#include<string.h>
int main()
{size_t len = strlen("abcdef");printf("%zd", len);return 0;
}
//求len的长度更简洁:
#include<string.h>
int main()
{printf("%zd", strlen("abcdef"));return 0;
}

补充:printf 函数返回的是打印在屏幕上字符的个数

#include<string.h>
int main()
{printf("%d", printf("%d", printf("%d", 43)));return 0;
}输出:4321

 上面例子中,第一个printf打印的是第二个printf的返回值,第二个printf打印的是第三个peintf的返回值

第三个printf打印43,在屏幕上打印两个字符再返回2

第二个printf打印2,在屏幕上打印一个字符再返回1

第一个peintf打印1

最终打印结果为4321

8..函数的声明和定义

单个文件

//函数的声明
int is_leap_year(int y);int main()
{int year = 0;scanf("%d", &year);//函数调用if (is_leap_year(year))printf("闰年\n");elseprintf("不是闰年\n");return 0;
}//函数定义
int is_leap_year(int y)
{return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
}
  • 函数定义是一种特殊的声明
  • 函数声明要在使用之前

多个文件

函数的声明一般会放在头文件( .h )中,自己写的头文件用 "  " 包含

函数的定义放在  .c  文件中

头文件封装在属性里边更改文件类型为lib静态库(动态库.dll)

使用时导入静态库#pragma comment(lib,"add.lib")

有些编译环境默认不支持多文件编译

static和extern

static 和 extern 都是C语言中的关键字。

static 是 静态的 意思,可以用来:

  • 修饰局部变量
  • 修饰全局变量
  • 修饰函数

extern 是用来声明外部符号的

#include<stdio.h>
void test()
{int a = 5;a++;printf("%d", a);}int main()
{int i = 0;for (i = 0; i < 5; i++){test();}return 0;
}输出:66666
#include<stdio.h>
void test()
{static int a = 5;a++;printf("%d", a);}int main()
{int i = 0;for (i = 0; i < 5; i++){test();}return 0;
}输出:678910

上述代码使用static时,上一次使用代码返回值会再次使用(代码运行时不执行)

结论:static 修饰局部变量改变了变量的生命周期,生命周期的改变本质是改变了变量的存储类型,本来一个局部变量是存储在内存的栈区的,但是被static修饰后存储到了静态区。存储在静态区的变量和全局变量是一样的,生命周期就和程序的生命周期一样了,只有程序结束,变量才销毁,内存才回收。但作用域是不变的。

补充:

作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效(可用)的,而限定这个名字的可用性代码范围就是这个名字的作用域。

  1. 局部变量的作用域是变量所在的局部范围。
  2. 全局变量的作用域是整个工程(项目)。

生命周期指的是变量的创建(申请内存)到变量销毁(收回内存)之间的一个时间段。

  1. 局部变量的生命周期是:进入作用域变量创建,生命周期开始,出作用域生命周期结束。
  2. 全局变量的生命周期是:整个程序的生命周期。

栈区:局部变量,形式参数

堆区:动态内存,分配,malloc,calloc,realloc/free

静态区:全局变量,静态变量

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

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

相关文章

Ubuntu 22.04上安装Miniconda

在Ubuntu 22.04上安装Miniconda&#xff0c;可以按照以下步骤进行&#xff1a; 步骤1&#xff1a;更新系统 首先&#xff0c;更新您的系统软件包&#xff1a; sudo apt update sudo apt upgrade -y步骤2&#xff1a;下载Miniconda安装脚本 访问Miniconda的官方网站或使用以下…

IAR全面支持旗芯微车规级MCU,打造智能安全的未来汽车

中国上海&#xff0c;2024年10月18日 — 在全球汽车电子快速发展的今天&#xff0c;IAR与苏州旗芯微半导体有限公司&#xff08;以下简称“旗芯微”&#xff09;联合宣布了一项激动人心的合作——IAR Embedded Workbench for Arm 9.60.2版本现已全面支持旗芯微车规级MCU&#x…

【Docker】docker | 部署nginx

一、概述 记录下nginx的部署流程&#xff1b;将conf配置文件映射到宿主机 前提依赖&#xff1a;自行准备nginx的镜像包 二、步骤 1、运行、无映射 docker run --name nginx -p 80:80 -d nginx:1.18.0-alpine 80&#xff1a;80&#xff0c;前面是宿主机端口&#xff1b;如果冲…

IPsec简单介绍

VPN相关介绍 VPN&#xff1a;虚拟私有网络 例如&#xff1a;像这种不加密的 PPTPL2TP ------- 一般用在windows server 服务端&#xff08;但是大多数企业不用这个&#xff09; 假如总公司内部的PC1要去访问分公司内部的PC2&#xff08;一般用在公司服务器有内网的服务&#…

vue需要清除定时器和延时器吗

在更新组件时清除定时器&#xff1a; 如果你的定时器是在组件的更新过程中创建的&#xff0c;你可能需要在更新前清除它&#xff0c;以免重复创建。你可以在组件的beforeUpdate钩子中清除定时器。 例如&#xff0c;在Vue2中&#xff0c;你可以这样清除定时器&#xff1a; exp…

【知识科普】今天聊聊前端打包工具webpack

文章目录 webpack概述1. 入口&#xff08;Entry&#xff09;2. 输出&#xff08;Output&#xff09;3. Loader4. 插件&#xff08;Plugins&#xff09;5. 模式&#xff08;Mode&#xff09;6. 浏览器兼容性&#xff08;Browser Compatibility&#xff09;7. 环境&#xff08;En…

Oracle 使用位图索引 Cost降低200倍! 探讨位图索引的利与弊

一.简介 位图索引&#xff08;Bitmap Index&#xff09; 是 Oracle 数据库中一种特殊类型的索引&#xff0c;适用于低基数&#xff08;Low Cardinality&#xff09;列&#xff0c;即那些列中可选值相对较少的情况下使用。它与常规的 B-tree 索引不同&#xff0c;位图索引通过位…

Vue组件学习 | 二、Vuex组件

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式和库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。以下是 Vuex 的基本用法 Vuex 基本用法 安装 Vuex 首先&#xff0c;你需要安装 Vuex。如果你使用的是 n…

003:无人机概述

摘要&#xff1a;本文介绍无人机的定义和分类、无人机系统定义、民用无人机驾驶员分类和应用领域。 一、无人机的定义和分类 1.无人机定义 无人机是一种能够在无人驾驶的条件下完成复杂空中飞行任务和各种负载任务的飞行器&#xff0c;可以被视为“空中机器人”。它利用先进的…

(48)MATLAB使用firls函数设计均衡器

文章目录 前言一、频域均衡器的设计二、MATLAB源代码1.firls函数与freqz函数2.MATLAB仿真源代码3.代码说明 三、仿真结果画图 前言 利用MATLAB的firls函数&#xff0c;根据所要求的频率向量和频响幅度向量&#xff0c;设计出所需的均衡器&#xff0c;使得包括滤波器在内的系统…

【python爬虫】python的requests模块使用`Session`对象可以保持会话状态,自动处理Cookie等信息

1. 请求发送 网络爬虫的第一步是发送HTTP请求。Python中的requests库是发送请求的首选工具&#xff0c;它简单易用且功能强大。 使用requests库 import requestssession requests.Session() session.headers {"User-Agent": "Mozilla/5.0",# 其他请求…

qt 构建、执行qmake、运行、重新构建、清除

qt右键功能有 构建、执行qmake、运行、重新构建、清除&#xff0c;下面简单介绍一下各个模块的作用。 1. 执行qmake qmake是一个工具&#xff0c; 它根据pro文件生成makefile文件&#xff0c;而makefile文件中则定义编译与连接的规则。pro文件中定义了头文件&#xff0c;源文件…

C语言_通讯录_进阶

引言&#xff1a;在之前的项目中&#xff0c;我们所用的通讯录是静态版本&#xff0c;也就是常规的固定数组大小&#xff0c;但仔细思考&#xff0c;在现实的复杂环境中&#xff0c;是很难做到这样死板&#xff0c;所以在学习过动态内存的章节后&#xff0c;我们将通讯录重新修…

Spring Cache Caffeine 高性能缓存库

​ Caffeine 背景 Caffeine是一个高性能的Java缓存库&#xff0c;它基于Guava Cache进行了增强&#xff0c;提供了更加出色的缓存体验。Caffeine的主要特点包括&#xff1a; 高性能&#xff1a;Caffeine使用了Java 8最新的StampedLock乐观锁技术&#xff0c;极大地提高了缓存…

三国杀钓鱼自动化

三国杀钓鱼脚本 前言 本来是想做必杀的&#xff0c;但是后来测试了大约400钓发现纯靠连点没有漏掉的鱼&#xff0c;所以必杀功能就舍弃了。 我pyinstaller打包后运行.exe居然黑屏了&#xff1f;&#xff1f;&#xff1f;可能是多进程报错处理没写好&#xff0c;反正还是用vsc…

笔试第五行

static作用&#xff1a; 1.函数体内&#xff0c;一个被声明为静态的变量在这一函数被调用时值维持不变。 2.函数体外&#xff0c;模块内&#xff0c;一个被声明为静态的变量可以被模块内函数访问&#xff0c;但不能模块外函数访问&#xff0c;这是一个本地的全局变量。 3.模…

k8s部署使用有状态服务statefulset部署eureka集群,需登录认证

一、构建eureka集群镜像 1、编写dockerfile文件&#xff0c;此处基础镜像为arm版本&#xff0c;eureka目录中文件内容&#xff1a;application-dev.yml、Dockerfile、eureka-server-1.0-SNAPSHOT.jar(添加登录认证模块&#xff0c;文章最后附上下载连接) FROM mdsol/java8-j…

Go使用exec.Command() 执行脚本时出现:file or directory not found

使用 Go 提供的 exec.Command() 执行脚本时出现了未找到脚本的 bug&#xff0c;三个排查思路 &#xff1a; exec.Command(execName, args…) 脚本名字不允许相对路径 exec.Command(execName, args…) execName 只能有脚本名&#xff0c;不允许出现参数 如果你是使用 Windows …

为什么要使用网络IO内存数据库?

1.摘要 学习Redis的时候&#xff0c;我有个疑问&#xff1a;Redis缓存是内存数据库&#xff0c;但是它部署在独立的一个服务器上&#xff0c;那么应用服务器访问redis不是要通过网络吗&#xff0c;那么是不是还不如从本地服务器读取数据库的效率 &#xff1f;结论是&#xff1a…

Ubuntu github 网速慢 打不开

1.在ipaddress 网站查找一下github的dns 并复制到/etc/hosts https://www.ipaddress.com/website/github.com/ 140.82.113.4 github.com 185.199.108.133 raw.githubusercontent.com #185.199.109.133 raw.githubusercontent.com #185.199.110.133 raw.githubusercontent.com …