初阶C语言-函数(上)

news2024/9/28 3:30:43

“追光的人,终会光芒万丈!” 今天我们一起来学习一下函数的相关知识点。

函数

  • 1.函数是什么?
  • 2.C语言中函数的分类
    • 2.1库函数
    • 2.2自定义函数
  • 3.函数的参数
    • 3.1实际参数(实参)
    • 3.2形式参数(形参)
  • 4.函数的调用
    • 4.1传值调用
    • 4.2传址调用
    • 4.3练习

1.函数是什么?

数学中我们常见函数的概念,在数学中,函数通常是解决自变量与因变量之间关系的问题。那么,在C语言中,函数是做什么的呢?维基百科中对函数的定义为:子程序

在计算机中,子程序是一个大型程序中的某部分代码,由一个或多个语句块组成。它负责完成某项特定任务,而且较其他代码,相对独立。一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。

2.C语言中函数的分类

  1. 库函数
  2. 自定义函数

2.1库函数

为什么会有库函数呢?

1.我们在学习C语言编程的时候,总是在一个代码编写完成后迫不及待的想知道结果,想把这个结果打印在我们的屏幕上,这个时候我们就会频繁的使用一个功能:将信息按照一定格式打印到屏幕上(printf
2.在编程的过程中,我们会频繁的做一些字符串的拷贝工作(strcpy
3.在编程的过程中我们也会计算,比如计算n的k次方(pow

像上述我们描述的基本功能,它们不是业务性的代码。我们在开发的过程中每一个程序员都可以用到,为了支持可移植性和提高程序的效率,所有C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。

需要注意的是库函数不是C语言提供的,是C语言标准中约定好,由编译器的厂商提供实现。

下面给出示例:

在C语言的标准中,对于strlen函数做出以下规定:
1.函数的功能-求字符串的长度
2.函数名-strlen
3.参数- const char*str
4.返回类型- size_t
以上规定是C语言规定好的,具体的函数实现是由不同的厂商实现的。

那么,库函数到底有哪些呢?我们可以去查看该网站:库函数查找的链接
在这里插入图片描述
简单的总结,C语言中常用的库函数都有:

  1. IO函数(标准输入输出头文件#include <stdio.h>
  2. 字符串操作函数(strlen、strcpy等函数的头文件为#include <string.h>
  3. 内存操作函数(头文件为#include <malloc.h>
  4. 时间/日期函数(头文件为#include <time.h>
  5. 数学函数(头文件为#include <math.h>
  6. 其他库函数

具体的函数及用法,大家可以查阅上面的网站学习。这里,我们给大家简单介绍几种库函数及其使用。

1.pow函数(头文件为#include <math.h>
通过查阅网站我们可以了解到该函数的使用方法:
在这里插入图片描述
接下来,让我们一起来试着用一下这个函数吧!

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <math.h>
int main()
{
	int ret = (int)pow(3, 5);//由于pow函数是float型,所以可以强制类型转化为int型
	printf("%d", ret);
	return 0;
}

这里,我们建议大家把pow的返回类型强转为int型,因为我们给出的样例输入是整型,不强转的话会给出警告。
在这里插入图片描述

在这里插入图片描述
2.strcpy函数(头文件为#incude <string.h>
同样的,我们可以先查找网站,看看该函数的相关用法。
在这里插入图片描述

//strcpy函数
#include <stdio.h>
int main()
{
	char arr1[20] = "xxxxxxxxxxxxxxxxxxxx";
	char arr2[] = "Hello C World!";
	strcpy(arr1, arr2);
 printf("%s\n", arr1);
	return 0;
}

在这里插入图片描述
不难发现strcpy函数就是起到的一个复制的作用,那么字符串的结束标志是否被一同复制过去呢?这里,我们可以调试运行着看一下。
在这里插入图片描述
注:我们可以发现strcpy函数会将'\0'一同复制过去!

3.memset函数(头文件为#incude <string.h>
在这里插入图片描述

//memset函数
#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "Hello C World!";
	memset(arr, 'x', 5);
	printf("%s\n", arr);
	return 0;
}

在这里插入图片描述
注:使用库函数必须要包含#include对应的头文件

2.2自定义函数

如果库函数能解决所有的问题,那么还需要程序员干嘛呢?所以,更多的时候还是需要用到自定义函数。自定义函数和库函数一样,有函数名、返回类型和函数参数。但是不一样的是这些是我们自己来设计的,给了程序员很大的发挥空间。

//函数的组成:
ret_type fun_name(paral,*)
{
    statement;//语句项
}
//ret_type-返回类型
//fun_name-函数名
//paral-函数参数

下面我们举一个例子,写一个函数可以找出两个整数中的最大值。

//写出一个函数求两个数的最大值
#include <stdio.h>
int get_max(int x, int y)
{
	if (x > y)
		return x;
	else
		return y;
}
int main()
{
	int num1 = 0;
	int num2 = 0;
	scanf("%d%d", &num1, &num2);
	int max = get_max(num1, num2);
	printf("%d\n", max);
	return 0;
}

在这里插入图片描述
我们再举一个例子,写一个函数可以交换两个整型变量的内容。

#define _CRT_SECURE_NO_WARNINGS 1
//写一个函数可以交换两个整型变量的内容
#include <stdio.h>
void swap(int x, int y)//形式参数
{
	int t;
	t = x;
	x = y;
	y = t;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d%d", &a, &b);
	printf("交换前:%d %d\n", a, b);
	swap(a, b);//实际参数
	//函数调用时将实参传给形参,形参其实是实参的一份临时拷贝
	//对形参的修改不会改变实参
	printf("交换后:%d %d\n", a, b);
	return 0;
}

通过前面所学,我们知道了交换两个变量的值需要用到中间变量t,那么这样写出来的代码是否正确呢?
在这里插入图片描述
我们可以发现两个整型变量的内容并没有发生交换,遇到问题的时候,我们试着自己调试着发现问题!
在这里插入图片描述
通过调试,我们发现,形参和实参的地址不一样,因此对形参的修改不会改变实参,这时候考虑到地址,我们应该就想到了前面提及的指针,那我们再把代码修改一下来实现我们希望的功能。

#include <stdio.h>
void swap2(int *x, int *y)
{
	int t;
	t = *x;//t = a
	*x = *y;//a = b
	*y = t;//b = t
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d%d", &a, &b);
	printf("交换前:%d %d\n", a, b);
	swap2(&a, &b);//实际参数
	printf("交换后:%d %d\n", a, b);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

3.函数的参数

3.1实际参数(实参)

真实的传给函数的参数,叫实参。
实参可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

int max(int x, int y)
{
	if (x > y)
		return x;
	else
		return y;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d%d", &a, &b);
	max(3, 6);//实参是常量
	max(a, 6);//实参是变量
	max(b, max(a, 4));//实参是函数
	max(a, 3 + 5);//实参是表达式
	return 0;
}

3.2形式参数(形参)

形式参数是指函数名后括号中的变量,因为 形式参数只有在函数被调用的过程中,才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。

#include <stdio.h>
void swap1(int x, int y)
{
	int tep = 0;
	tep = x;
	x = y;
	y = tep;
}
void swap2(int* p1, int* p2)
{
	int tep = 0;
	tep = *p1;
	*p1 = *p2;
	*p2 = tep;
}
int main()
{
	int num1 = 1;
	int num2 = 2;
	swap1(num1, num2);
	printf("swap1:%d %d\n", num1, num2);
	swap2(&num1, &num2);
	printf("swap2:%d %d\n", num1, num2);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这里我们可以看到swap1函数在调用的时候,x、y拥有自己的空间,同时拥有了和实参一模一样的内容。所以,我们可以简单认为:形参实例化之后相当于实参的一份临时拷贝

4.函数的调用

4.1传值调用

函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参。

4.2传址调用

传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。

4.3练习

1.写一个函数可以判断一个数是不是素数。

//写一个函数可以判断一个数是不是素数(打印100~200之间的素数)
#include <stdio.h>
#include <math.h>
int is_prime(int x)
{
	int j = 0;
	for (j = 2; j <= sqrt(x); j++)
	{
		if (x % j == 0)
			return 0;
	}
	return 1;
}
int main()
{
	int i = 0;
	for (i = 100; i <= 200; i++)
	{
		if (is_prime(i))
			printf("%d ", i);
	}
	return 0;
}

在这里插入图片描述
这里,我们给大家介绍一下布尔类型(bool),bool类型的变量只有两种取值,true和false.因此,我们也可以用bool类型来写这段程序。

#include <stdio.h>
#include <math.h>
#include <stdbool.h>//bool类型需要添加该头文件
//C语言中有一个bool类型,它的取值只有两种取值true和false
bool is_prime(int x)
{
	int j = 0;
	for (j = 2; j <= sqrt(x); j++)
	{
		if (x % j == 0)
			return false;
	}
	return true;
}
int main()
{
	int i = 0;
	for (i = 100; i <= 200; i++)
	{
		if (is_prime(i))
			printf("%d ", i);
	}
	return 0;
}

在这里插入图片描述

2.写一个函数判断一年是不是闰年。

//写一个函数判断一年是不是闰年。(打印1000~2000之间的闰年)
#include <stdio.h>
#include <stdbool.h>//bool类型的头文件
bool is_leap_year(int x)
{
	if (x % 4 == 0 && x % 100 != 0 || x % 400 == 0)
		return true;
	else
		return false;
}
int main()
{
	int y = 0;
	for (y = 1000; y <= 2000; y++)
	{
		if(is_leap_year(y))
			printf("%d ",y);
	}
	return 0;
}

在这里插入图片描述
3.写一个函数,实现一个整型有序数组的二分查找。

//写一个函数,实现一个整型有序数组的二分查找。
//找到了返回下标,找不到返回-1
int binary_search(int arr[], int n, int sz)
{
	int left = 0;
	int right = sz - 1;
	while (left <= right)
	{
		int mid = (left + right) / 2;
		if (arr[mid] > n)
			right = mid - 1;
		else if (arr[mid] < n)
			left = mid + 1;
		else
			return mid;
	}
	return -1;
}
#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int n = 0;
	scanf("%d", &n);
	int sz = sizeof(arr) / sizeof(arr[0]);
	int ret = binary_search(arr,n,sz);
	if (ret == -1)
	{
		printf("找不到!\n");
	}
	else
		printf("找到了,下标是%d", ret);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
但是,上述代码依然存在着弊端,int mid = (left + right) / 2;针对于left和right数值较小的情况,一旦它们的数值大到一定的时候,会出现溢出的情况。那么,我们该如何求两个数的平均值呢?下面给出图示,我们发现,只需要将b比a多的那部分的一半加到a上就是两者的平均值了,那么代码该如何改进呢?
在这里插入图片描述

int binary_search(int arr[], int n, int sz)
{
	int left = 0;
	int right = sz - 1;
	while (left <= right)
	{
		int mid = left + (right - left) / 2;//更改的地方,目的为了防止数值太大溢出
		if (arr[mid] > n)
			right = mid - 1;
		else if (arr[mid] < n)
			left = mid + 1;
		else
			return mid;
	}
	return -1;
}
#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int n = 0;
	scanf("%d", &n);
	int sz = sizeof(arr) / sizeof(arr[0]);
	int ret = binary_search(arr, n, sz);
	if (ret == -1)
	{
		printf("找不到!\n");
	}
	else
		printf("找到了,下标是%d", ret);
	return 0;
}

我们可以发现这样写出来的程序运行结果与刚刚是一样的!
在这里插入图片描述
在这里插入图片描述
4.写一个函数,每调用一次这个函数,就会将num的值增加1。

//写一个函数,每调用一次这个函数,就会将num的值增加1。
#include <stdio.h>
void add(int *a)
{
	*a = *a + 1;
}
int main()
{
	int num = 0;
	add(&num);
	printf("%d\n", num);
	add(&num);
	printf("%d\n", num);
	add(&num);
	printf("%d\n", num);
	return 0;
}

在这里插入图片描述

好啦,关于函数的知识点就先讲到这里,后期会继续更新,欢迎大家持续关注、点赞和评论!

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

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

相关文章

网络层中一些零碎且易忘的知识点

异构网络&#xff1a;指传输介质、数据编码方式、链路控制协议以及数据单元格式和转发机制不同&#xff0c;异构即物理层和数据链路层均不同RIP、OSPF、BGP分别是哪一层的协议&#xff1a; -RIPOSPFBGP所属层次应用层网络层应用层封装在什么协议中UDPIPTCP 一个主机可以有多个I…

element时间选择器的默认值

概览&#xff1a;vue使用element组件&#xff0c;需要给时间选择器设置默认值&#xff0c;场景一&#xff1a;默认时间选择器&#xff0c;场景二&#xff1a;时间范围选择器&#xff0c;开始时间和结束时间。 一、默认时间选择器 实现思路&#xff1a; element组件的v-model绑…

ELK + Fliebeat + Kafka日志系统

参考&#xff1a; ELKFilebeatKafka分布式日志管理平台搭建_51CTO博客_elk 搭建 ELK 日志分析系统概述及部署&#xff08;上&#xff09;-阿里云开发者社区 ELK是三个开源软件的缩写&#xff0c;分别表示&#xff1a;Elasticsearch , Logstash, Kibana , 它们都是开源软件。…

【1.1】Java微服务:初识微服务

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; 微服务 ✨特色专栏&#xff1a; 知识分享 &#x…

IntelliJ IDEA 2023.2 主要更新了什么?(纯文本介绍版)

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Python 进阶(五):os 模块

❤️ 博客主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;Python 入门核心技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; 文章目录 1. 文件和目录的基本操作1.1 获取当前工作目录1.2 更改当前工作目录1.3 获取目录下所有…

【Linux进程篇】冯诺依曼体系

【Linux进程篇】冯诺依曼体系 目录 【Linux进程篇】冯诺依曼体系冯诺依曼体系结构&#xff08;1/3内容 &#xff09;操作系统(Operator System)概念设计OS的目的定位如何理解“管理”总结系统调用和库函数的概念 作者&#xff1a;爱写代码的刚子 时间&#xff1a;2023.7.28 前言…

EMO:重新思考高效的基于注意力的移动块模型

文章目录 摘要1、介绍2、方法论:归纳法和演绎法2.1、通用效率模型标准2.2、元移动块2.3、微设计:倒置残余移动块2.4、面向密集预测的EMO宏观设计 3、实验3.1、图像分类3.2、下游任务3.3、额外的消融和解释分析 4、相关工作5、结束语及未来工作 摘要 论文链接&#xff1a;https…

【ray】 分布式计算的搭建和调用以及项目实践

目录 0 RAY相关资料1 ray的简要介绍2 ray的搭建3 ray的调用4 实践代码分析4.1 ray的配置4.2 代码中使用ray 0 RAY相关资料 ray 官网&#xff1a;https://docs.ray.io/en/latest/index.html Ray分布式计算框架详解&#xff1a;https://zhuanlan.zhihu.com/p/460600694 b站视频…

OpenLayers入门,地图全图显示经纬度网格标记线

专栏目录: OpenLayers入门教程汇总目录 前言 使用OpenLayers实现地图全图显示经纬度网格标记线。方便查看可视区域所处的经纬度区间。 二、依赖和使用 "ol": "^6.15.1"使用npm安装依赖npm install ol@6.15.1使用Yarn安装依赖yarn add olvue中如何使用…

MODBUS-TCP转Ethernet IP 网关连接空压机 配置案例

本案例是工业现场应用捷米特JM-EIP-TCP的Ethernet/IP转Modbus-TCP网关连接欧姆龙PLC与空压机的配置案例。使用设备&#xff1a;欧姆龙PLC&#xff0c;捷米特JM-EIP-TCP网关&#xff0c; ETHERNET/IP 的电气连接 ETHERNET/IP 采用标准的 T568B 接法&#xff0c;支持直连和交叉接…

github Recv failure: Connection reset by peer

Recv failure: Connection reset by peer 背景处理ping一下github网页访问一下github项目git配置git ssh配置再次尝试拉取 疑惑点待研究参考 背景 晚上敲着代码准备提交&#xff0c;执行git pull&#xff0c;报错Recv failure: Connection reset by peer。看着这报错我陷入了沉…

Spring Cloud Eureka 服务注册和服务发现超详细(附加--源码实现案例--及实现逻辑图)

文章目录 EurekaEureka组件可以实现哪些功能什么是CAP原则&#xff1f;服务注册代码实战搭建注册中心服务A搭建服务B搭建启动服务启动注册中心启动服务A启动服务B 结束语 Eureka 这篇文章先讲述一下Eureka的应用场景、代码实现案例&#xff0c;多个服务模块注册到Euraka中&…

QT多线程的示例

想象现在有一个场景&#xff0c;一共有三个线程线程A需要产生1000以内的随机数&#xff0c;线程B需要对这些随机数进行冒泡排序&#xff0c;线程C需要对这些随机数进行快速排序&#xff0c;主线程用来显示线程A的随机数&#xff0c;并且显示线程A和线程B的处理结果&#xff0c;…

机器学习 | Python实现NARX模型预测控制

机器学习 | Python实现NARX模型预测控制 目录 机器学习 | Python实现NARX模型预测控制效果一览基本介绍研究内容程序设计参考资料效果一览 基本介绍 机器学习 | Python实现NARX模型预测控制 研究内容 贝叶斯黑盒模型预测控制,基于具有外源输入的非线性自回归模型的预期自由能最…

后端通过CorsRegistry对象配置了全局跨域,但是前端仍然报CORS跨域错误

后端通过CorsRegistry配置了全局跨域&#xff0c;但是前端仍然报CORS跨域错误 问题背景 在实现登录功能时&#xff0c;我先是通过CorsRegistry配置了全局跨域&#xff0c;然后配置了一个登录拦截器后前端就报错CORS跨域错误 问题原因 前置知识 首先我们来了解一下什么是跨域错误…

hw技战法整理参考

目录 IP溯源反制 账户安全策略及预警 蜜罐部署联动方案

【42万字,2902页】全网最全《零基础网络安全/黑客自学笔记》,爆肝分享!

这次为大家带来一份零基础也能学会的《全网最全黑客自学笔记》&#xff0c;“全网最全”可不是吹牛的&#xff0c;整个笔记一共42万字&#xff0c;2902页&#xff0c;95个章节。 这份笔记涵盖了网络安全导论、渗透测试基础、网络基础、Linux操作系统基础、web安全等等入门知识…

基于应用值迭代的马尔可夫决策过程(MDP)的策略的机器人研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【SSM】问题集锦(持续更新)

目录 1.错误500&#xff1a;Servlet.init() for servlet DispatcherServlet threw exception Error creating bean with name ‘sqlSessionFactory’ defined in class path reso 主要解决方法可参考这篇文章 我自己的问题是因为spring上下文应用程序关联问题 2.org.apache.c…