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

函数的定义

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这种不需要建立存储空间的,称为引用性声明
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值