当前位置:   article > 正文

C语言中的引用,以及传递引用,数组传递_c语言引用传递

c语言引用传递

很多初学者不理解为什么C语言中用数组名作为参数能改变实参数组的值,现在来谈谈我的理解。

先来预热一下。

把实参数组传递给函数,则形参从数组哪里得到了其实地址,因此数组与实参数组共占了同一段内存单元,在函数调用期间,该变了形参数组的值,也就改变了实参数组的值。

现在问题来了,怎么理解共占同一段内存单元和值改变造成的影响呢?

举例:

int     i = 12;
int *p = & i;   //此时*p与i共占同一段内存单元,
*p = 23;  //此时改变了*p的值,i的值也就跟着改变了。此时 i = 23;
  • 1
  • 2
  • 3

上述例子中,可以理解为*p表示形参数组,i表示实参,它们共占同一段内存单元 ,所以改变形参能改变实参的值。

详解c++指针的指针和指针的引用

以下参考自:https://www.cnblogs.com/li-peng/p/4116349.html

展示一下使用指针的指针和指针的引用修改传递给方法的指针,以便更好的使用它。(这里说的指针的指针不是一个二维数组

为什么需要使用它们

当我们把一个指针做为参数传一个方法时,其实是把指针的复本传递给了方法,也可以说传递指针是指针的值传递

如果我们在方法内部修改指针会出现问题,在方法里做修改只是修改的指针的copy而不是指针本身,原来的指针还保留着原来

的值。我们用下边的代码说明一下问题:

int m_value = 1;

void func(int *p)
{
    p = &m_value;
}

int main(int argc, char *argv[])
{
    int n = 2;
    int *pn = &n;
    cout << *pn << endl;
    func(pn);
    cout << *pn <<endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

看一下输出结果

在这里插入图片描述

输出的是两个2

使用指针的指针

展示一下使用指针的指针做为参数

void func(int **p)
{
    *p = &m_value;

    // 也可以根据你的需求分配内存
    *p = new int;
    **p = 5;
}

int main(int argc, char *argv[])
{
    int n = 2;
    int *pn = &n;
    cout << *pn << endl;
    func(&pn);
    cout << *pn <<endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在这里插入图片描述

我们看一下 func(int **p)这个方法

p: 是一个指针的指针,在这里我们不会去对它做修改,否则会丢失这个指针指向的指针地址
*p: 是被指向的指针,是一个地址。如果我们修改它,修改的是被指向的指针的内容。换句话说,我们修改的是main()方法里 pn指针
**p: 两次解引用是指向main()方法里
pn的内容

指针的引用

再看一下指针的引用代码

int m_value = 1;

void func(int *&p)
{
    p = &m_value;

    // 也可以根据你的需求分配内存
    p = new int;
    *p = 5;
}

int main(int argc, char *argv[])
{
    int n = 2;
    int *pn = &n;
    cout << *pn << endl;
    func(pn);
    cout << *pn <<endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在这里插入图片描述

看一下func(int *&p)方法

p: 是指针的引用,main()方法里的 *pn
*p:是main()方法里的pn指向的内容。




你可以这样来理解指针与引用:
参考自:https://www.cnblogs.com/x_wukong/p/5712345.html

传指针和传指针引用的区别/指针和引用的区别(本质)

转自:http://blog.sina.com.cn/s/blog_673ef8130100imsp.html

指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)

而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址(int &a的形式)。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。

为了进一步加深大家对指针和引用的区别,下面我从编译的角度来阐述它们之间的区别:

程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。

最后,总结一下指针和引用的相同点和不同点:

★相同点:

●都是地址的概念;

指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

★不同点:

●指针是一个实体,而引用仅是个别名;

●引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;

●引用没有const,指针有const,const的指针不可变;(具体指没有int& const a这种形式,而const int& a是有 的, 前者指引用本身即别名不可以改变,这是当然的,所以不需要这种形式,后者指引用所指的值不可以改变)

●引用不能为空,指针可以为空;

●“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;

●指针和引用的自增(++)运算意义不一样;

●引用是类型安全的,而指针不是 (引用比指针多了类型检查

一、引用的概念

引用引入了对象的一个同义词。定义引用的表示方法与定义指针相似,只是用&代替了*。
例如: Point pt1(10,10);
Point &pt2=pt1; 定义了pt2为pt1的引用。通过这样的定义,pt1和pt2表示同一对象。
需要特别强调的是引用并不产生对象的副本,仅仅是对象的同义词。因此,当下面的语句执行后:
pt1.offset(2,2);
pt1和pt2都具有(12,12)的值。
引用必须在定义时马上被初始化,因为它必须是某个东西的同义词。你不能先定义一个引用后才
初始化它。例如下面语句是非法的:
Point &pt3;
pt3=pt1;
那么既然引用只是某个东西的同义词,它有什么用途呢?
下面讨论引用的两个主要用途:作为函数参数以及从函数中返回左值。

二、引用参数

1、传递可变参数
传统的c中,函数在调用时参数是通过值来传递的,这就是说函数的参数不具备返回值的能力。
所以在传统的c中,如果需要函数的参数具有返回值的能力,往往是通过指针来实现的。比如,实现
两整数变量值交换的c程序如下:
void swapint(int *a,int *b)
{
int temp;
temp=*a;
a=*b;
*b=temp;
}

使用引用机制后,以上程序的c++版本为:
void swapint(int &a,int &b)
{
int temp;
temp=a;
a=b;
b=temp;
}
调用该函数的c++方法为:swapint(x,y); c++自动把x,y的地址作为参数传递给swapint函数。

2、给函数传递大型对象
当大型对象被传递给函数时,使用引用参数可使参数传递效率得到提高,因为引用并不产生对象的
副本,也就是参数传递时,对象无须复制。下面的例子定义了一个有限整数集合的类:
const maxCard=100;
Class Set
{
int elems[maxCard]; // 集和中的元素,maxCard 表示集合中元素个数的最大值。
int card; // 集合中元素的个数。
public:
Set () {card=0;} //构造函数
friend Set operator * (Set ,Set ) ; //重载运算符号*,用于计算集合的交集 用对象作为传值参数
// friend Set operator * (Set & ,Set & ) 重载运算符号*,用于计算集合的交集 用对象的引用作为传值参数

}
先考虑集合交集的实现
Set operator ( Set Set1,Set Set2)
{
Set res;
for(int i=0;i<Set1.card;++i)
for(int j=0;j>Set2.card;++j)
if(Set1.elems[i]==Set2.elems[j])
{
res.elems[res.card++]=Set1.elems[i];
break;
}
return res;
}
由于重载运算符不能对指针单独操作,我们必须把运算数声明为 Set 类型而不是 Set * 。
每次使用
做交集运算时,整个集合都被复制,这样效率很低。我们可以用引用来避免这种情况。
Set operator *( Set &Set1,Set &Set2)
{ Set res;
for(int i=0;i<Set1.card;++i)
for(int j=0;j>Set2.card;++j)
if(Set1.elems[i]==Set2.elems[j])
{
res.elems[res.card++]=Set1.elems[i];
break;
}
return res;
}

三、引用返回值

如果一个函数返回了引用,那么该函数的调用也可以被赋值。这里有一函数,它拥有两个引用参数并返回一个双精度数的引用:
double &max(double &d1,double &d2)
{
return d1>d2?d1:d2;
}
由于max()函数返回一个对双精度数的引用,那么我们就可以用max() 来对其中较大的双精度数加1:
max(x,y)+=1.0;

注:int &a中的&本质就是“取地址”运算,在函数void swapint(int &a,int &b)中,&a要看成一个整体,看成是x的地址,故a就是x本身了

有区别,
无论你传值还是传指针,函数都会生成一个临时变量,
但传引用时,不会生成临时变量,

当你传值时,只可以引用值而不可以改变值,但传值引用时,可以改变值,
当你传指针时,只可以改变指针所指的内容,不可以改变指针本身,但传指针引用时,既可以改变指针所指的内容,又可以改变指针本身,

但传引用主要是它不生成临时变量,不进行返回值copy等,速度快。

数据结构的二叉排序树中有典型应用…

注:简单一点可以这么想,如果不用引用的话,被传递的参数本身是不能被修改的,
即使你传递的是指针,也只能修改指针指向的内容,不能修改指针本身。
如果要修改当前被传递的参数的话,要么再加一级指针,要么用引用。




换个话题,C语言如何将二维数组作为函数参数来传递呢,常说的C语言函数调用的三种方式:传值调用、引用调用和传地址调用是什么?

以下参考自:https://blog.csdn.net/kangxidagege/article/details/79475537
https://blog.csdn.net/weixin_41666244/article/details/80615661

你还可以参考这位大佬的博客:https://www.cnblogs.com/alantu2018/p/8465894.html

c语言中经常需要通过函数传递二维数组,有三种方法可以实现,如下:

方法一, 形参给出第二维的长度。

例如:

#include <stdio.h>
void func(int n, char  str[ ][5] )
{
 int i;
 for(i = 0; i < n; i++)
  printf("/nstr[%d] = %s/n", i, str[i]);
}

void main()
{
 char* p[3];
 char str[][5] = {"abc","def","ghi"};
 func(3, str);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

方法二,形参声明为指向数组的指针。

例如:

#include <stdio.h>
void func(int n, char  (*str)[5] )
{
 int i;
 for(i = 0; i < n; i++)
  printf("/nstr[%d] = %s/n", i, str[i]);
}

void main()
{
 char* p[3];
 char str[][5] = {"abc","def","ghi"};
 func(3, str);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

方法三,形参声明为指针的指针。

例如:

#include <stdio.h>
void func(int n, char **str)
{
 int i;
 for(i = 0; i < n; i++)
  printf("/nstr[%d] = %s/n", i, str[i]);
}
void main()
{
 char* p[3];
 char str[][5] = {"abc","def","ghi"};
 p[0] = &str[0][0];
 p[1] = str[1];
 p[2] = str[2];
    func(3, p);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

附加,第三种传参方式说明:在函数中使用传参过来的二维数组(指针)进行数组取值的时候不能使用(array[i][j])这种形式来取值。应该将二维数组看成一个一维数组,使用array[i * j + j]这种形式来进行取值。

个人理解:这是因为在传参的时候,我们将array[][]数组当成二级指针来进行传递,所以我认为他是将数组的属性退化成了二级指针的属性,因此这里并不能使用array[i][j]这种方式来进行数组取值。输出格式如下

int tag = 0;//tag标记,在方法中输出二维数组时所需要的标记
printf("使用传递过来的二维数组参数输出二维数组\n");
	for(i = 0; i < rows*columns; i++) {	
		printf("%d,", array[i]);
		if(tag == columns-1) {
			tag = 0;
			printf("\n");
		} else {
			tag++;
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11



插个队。。
1、引用的理解

C语言没有引用啊,C++才有.
引用能起到指针的部分作用,但是比指针安全.
一个引用可以看作是某个变量的一个"别名"。对引用进行操作就像对原变量进行操作一样。
主要用于函数的参数传递时使用。因为C语言没有类似VB的“传引用调用”这个功能,所以C++的引用填补了这个空白。从此即使需要改动参数,也直接传递一个变量过去即可。这在操作符重载中有更重要的意义。等你学到以后才会明白。
int a; //声明变量a
int& ra = a; //声明一个引用,名字是ra,ra引用了a
注意,ra声明的时候必须同时给出它到底引用了谁
int& ra; //只声明不指明是不对的。
还有,引用一旦声明,就不能再修改到其他变量上了,这与指针不同。
ra = b; //这是不行的,因为已经int &ra = a了

引用是引入了对象的一个同义词。定义引用的表示方法与定义指针相似,只是用&代替了*。

例如: Point pt1(10,10);
Point &pt2=pt1; 定义了pt2为pt1的引用。通过这样的定义,pt1和pt2表示同一对象。

需要特别强调的是引用并不产生对象的副本,仅仅是对象的同义词。因此,当下面的语句执行后:

pt1.offset(2,2);

pt1和pt2都具有(12,12)的值。

引用必须在定义时马上被初始化,因为它必须是某个东西的同义词。你不能先定义一个引用后才

初始化它。例如下面语句是非法的:

Point &pt3;

pt3=pt1;

2、引用的两个主要用途
作为函数参数以及从函数中返回左值。
(1)引用参数

a、传递可变参数
传统的c中,函数在调用时参数是通过值来传递的,这就是说函数的参数不具备返回值的能力。所以在传统的c中,如果需要函数的参数具有返回值的能力,往往是通过指针来实现的。比如,实现两整数变量值交换的c程序如下:

void swapint(int *a,int *b)

{

int temp;

temp=*a;

a=*b;

*b=temp;

}

使用引用机制后,以上程序的c++版本为:

void swapint(int &a,int &b)

{

int temp;

temp=a;

a=b;

b=temp;

}

调用该函数的c++方法为:swapint(x,y); c++自动把x,y的地址作为参数传递给swapint函数。

b、给函数传递大型对象

当大型对象被传递给函数时,使用引用参数可使参数传递效率得到提高,因为引用并不产生对象的副本,也就是参数传递时,对象无须复制。下面的例子定义了一个有限整数集合的类:

const maxCard=100;

Class Set

{

int elems[maxCard]; // 集和中的元素,maxCard 表示集合中元素个数的最大值。

int card; // 集合中元素的个数。

public:

Set () {card=0;} //构造函数

friend Set operator * (Set ,Set ) ; //重载运算符号*,用于计算集合的交集 用对象作为传值参数

// friend Set operator * (Set & ,Set & ) 重载运算符号*,用于计算集合的交集 用对象的引用作为传值参数

}

先考虑集合交集的实现

Set operator *( Set Set1,Set Set2)

{

Set res;

for(int i=0;i<Set1.card;++i)

for(int j=0;j>Set2.card;++j)

if(Set1.elems[i]==Set2.elems[j])

{

res.elems[res.card++]=Set1.elems[i];

break;

}

return res;

}

由于重载运算符不能对指针单独操作,我们必须把运算数声明为 Set 类型而不是 Set * 。每次使用*做交集运算时,整个集合都被复制,这样效率很低。我们可以用引用来避免这种情况。

Set operator *( Set &Set1,Set &Set2)

{ Set res;

for(int i=0;i<Set1.card;++i)

for(int j=0;j>Set2.card;++j)

if(Set1.elems[i]==Set2.elems[j])

{

res.elems[res.card++]=Set1.elems[i];

break;

}

return res;

}

2、引用返回值

如果一个函数返回了引用,那么该函数的调用也可以被赋值。这里有一函数,它拥有两个引用参数并返回一个双精度数的引用:

double &max(double &d1,double &d2)

{

return d1>d2?d1:d2;

}

由于max()函数返回一个对双精度数的引用,那么我们就可以用max() 来对其中较大的双精度数加1:

max(x,y)+=1.0;
在这里插入图片描述

扩展资料
使用c语言中引用的原因

程序按功能划分可分为数值运算、符号处理和I/O操作三类,符号处理程序占相当大的比例,符号处理程序无处不在,编译器、浏览器、Office套件等程序的主要功能都是符号处理。

在程序中通过对函数的调用来执行函数体,其过程与其它语言的子程序调用相似。

C语言中,函数调用的一般形式为:

函数名(实际参数表)

对无参函数调用时则无实际参数表。实际参数表中的参数可以是常数、变量或其它构造类型数据及表达式。各实参之间用逗号分隔。字符函数引用即对引用有关库函数或自定义函数函数。

参考资料:百度百科——字符函数引用




C语言函数调用的三种方式:传值调用、引用调用和传地址调用

我想,你只要看了C语言上关于传值函数调用的测试题,一切都会了然于胸:

  1. 考题一:程序代码如下:

    void Exchg1(int x, int y)
    {
    int tmp;
    tmp=x;
    x=y;
    y=tmp;
    printf(“x=%d,y=%d/n”,x,y)
    }
    void main()
    {
    int a=4,b=6;
    Exchg1 (a,b) ;
    printf(“a=%d,b=%d/n”,a,b)
    }

输出的结果:

x=____, y=____
a=____, b=____
  • 1
  • 2

问下划线的部分应是什么,请完成。

  1. 考题二:代码如下。

    Exchg2(int *px, int *py)
    {
    int tmp=*px;
    *px=*py;
    *py=tmp;
    print(“*px=%d,*py=%d/n”,*px,*py);
    }
    main()
    {
    int a=4;
    int b=6;
    Exchg2(&a,&b);
    Print(“a=%d,b=%d/n”, a, b);
    }

输出的结果为:

*px=____, *py=____
a=____, b=____
  • 1
  • 2

问下划线的部分应是什么,请完成。

  1. 考题三:

    Exchg2(int &x, int &y)
    {
    int tmp=x;
    x=y;
    y=tmp;
    print(“x=%d,y=%d/n”,x,y);
    }
    main()
    {
    int a=4;
    int b=6;
    Exchg2(a,b);
    Print(“a=%d,b=%d/n”, a, b);
    }

二. 函数参数传递方式之一:值传递

1. 值传递的一个错误认识
先看题一中Exchg1函数的定义:

void Exchg1(int x, int y)   //定义中的x,y变量被称为Exchg1函数的形式参数
{
int tmp;
tmp=x;
x=y;
y=tmp;
printf(“x=%d,y=%d/n”,x,y)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

问:你认为这个函数是在做什么呀?
答:好像是对参数x,y的值对调吧?
请往下看,我想利用这个函数来完成对a,b两个变量值的对调,程序如下:

void main()
{
int a=4,b=6;
Exchg1 (a,b)     //a,b变量为Exchg1函数的实际参数。
/ printf(“a=%d,b=%d/n”,a,b)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我问:Exchg1 ()里头的 printf(“x=%d,y=%d/n”,x,y)语句会输出什么啊?
我再问:Exchg1 ()后的 printf(“a=%d,b=%d/n”,a,b)语句输出的是什么?
程序输出的结果是:
x=6 , y=4
a=4 , b=6 //为什么不是a=6,b=4呢?

奇怪,明明我把a,b分别代入了x,y中,并在函数里完成了两个变量值的交换,为什么a,b变量值还是没有交换(仍然是a4,b6,而不是a6,b4)?如果你也会有这个疑问,那是因为你跟本就不知实参a,b与形参x,y的关系了。

2. 一个预备的常识
为了说明这个问题,我先给出一个代码:

int a=4;
int x;
x=a;
x=x+3;
  • 1
  • 2
  • 3
  • 4

看好了没,现在我问你:最终a值是多少,x值是多少?
(怎么搞的,给我这个小儿科的问题。还不简单,不就是a4 x7嘛!)
在这个代码中,你要明白一个东西:虽然a值赋给了x,但是a变量并不是x变量哦。我们对x任何的修改,都不会改变a变量。呵呵!虽然简单,并且一看就理所当然,不过可是一个很重要的认识喔。

3. 理解值传递的形式
看调用Exch1函数的代码:

main()
{
int a=4,b=6;
Exchg1(a,b) //这里调用了Exchg1函数        
printf(“a=%d,b=%d”,a,b)
}

Exchg1(a,b)时所完成的操作代码如下所示。
int x=a;//←
int y=b;//←注意这里,头两行是调用函数时的隐含操作
int tmp;
tmp=x;
x=y;
y=tmp;
请注意在调用执行Exchg1函数的操作中我人为地加上了头两句:

int x=a;
int y=b;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

这是调用函数时的两个隐含动作。它确实存在,现在我只不过把它显式地写了出来而已。问题一下就清晰起来啦。(看到这里,现在你认为函数里面交换操作的是a,b变量或者只是x,y变量呢?)
原来 ,其实函数在调用时是隐含地把实参a,b 的值分别赋值给了x,y,之后在你写的Exchg1函数体内再也没有对a,b进行任何的操作了。交换的只是x,y变量。并不是a,b。当然a,b的值没有改变啦!函数只是把a,b的值通过赋值传递给了x,y,函数里头操作的只是x,y的值并不是a,b的值。这就是所谓的参数的值传递了。
哈哈,终于明白了,正是因为它隐含了那两个的赋值操作,才让我们产生了前述的迷惑(以为a,b已经代替了x,y,对x,y的操作就是对a,b的操作了,这是一个错误的观点啊!)。

三. 函数参数传递方式之二:地址传递
继续——地址传递的问题!
看题二的代码:

Exchg2(int *px, int *py)
{
int tmp=*px;
*px=*py;
*py=tmp;
print(“*px=%d,*py=%d/n”,*px,*py);
}
main()
{
int a=4;
int b=6;
      Exchg2(&a,&b);
      Print(“a=%d,b=%d/n”, a, b);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

它的输出结果是:

*px=6,*py=4
a=6,b=4
  • 1
  • 2

看函数的接口部分:Exchg2(int *px,int *py),请注意:参数px,py都是指针。
再看调用处:Exchg2(&a, &b);
它将a的地址(&a)代入到px,b的地址(&b)代入到py。同上面的值传递一样,函数调用时作了两个隐含的操作:将&a,&b的值赋值给了px,py。
px=&a;
py=&b;
呵呵!我们发现,其实它与值传递并没有什么不同,只不过这里是将a,b的地址值传递给了px,py,而不是传递的a,b的内容,而(请好好地在比较比较啦)
整个Exchg2函数调用是如下执行的:

px=&a;   //
py=&b;   //请注意这两行,它是调用Exchg2的隐含动作。
int tmp=*px;
*px=*py;
*py=tmp;
print(“*px=%d,*py=%d/n”,*px,*py);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这样,有了头两行的隐含赋值操作。我们现在已经可以看出,指针px,py的值已经分别是a,b变量的地址值了。接下来,对*px,*py的操作当然也就是对a,b变量本身的操作了。所以函数里头的交换就是对a,b值的交换了,这就是所谓的地址传递(传递a,b的地址给了px,py),你现在明白了吗?

四. 函数参数传递方式之三:引用传递(好像这里属于C++的方式)
看题三的代码:

Exchg3(int &x, int &y) //注意定义处的形式参数的格式与值传递不同
{
   int tmp=x;
   x=y;
   y=tmp;
print(“x=%d,y=%d/n”,x,y);
}
main()
{
int a=4;
int b=6;
      Exchg3(a,b); //注意:这里调用方式与值传递一样
      Print(“a=%d,b=%d/n”, a, b);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

输出结果:

x=6, y=4
a=6, b=4   //这个输出结果与值传递不同。
  • 1
  • 2

看到没有,与值传递相比,代码格式上只有一处是不同的,即在定义处:
Exchg3(int &x, int &y)。
但是我们发现a与b的值发生了对调。这说明了Exchg3(a,b)里头修改的是a,b变量,而不只是修改x,y了。
我们先看Exchg3函数的定义处Exchg3(int &x,int &y)。参数x,y是int的变量,调用时我们可以像值传递(如: Exchg1(a,b); )一样调用函数(如: Exchg3(a,b); )。但是x,y前都有一个取地址符号&。有了这个,调用Exchg3时函数会将a,b 分别代替了x,y了,我们称x,y分别引用了a,b变量。这样函数里头操作的其实就是实参a,b本身了,也就是说函数里是可以直接修改到a,b的值了。

最后对值传递与引用传递作一个比较:

1. 在函数定义格式上有不同:
值传递在定义处是:Exchg1(int x, int y);
引用传递在这义处是:Exchg1(int &x, int &y);

2. 调用时有相同的格式:
值传递:Exchg1(a,b);
引用传递:Exchg3(a,b);

3. 功能上是不同的:
值传递的函数里操作的不是a,b变量本身,只是将a,b值赋给了x,y函数里操作的只是x,y变量而不是a,b,显示a,b的值不会被Exchg1函数所修改。

引用传递Exchg3(a,b)函数里是用a,b分别代替了x,y。函数里操作的是a,b

转自:http://blog.csdn.net/xiaosong2008/article/details/25430261




最后再讨论一个话题,指针是操作数据的,访问或者改变内存里的数据。那么,c语言如何在局部函数里,改变指针的指向呢?

1、如果函数参数直接传递的是指针类型,那么在函数内改变指针指向,并不能影响函数外的指针实例。只有传入指针的指针,才能改变指针的指向。
2、函数里的形参是一般变量,在函数里面改变变量的值,不会改变主函数里实参的值。指针就是地址变量,在函数里改变地址变量的值时,不会改变主函数实参地址变量的值。只有在函数里改变指针所指向的变量的值时 主函数实参指针所指向的变量的值才会改变。

改变指针的指向 传递指针的引用进去,或者指针的指针,上面其实已经讨论过了。。

#include <iostream>
using namespace std;
typedef struct Lstruct
{
int data;
struct Lstruct * next;
}LS;
void xy(LS *s1,LS *s2)
{
s1->data=91;
s2->data=92;
s1=s2;
}
void xy1(LS & s1,LS & s2)
{
s1.data=91;
s2.data=92;
s1 = s2;
}
int main()
{
LS *s1 , *s2 ;
s1=(LS*)malloc(sizeof(LS));
s2=(LS*)malloc(sizeof(LS));
s1->data= 1 ;
s2->data= 2 ;
printf("原来是:%d.%d\n",s1->data,s2->data);
xy(s1,s2);
printf("第一次之后%d.%d\n",s1->data,s2->data);
s1->data = 1 ;
s2->data = 2 ;
xy1(*s1,*s2);
printf("第二次之后%d.%d\n",s1->data,s2->data);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/cp456/article/detail/63168
推荐阅读
相关标签
  

闽ICP备14008679号