C语言学习笔记(六): 探索函数与变量

news2024/9/22 11:30:01

函数的定义

image-20211214210659467

形参和实参

在定义函数时函数名后面括号中的变量名称为“形式参数”(简称“形参”)或“虚拟参数”。

在主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”(简称“实参”)。

当函数被调用时,系统为形参分配内存空间。无论形参与实参的名称是否相同,它们都各自占用自己的存储空间。


函数的声明

函数声明是在程序中声明函数的名称、参数列表和返回类型的语句。它不包括函数的主体,也就是实际的代码。它的目的是向编译器说明接下来将定义的函数的类型,以便编译器知道如何处理函数调用

在函数声明中的形参名可以省略,只写形参的类型。

float add(float x, float y);
float add(float, float);		//不写参数名,只写参数类型
float add(float a,  float b);	//参数名不用x,y,而用a,b。合法

函数的递归调用

在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。

程序中不应出现无终止的递归调用,而只应出现有限次数的、有终止的递归调用,这可以用if语句来控制,只有在某一条件成立时才继续执行递归调用;否则就不再继续。


例如这个例子,有5个学生坐在一起,问第5个学生多少岁,他说比第4个学生大2岁。问第4个学生岁数,他说比第3个学生大2岁。问第3个学生,又说比第2个学生大2岁。问第2个学生,说比第1个学生大2岁。最后问第1个学生,他说是10岁。请问第5个学生多大1.

include <stdio.h>
int main()
{	int age(int n);					//对age函数的声明
	printf("NO.5,age:%d\n",age(5)); 	//输出第5个学生的年龄
	return 0;
} 

int age(int n) 						//定义递归函数
{	int c; 						//c用作存放函数的返回值的变量
	if(n==1) 						//如果n等于1
		c=10;					//年龄为10
	else 							//如果n不等于1
		c=age(n-1)+2;			//年龄是前一个学生的年龄加2(如第4个学生年龄是第3个学生年龄加2)
	return(c); 					//返回年龄
}

数组作为函数参数

数组元素可以用作函数实参,但是不能用作形参。

因为形参是在函数被调用时临时分配存储单元的,不可能为一个数组元素单独分配存储单元(数组是一个整体,在内存中占连续的一段存储单元)。

在用数组元素作函数实参时,把实参的值传给形参,是==“值传递”==方式。数据传递的方向是从实参传到形参,单向传递。

数组可以作为函数实参,通过==“地址传递”==的方式将值传递给形参

int test(int *p) {
	int i = p[0];
	return i;
}

int main()
{
	int a[] = { 1,2,3,4,5 };
	printf("%d", test(a)); //数组作为实参
}

一维数组作函数参数

例如下述例子,有一个一维数组score,内放10个学生成绩,求其平均成绩。函数的实参是一个数组名,其本质上属于值传递

include <stdio.h>
int main()
{	float average(float array[],int n);
	float score[10]={67.5,89.5,99,69.5,77,89.5,76.5,54,60,99.5};//定义长度为10的数组

	printf("The average of class B is %6.2f\n",average(score,10)); //用数组名score和10作实参
	return 0;
}

float average(float array[],int n) //定义average函数,未指定形参数组长度
{	int i;
	float aver,sum=array[0];
	for(i=1;i<n;i++)
		sum=sum+array[i];	    //累加n个学生成绩
	aver=sum/n;
	return(aver);
}

二维数组作函数参数

image-20211215221924729


如下例子所示, 有一个3×4的矩阵,求所有元素中的最大值。可以发现函数的参数是一个二维数组

include <stdio.h>
int main()
{	int max_value(int array[][4]);		//函数声明
	int a[3][4]={{1,3,5,7},{2,4,6,8},{15,17,34,12}};	 //对数组元素赋初值
	printf("Max value is %d\n",max_value(a));
	//max_value(a)为函数调用
	return 0;
}

