函数参数传递的两种方式为值传递和引用传递
1.传值方式传参
c语言是按值传递的,在函数中被传递的参数的本身(实参)是不能被修改的!参数x传进去的时候会被复制了一份copy,此后的修改都是在临时变量copy上,出了函数体copy被销毁,x还是原来的x,根本就没有被修改过,所以对变量x的修改无效。
如果想要修改传入的参数,有两种方法:
①传地址,传入x的地址,也就是将指向x的指针作为参数进行传递,【指针参数传递本质上是值传递,它所传递的是一个地址值】int f(int *x); f(&x); 指针传进去被复制了一份copy,x的指针的copy指向的内容也是x,对指针的copy的修改也就是修改了x的内容。 对于①来讲,在函数中如果传递的是指针,那么只能修改指针指向的内容,不能修改指针本身;如果想要修改指针本身,要么在再加一级指针,要么用引用&。
②引用传参 ,引用传参往往要比值传参高效,因为它是直接将x作为参数传入进去,而少了对x进行复制这部分的开销,既然传入进去的是x,那么对x的修改肯定也生效。
2.引用方式传参
引用可以被理解为变量的一个别名,但这依旧是原变量,如果在函数内对该变量进行修改的话,在外部该变量也会相应被修改。一定要先有原变量,才能有原变量的别名,故引用一定要赋初值,写成int &a=一个已存在的值的形式。
int a=11; int &b=a; b=9 在这时输出a的值发现a=9。
【比如:我的名字叫王**,别名叫王哥,我在函数里传入的参数为王哥,在函数内部我修改了王哥的体重,那么在调用函数时,王**的体重也被修改了。】
引用声明后使用方式和原变量一样(用指针的话要加一个取值的操作)
3.通过一段代码运行进一步理解传指针(包括二级指针)和传指针的引用
①函数传递的是指针变量的值——即该指针所指向的变量的地址,只能改变指针所指向变量的值,而不能改变指针本身的值。
#include
#include
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
void CreateList(LNode *header){
header=(LNode*)malloc(sizeof(LNode));
header->data=11;
header->next=NULL;
}
int main(){
LinkList head=NULL;
CreateList(head);
if(head!=NULL){
printf("%d\n",head->data);//什么都没有输出
}
free(head);
return 0;
}
②传递指针的地址,便可以修改指针本身的内容
#include
#include
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
//初始化链表,函数调用完毕后,L会指向一个空的链表,即会改变指针的值,所以要用**header
//**header不仅能修改指针所指向变量的值,也能够修改指针本身的内容
void CreateList(LNode **header){ //(LinkList *header)
(*header)=(LNode*)malloc(sizeof(LNode));//(LinkList)malloc(sizeof(LNode));
(*header)->data=11;
(*header)->next=NULL;
}
int main(){
LinkList head=NULL;
CreateList(&head);//传递指针本身的地址
if(head!=NULL){
printf("%d\n",head->data);//11
}
free(head);
return 0;
}
③(LinkList &header)这里的header其实是传入指针head的别名
#include
#include
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
//header其实是传入指针head的别名
void CreateList(LinkList &header){ //参数也可写成(LNode *&header)
header=(LNode*)malloc(sizeof(LNode));//(LinkList)malloc(sizeof(LNode));
header->data=11;
header->next=NULL;
}
int main(){
LinkList head=NULL;
CreateList(head);
if(head!=NULL){
printf("%d\n",head->data);//11
}
free(head);
return 0;
}
4.总结
其实指针类型和基本类型(比如int)来说,并没有本质上的差别。示例 :int x;LNode *L; (LNode为结构体)
在传值方式传参时,对于基本类型:函数参数为int x,调用函数传入x;对于指针:函数参数为LNode *,调用函数时传入L
在地址传递时,对于基本类型:函数参数为int *x,调用函数传入&x;对于指针:函数参数为LNode **,调用函数时传入&L。
在引用方式传参,对于基本类型:函数参数为int &x,调用函数传入x;对于指针:函数参数为LNode* &L(或LinkList &L ),调用函数时传入&L。
当你传值时,只可以引用值而不可以改变值,但传值引用时,可以改变值; 当你传指针时,只可以改变指针所指的内容,不可以改变指针本身,但传指针引用时,即可以改变指针所指的内容,又可以改变指针本身
→补充注意点:
①在定义函数时函数括号中的变量名成为形式参数,简称形参或虚拟参数;在主调函数中调用一个函数时,该函数括号中的参数名称为实际参数,简称实参,实参可以是常量、变量或表达式。
②C语言中实参和形参之间的额数据传递是单向的“值传递”,单向传递,只能由实参传给形参,反之不能。
③被调用函数的形参只有函数被调用时才会临时分配存储单元,一旦调用结束占用的内存便会被释放。
④”按值传递“中包括值传递和指针传递(指针传递参数本质上是值传递的方式,它所传递的是一个地址值),传递的都是实参的一个拷贝;虽然指针传递可以通过改变地址值来改变指针所指向的变量的值,但是不能改变指针本身的值。
⑤对于指针的引用类似于二级指针,但是也有一定的区别:无论你传值还是传指针,函数都会生成一个临时变量, 但传引用时,不会生成临时变量,不进行返回值copy等,速度快。
⑥关于引用传递和指针传递(本质是值【地址值】传递):
· 相同点:都是地址的概念
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
· 不同点:
指针是一个实体(也可以理解为替身);引用只是一个别名(本体的另一个名字)
引用只能在定义时被初始化一次,之后不可改变;指针可以修改;
引用不能为空;指针可以为空;
sizeof 引用,得到的是所指向变量的大小;sizeof 指针,得到的是指针的大小;
指针 ++,意义为 指针的地址自增;引用++则是 所指变量自增;
引用是类型安全的,引用过程会进行类型检查;指针不会进行安全检查;
作者:Mongo_girl
来源:CSDN
原文:https://blog.csdn.net/m0_37345402/article/details/86622609 ↩︎