一、 函数的值传递
函数的值传递是指参数为基本类型时,如整型、浮点型、字符型(特指单字符型)时,参数传递时是从实参拷贝一份值传给形参,形参的变化不会影响实参的值。
- 1. 基本类型做参数
基本类型:是指整型(short int long等)、浮点型(float、double)、字符型(char特指单字符型)
当参数为基本类型时,属于值传递,注意以下几点:
(1)函数的实参和形参分别占有存储单元
(2)函数的实参复制一份值传给形参
(3)实参不会随着形参的变化而变化
例如:
int fun(int x, int y) { x++; y++; return x+y; } void main() { int a,b; int result; scanf(“%d%d”,&a,&b); result=fun(a,b); //此处为函数调用 实参a,b printf(“result=%d ”,result); printf(“a=%d,b=%d ”,a,b); }
根据此例子我们可以分析实参是a,b;而形参是x,y。由于x、y的类型是基本类型,可知该函数fun是值传递函数。根据注意事项可知a,b与x,y是分别占有存储单元的。传递的时候是a,b的值复制一份传给x,y的;那么x++;y++;形参发生改变,不会影响实参a,b的值。假设从键盘输入的a,b的值分别是3,4,根据图示来理解整个过程。
(1)实参与形参分别占有存储单元,传递的时候是将值的拷贝传给形参
(2)当函数中语句x++; y++;执行后,形参x、y的值发生改变,而并不会影响实参a、b的值
如上例子运行输入3,4后,计算结果是9,但是a和b的值没有发生变化,还是3和4,这就是值传递的特点。
二、 函数的地址传递
函数的地址传递是指参数是:数组或指针类型时,传递的是地址,而不是值。注意地址传递有以下特点:
(1)函数的实参和形参共享存储单元
(2)函数是将实参的地址传给形参
(3)实参会随着形参的变化而变化,参数类型为:数组和指针
- 1. 数组做参数
例如,有一个数组保存着所有5名学生的考试成绩,利用数组做参数求这5名学生的平均值。
float getAverage(int a[],int len) //数组做参数时,需要两个参数数组名和数组长度 { int i,sum=0; for(i=0;i<len;i++) { sum+=a[i]; } return (float)sum/len; } void main() { int a[5]={97,85,88,95,92}; printf(“平均成绩是%.2f ”,getAverage(a,5)); //数组做参数调用时只写数组名不写[] }
数组做参数特点:
(1)数组做参数传递的是数组的首地址。
(2)数组名表示数组的首地址(因此调用时候只写数组名)
(3)数组做参数属于地址传递,传递的是数组的首地址,或数组第一个元素的地址。
- 2. 指针做参数
例子:使用指针交换两个整数
void swap(int *p,int *q) //指针做函数的参数 { int t; t=*p; *p=*q; *q=t; } void main() { int a,b; scanf(“%d%d”,&a,&b); swap(&a,&b); //函数调用传递的地址,所以需要加& printf(“a=%d b=%d ”,a,b); }
我们可以发现两个数确实实现了交换,说明实参会随着形参的变化而变化,揪其根本原因是因为实参和形参是共享存储单元的,调用过程只是将地址(即门牌号)传给形参。
起初变量a,b的值是3、4;将地址传给p、q两指针,则p、q指向a、b两变量如图所示:
执行t=*p; *p=*q; *q=t;三句后,内存中发生了变化:
三、 结构体数组做参数
综上所述,数组可以做为函数的参数,数组做参数属于地址传递,数组可以是基本类型的数组:整型数组、浮点型数组、字符数组,当然数组也可以复杂类型的数组--结构体数组。当参数为结构体数组时,仍是值传递。
例子:创建手机结构体:包括编号、名称、价格、产地。输入五款手机,计算5款手机的平均价格。
struct phone { int id; //编号 char name[20]; //名称 float price; //单价 char loc[50]; //产地 }; float fun(struct phone p[],int len)//计算手机的平均值 { int i; float avg,sum=0; for(i=0;i<len;i++) { sum+=p[i].price; //p是结构体数组名 进行累加 } return sum/len; } void main() { struct phone p[5]; int i; for(i=0;i<5;i++) { printf("请输入第%d款手机的信息: ",i+1); printf(" 请输入手机编号:"); scanf("%d",&p[i].id); printf(" 请输入手机名称:"); scanf("%s",p[i].name); printf(" 请输入手机单价:"); scanf("%f",&p[i].price); printf(" 请输入手机产地:"); scanf("%s",p[i].loc); } printf("五款手机的平均价格是%.2f元 ",fun(p,5));//结构体数组做参数只写数组名,并告知数组长度 }
运行结果如图所示:
可见数组做参数传递的是数组首地址,调用时只写数组的名字,不需要中括号等,同时需要知道数组的长度。结构体数组做参数和普通数组做参数本质是一样的,只是要针对性处理结构体数组的每一个元素而已。
四、 结构体指针做参数
根据指针做参数的特点,可知指针做参数是地址传递的一种。结构体指针只不过是一种指向结构体这种复杂自定义类型的指针而已,并没有什么不同。
例如:根据上一例子的手机结构体,实现结构体指针做参数,传递过去计算打折,手机单价6000以上打8折,300以上打9折,3000以下原价但送优惠券。
struct phone { int id; char name[20]; float price; char loc[50]; }; void fun(struct phone *p) { if(p->price>6000) { printf("手机价格超过6000,享受8折优惠,最终消费金额是%.2f元 ",p->price*0.8); } else if(p->price>3000) { printf("手机价格超过3000,享受9折优惠,最终消费金额是%.2f元 ",p->price*0.9); } else { printf("手机价格不足3000,暂无优惠,送您优惠券一张,最终消费金额是%.2f元 ",p->price); } } void main() { struct phone p; printf(" 请输入手机编号:"); scanf("%d",&p.id); printf(" 请输入手机名称:"); scanf("%s",p.name); printf(" 请输入手机单价:"); scanf("%f",&p.price); printf(" 请输入手机产地:"); scanf("%s",p.loc); fun(&p); //调用时传递的地址,因为参数是指针类型 }
这种参数传递属于地址传递,传递的是变量的地址。可以简单的理解为告诉了这个变量家的门牌号,这样去修改的时候,变量就真的会发生变化。效果图如下:
学生信息管理系统
/* Note:Your choice is C IDE */ #include "stdio.h" #include "string.h" #include "stdlib.h" int i,p; int a[10],s;//s为总和 int b; int mima(){ char mima[30],name[30]; printf("请输入账户: "); scanf("%s",&name); printf("请输入密码: "); scanf("%s",&mima); for (i=0;i<3;i++){ if(strcmp(mima,"123456")==0&&strcmp(name,"杨建")==0){ return 1; }else{ printf("输入错误,您还有%d次机会",3-i); } i++; } return 0; } void show_meun(){ printf(" ══成绩管理系统══ "); printf(" 1.输入成绩 "); printf(" 2.输出成绩 "); printf(" 3.总成绩 "); printf(" 4.平均成绩 "); printf(" 5.最高成绩 "); printf(" 6.最低成绩 "); printf(" 7.排序 "); printf(" 8.成材率 "); printf(" 0.退出 "); printf(" 9.刷新 "); } void input(){ for(i=0;i<10;i++){ printf("请输入第%d个人的成绩:",i+1); scanf("%d",&a[i]); } } void output(){ for(i=0;i<10;i++){ s=s+a[i]; printf("第%d个人分数为%d ",i+1,a[i]); } } void All_score(){ printf("总成绩为%d",s); } void Max_score(){ for(i=0;i<10;i++){ if(b<a[i]){ b=a[i]; } } printf("最大值为%d",b); } void Min_score(){ for(i=0;i<10;i++){ if(b<a[i]){ b=a[i]; } } printf("最大值为%d",b); } void Average_score(){ b=s/10; printf("平均分数是%d",b); } void manage_number(){ for(i=0;i<10;i++){ if(a[i+1]>a[i]){ b=a[i+1]; a[i+1]=a[i]; a[i]=b; } } for(i=0;i<10;i++){ s=s+a[i]; printf("第%d名分数为%d",i+1,a[i]); } } void Good(){ int x; for(i=0;i<10;i++){ if(a[i]>=90){ x++; } } printf("成材率为%.2f%% ",x*10); } void main() { if (mima()==1){ show_meun(); } for(i=1;i>0;i++){ printf("请输入功能编号:"); scanf("%d",&p); switch (p){ case 1:input();break; case 2: output();break; case 3: All_score();break; case 4: Average_score();break; case 5: Max_score();break; case 6: Min_score();break; case 7: manage_number();break; case 8: Good();break; case 0: exit(1);break; case 9: system("cls");break; default :printf("--------------------- "); }//switch }//for }//zuihou