int max_value(int array[][4])	//函数定义
{	int i,j,max;
	max=array[0][0];
	for(i=0;i<3;i++)
		for(j=0;j<4;j++)
			if(array[i][j]>max) max=array[i][j];	//把大者放在max中
	return(max);
}

局部变量和全局变量

局部变量

在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为“分程序”或“程序块”。

形式参数也是局部变量。只在定义它的函数中有效。其他函数中不能直接引用形参。


全局变量

函数之外定义的变量称为外部变量,外部变量是全局变量(也称全程变量)。全局变量可以为本文件中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束。

若函数内的局部变量和全局变量同名,则局部变量会覆盖全局变量。


变量的生存期

从变量值存在的时间(即生存期)来观察,有的变量在程序运行的整个过程都是存在的,而有的变量则是在调用其所在的函数时才临时分配存储单元,而在函数调用结束后该存储单元就马上释放了,变量不存在了。


变量的存储方式

静态存储方式

静态存储的变量通常在程序整个生命周期中存在,不能在运行期间被删除,空间分配静态,因此使用静态存储的变量是程序中最常见的存储方式。静态存储的变量可以用关键字 “static” 声明


动态存储方式

动态存储是在程序运行时动态分配空间的存储方式。动态存储的变量可以在运行期间删除,不需要预先分配空间,因此可以根据需要调整内存分配。动态存储的变量用关键字 “malloc” 声明,使用 “free” 释放


变量的存储类别

自动变量

若局部变量不专门声明为static(静态)存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。函数中的形参和在函数中定义的局部变量(包括在复合语句中定义的局部变量),都属于此类。在调用该函数时,系统会给这些变量分配存储空间,在函数调用结束时就自动释放这些存储空间。因此这类局部变量称为自动变量。自动变量用关键字auto作存储类别的声明

int f(int a)			//定义f函数,a为形参
{
	auto int b,c=3;	//定义b,c为自动变量,新版本auto不能加在数据类型前面了
	   
}

静态局部变量

若希望变量调用完后值还留着,即其占用的存储单元不释放,在下一次再调用该函数时,该变量的值就是上次用的值。这时就应该指定该局部变量为静态局部变量,用关键字static进行声明。

静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,分配在动态存储区空间而不在静态存储区空间,函数调用结束后即释放。


寄存器变量

为提高执行效率,允许将局部变量的值放在CPU中的寄存器中,需要用时直接从寄存器取出参加运算,不必再到内存中去存取。这种变量叫做寄存器变量,用关键字register作声明,如register int f;


外部变量

外部变量是在函数的外部定义的全局变量,它的作用域是从变量的定义处开始,到本程序文件的末尾


如下代码所示,在文件内扩展外部变量的作用域

include <stdio.h>
int main()
{	int max();
	extern int A,B,C;	//把外部变量A,B,C的作用域扩展到从此处开始
	printf("Please enter three integer numbers:");
	scanf("%d %d %d",&A,&B,&C);		//输入3个整数给A,B,C
	printf("max is %d\n",max());
	return 0;
}
int A,B,C;				//定义外部变量A,B,C
int max()
{	int m;
	m=A>B?A:B;		//把A和B中的大者放在m中
	if(C>m) m=C;		//将A,B,C三者中的大者放在m中
	return(m);		//返回m的值
}

如下代码所示,将外部变量的作用域扩展到其他文件

include <stdio.h>
int A;				//定义外部变量
int main()
{	int power(int);		//函数声明
	int b=3,c,d,m;
	printf("enter the number a and its power m:\n");
	scanf("%d,%d",&A,&m);
	c=A*b;
	printf("%d*%d=%d\n",A,b,c);
	d=power(m);
	printf("%d**%d=%d\n",A,m,d);
	return 0;
}
extern A;
//把file1中定义的外部变量的作用域扩展到本文件
int power(int n)
{	int i,y=1;
	for(i=1;i<=n;i++)
	y*=A;
	return(y);
}

