入门C语言——函数

函数定义

函数的使用是为了避免代码冗长,重复。预先定义的函数也叫做API,为了模块化设计,在函数体中事先写好相应功能性的代码,需要使用时,直接调用这些API。

函数先定义再使用,定义方式三要素:返回值类型 函数名 参数列表。函数名要做到"见名知意",驼峰命名法。

函数调用

调用条件

只有被定义的函数才能被调用,使用库函数的话,需要引入头文件,如果函数定义的位置在main函数的后边,需要在main函数前,做函数声明,写出函数的三要素。

函数嵌套

因为函数具有返回值,所以函数调用时候可以作为其他函数的参数。

不同函数之间可以互相调用,函数体中调用了其他函数,就是函数的嵌套,程序运行时会一层一层进入函数,然后进入到最后一层得到返回值后,又将返回值一层一层返回,然后回到第一层函数。

函数递归

函数递归相当于特殊的函数嵌套,嵌套的函数是他自己本身。注意:函数递归一定要写退出条件,不然会有可能会死循环。

参数

形式参数

形式参数是定义函数时,括号里面的参数。

实际参数

实际参数是调用函数时,括号里面的参数。

调用时的关系

函数类似一个有功能的黑匣子,在调用时,需要我们给他数据,函数便对数据进行操作,操作完之后,给我们一个结果。所以函数体和形式参数是一个功能框架,调用时给的数据便是实际参数,函数把实际参数的值,赋值给形式参数,整个过程中操作的也是形式参数,而不是实际参数。因为调用时操作的是形式参数那么在函数调用期间,实际参数不会发生改变。最后调用结束会将得到的相应结果,返回到主函数。

形式参数和实际参数是两个不同的存储单元,而且形式参数只有在调用时,才会分配空间,调用结束会释放空间,所以形式参数的生命周期只存在于开始调用和结束调用。

传参类型

数值型:将变量的值传递给形式参数,实际参数的值不变。

数组型:将数组的首地址传递给形式参数,且形式参数不用规定数组大小。如果用下标法改变数组元素,主函数中的数组的值也会发生改变,但是数组的地址不会发生改变。注意:二维数组传参时候,需要指定列的大小,因为二维数组是特殊的一维数组,不划分列数,操作系统不知道该数组中有几个一维数组。

指针型:将一个地址或者指针型变量的值传递给形式参数,实际参数的值不变,即实参形参同时指向一个地址,调用过程中主函数中该指针指向的地址不变。如果函数对形式参数操作时,形参指针发生变化,那么形参指向的地址便会和实参指向的地址不同。如果函数中有对形式参数进行取内容操作,则会修改该地址的里面的内容,主函数中该地址的内容也会发生变化。所以如果需要通过函数来修改主函数里面的变量的值的时候,可以在函数的参数列表里面多设置一个该类型变量的指针的形参,传参将变量的地址传入到形参,函数中对该地址取内容后的任何操作,都会影响主函数里面变量的值。这就是通过在a函数(main函数)里面调用b函数,b函数里面传参传a函数局部变量的地址,来改变a函数局部变量的值,比如main函数里面调用scanf,需要&。

数组型传参是一种特殊的指针型传参,实际上形参不存在数组概念,传数组相当于传地址。eg:

int *p=&arr[0]=arr;   *(p+1)=*&arr[1]=arr[1]。(p为形参,arr为实参)。

当传递的参数是数组名时,形参是指针,该指针便可以当做数组使用,还是可以用下标法访问数组元素。

当传递的参数是数组名向后偏移了的地址的时候,指针也可以当做数组使用,只是访问的时候,指针指向的位置就不是原数组名指向的地址了,而是偏移后的地址,还是可以用下标法访问数组元素。

注意如果想操作数组的部分元素:

可以在传参的时候传数组名偏移后的地址,数组长度传参时也可以相应变化,在函数里面仍然可以通过下标法或者指针偏移取内容访问。

也可以在传参的时候传数组名和数组长度且不做修改,通过改函数里面的内容,将形参偏移,再将形参的数组长度变化,也可以通用下标法访问或指针偏移取内容访问。

如果讲究泛用性,一般采取第一种方式。

注意普通变量与指针变量的区别

变量名是数值的别名,在使用的时候,他就是这个变量地址里面存储的数据即变量值,他的地址是&x而不是x,若要把这个地址存储起来用另外一个变量表示,需要使用指针变量

指针变量是某个地址的别名,对指针变量取内容修改里面的内容,这个操作并没有改变指针变量本身的值,即指针变量存储的地址还是原来的地址,但是这个地址里面的存储的内容已经变化

指针变量 对变量名操作 就是修改该指针指向的地址,但是修改前后两个地址的内容没有变化。

普通变量 对变量名操作 就是对这个地址里面数据操作,这个变量的值已经变化

注意外部变量和局部变量的区别

局部变量定义在函数体中,作用域是从定义开始到函数结束。

外部变量定义在函数体外面,作用域是从定义开始到所有代码结束。

全局变量是定义在头文件下的特殊外部变量,作用域是整个代码。

建议:因为函数是强调功能性的封装,所以函数体中主要写必要功能的业务逻辑,还要把需要的数据要return到主函数中,不建议直接在函数里面完成所有的业务,而不使用返回值。

若调用时需要函数获得多项结果 但return只能返回一项 可以使用全局变量或者直接指针改数据。

作业案例:函数封装实现冒泡排序和选择排序

#include<stdio.h>
#include<string.h>
void swap(int *p1, int *p2){
	int tem;
	tem=*p1;
	*p1=*p2;
	*p2=tem;
}
void pr(int a[],int len){
	for(int i=0;i<len;i++){
		printf("%d ",a[i]);
	}
}
int init(int a[],int len){
	int cnt=0;
	for(int i=0;i<len;i++){
		scanf("%d",&a[i]);
		if(a[i]==-1)break;
		cnt++;
	}
	return cnt;
}
void bob(int a[],int len){
	for(int i=0;i<len-1;i++){
		for(int j=0;j<len-i-1;j++){
			if(a[j]>a[j+1])swap(&a[j],&a[j+1]);
		}
	}
}
void choose(int a[],int len){
	for(int i=0;i<len-1;i++){
		for(int j=i+1;j<len;j++){
			if(a[i]>a[j])swap(&a[i],&a[j]);
		}
	}
}
int main(){
	printf("请输入数据以-1结束\n");
	int a[100];
	int cnt=init(a,100);
	int b[100];
	memcpy(b,a,sizeof(a));
	printf("排序前a: ");
	pr(a,cnt);
	printf("\n排序前b: ");
	pr(b,cnt);
	printf("\n对a选择排序: ");
	choose(a,cnt);
	pr(a,cnt);
	printf("\n对b冒泡排序: ");
	bob(b,cnt);
	pr(b,cnt);
	return 0;
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

做台无人机

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值