若不希望本文件的变量被外部文件引用,可以使用关键字static声明变量

image-20211217200751491


变量的声明

  • 定义性声明:像int a这种需要建立存储空间的,称为定义性声明
  • 引用性声明:像extern int a这种不需要建立存储空间的,称为引用性声明

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

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

相关文章

独自开:提供创业机会、享受平台分红、推出新颖赚钱副业

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 前言 独自开&#xff1a;一款聚焦软件定制开发&#xff0c;独立、自主、开放平台 独创分层标准化平台架构,满足系统不断生长的个性化需求多端一键部署前端业务交互与展…

KMP算法详解

注意&#xff1a;PC阅读效果更佳&#xff0c;建议阅读的同时完成代码实践加深理解一、问题描述指定文本串&#xff1a;aabaabaaf和模式串&#xff1a;aabaaf使用KMP算法判断模式串是否在文本串中出现过&#xff1f;假定模式串的长度小于文本串二、思路解析BF算法的问题是&#…

【pytorch安装】conda安装pytorch无法安装cpu版本(完整解决过程)

问题描述 在安装pytorch过程中&#xff0c;发现最后验证torch时总是返回结果为False&#xff0c;结果翻上去发现自己安装的是cpu版本的。 然后又通过conda去更换不同版本尝试&#xff0c;发现都是cpu版本的。 问题分析 通过conda安装pytorch是从源中搜索匹配指令中的文件&am…

@Validated注解不生效问题汇总

Validated注解不生效问题汇总 文章目录Validated注解不生效问题汇总背景&#xff1a;一&#xff1a;可能原因原因1&#xff1a;原因2&#xff1a;原因3&#xff1a;原因4&#xff1a;二&#xff1a;补充全局异常对validation的处理背景&#xff1a; 项目框架应用的是validatio…

捕鱼大作战协议解密

捕鱼大作战协议解密协/议/流/量/解/密分析捕鱼大作战这款游戏流量的加密方式及解密方法。序捕鱼大作战是tuyoo公司在很多年前上线的一款休闲游戏&#xff0c;对&#xff0c;就是那个之前本号批斗过的途游&#xff0c;这款游戏以海洋深处作为背景&#xff0c;玩家通过在海底施展…

D31 Vue2 + Vue3 K104-K123

D31.Vue F17.打包 图片懒加载&#xff08;K104-K106&#xff09; 1.打包 1&#xff09;vue.config.js module.exports {//打包时不生成map文件(用来进行错误提示的文件&#xff0c;很占用空间)productionSourceMap: false,// 关闭ESLINT校验工具lintOnSave: false, }pnp…

学完Scrapy-Splash秒变爬虫大佬

在做爬虫的时候&#xff0c;大多数的网页中会存在数据动态加载的部分&#xff0c;而且多数都是后期渲染上的。正常情况下爬虫程序仅能爬取被渲染过的数据。因此我们看到的数据也许并非是爬虫直接获取来的。 而scrapy-splash担任了一个中间人的角色&#xff0c;程序通过splash服…

吴思进——复杂美创始人首席执行官

杭州复杂美科技有限公司创始人兼CEO, 本科毕业于浙江大学机械专业&#xff0c;辅修过多门管理课程&#xff1b;1997年获经济学硕士学位&#xff0c;有关对冲基金的毕业论文被评为优秀&#xff1b;2008年创办杭州复杂美科技有限公司。 吴思进 中国电子学会区块链委员会专家&…

计算机网络-基本概念

目录 计算机网络-基本概念 互联网 Java的跨平台原理 ​编辑 C\C的跨平台原理 解释性语言的跨平台原理(python,js等) 客户端 vs 服务器 什么是协议&#xff1f; 网络互连模型 请求过程 计算机之间的通信基础 计算机之间的连接方式-网线直连(需要用交叉线&#xff0c;而…

GIS数据经纬度投影坐标转换总结(涵盖几乎全行业的坐标转换方法)

在处理GIS数据的过程中,避免不了要与坐标和坐标系打交道。这篇文章对能够进行地理坐标转换的所有软件框架做一个一次性总结。 软件类: 1.arcgis arcgis能够进行很全面的很方便的坐标处理,无论是经纬度坐标转投影坐标还是投影坐标转经纬度坐标都非常的简单。arcgis能够对导…

Qt编写视频监控系统70-0SD标签和图形信息(支持写入到文件)

一、前言 作为一个完整的视频监控系统&#xff0c;用户还需要自定义一些OSD标签信息显示在对应通道上面&#xff0c;而且不止一个OSD标签信息&#xff0c;位置可以在四个角或者指定坐标显示。最开始本系统设计的时候&#xff0c;由于本人擅长的是painter绘制&#xff0c;所以直…

MySQL视图特性

文章目录MySQL视图特性基本使用准备测试表创建视图修改视图影响基表修改基表影响视图删除视图视图规则和限制MySQL视图特性 视图的概念 视图是一个虚拟表&#xff0c;其内容由查询定义&#xff0c;同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图中的数据…

opencv读取摄像头和视频数据

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…

TensorRT和DLA(Deep Learning Accelerator)

TensorRT和DLA(Deep Learning Accelerator) 点击此处加入NVIDIA开发者计划 文章目录TensorRT和DLA(Deep Learning Accelerator)12.1. Running On DLA During TensorRT Inference注意&#xff1a;对于任何张量&#xff0c;索引维度的总体积加上请求的批量大小不得超过此函数返回…

Docker 面试知识点

Docker 是什么&#xff1f; 是实现容器技术的一种工具是一个开源的应用容器引擎使用 C/S 架构模式&#xff0c;通过远程API 来管理 (我们本机是 C&#xff0c;docker 引擎是 S,实际的构建过程是在 docker 引擎下完成的)可以打包一个应用及依赖包到一个轻量级、可移植的容器中 …

Hbase 数据迁移

Hbase 数据迁移 可选方案对比 l 已验证方案操作说明&#xff1a; n Export&import u 导出命令及示例 hbase org.apache.hadoop.hbase.mapreduce.Export “表名” 文件路径 导出至本地文件系统&#xff1a; ./bin/hbase org.apache.hadoop.hbase.mapreduce.Export ‘defa…

UnityBurst系统批量计算的插件入门

什麽是Burst系統做一些批量計算需要&#xff0c;比较难用&#xff0c;针无两头利如果不需要“密集”计算&#xff0c;就帧的不需要&#xff0c;到底什么是密集计算呢&#xff0c;for循环不密集么&#xff0c;while循环不密集么&#xff1f;安装Burst因为发现一个不错项目的插件…

Zookeeper实现分布式锁

文章目录ZK节点类型watch监听机制Zookeeper实现分布式锁锁原理创建锁的过程释放锁的过程ZK锁的种类代码实现Zookeeper是一个开源的分布式协调服务&#xff0c;是一个典型的分布式数据一致性解决方案。 分布式应用程序可以基于Zookeeper实现诸如数据发布/订阅&#xff0c;负载均…

【C/C++基础练习题】简单指针与数组使用练习题

&#x1f349;内容专栏&#xff1a;【C/C要打好基础啊】 &#x1f349;本文内容&#xff1a;简单指针与数组练习题&#xff08;复习之前写过的实验报告&#xff09; &#x1f349;本文作者&#xff1a;Melon西西 &#x1f349;发布时间 &#xff1a;2023.2.12 目录 1.vector​编…

async thunk 解决 API 调用的依赖问题

async thunk 解决 API 调用的依赖问题 一句话节省看下面一堆内容的时间就是&#xff1a; async thunk 中可以使用 async/await 锁住其他的 action 操作 一般 API 之间存在三种情况&#xff1a; A 和 B 之间没有依赖关系 这样的情况下&#xff0c;A 和 B 可以各调用各的&#x…