首页 > 编程语言 >C/C++按值传递和按地址传递

C/C++按值传递和按地址传递

时间:2023-01-01 22:00:20浏览次数:37  
标签:函数 C++ changeNumber 传递 地址 main 按值


C/C++的按值传递和按地址传递有明显不同,下面对他们作个区别:

按值传递:在调用函数中将原函数的值拷贝一份过去被调用的函数,在被调用函数中对该值的修改不会影响原函数的值。

按地址传递:在调用函数的时候将原函数的值所在的地址拷贝一份过去,被调用函数对这个地址所作的修改会影响原来的值。

鉴于本人表达能力有限,这样说可能有点迷惑,下面直接上图:

一、按值传递

这里是一个十分简单的程序,其中包含了一个changeNumber()函数,意图是改变在main()函数中变量 a 的值,显而易见,这是一种按值传递,changeNumber()函数不可能完成任务:

C/C++按值传递和按地址传递_地址传递

可以看到,a并没有被改变。原因很简单,按值传递,当调用changeNumber()函数的时候,以 a 作为实际参数,在程序跳到changeNumber()函数的时候,会拷贝一份a的数据,也就是说,在内存空间中重新开辟了一块空间,它的作用就是用来存储a的值,并且这块空间的名称为 x,也就是changeNumber()中的这个x,注意,这个x所在的空间和a所在的空间是完全不同的两块内存(通过对他们分别输出地址可以得出),既然他们根本不属于同个地方,那么对x所作的任何修改都无法影响a。

二、按地址传递

如果这么写代码:

这里的代码就是按地址传递,首先在changeNumber()的声明中,使用了int*类型而不是int类型,其次在main()函数调用changeNumber()函数的时候使用的实参是&a而不是a,这就传递了一个地址给changeNumber()函数,这个changeNumber()就可以完成修改a的任务:

C/C++按值传递和按地址传递_开发语言_02

按照我的理解,按地址传递实际上是一种特殊的按值传递,原因如下:

1.main()函数调用changeNumber()的时候,将a的地址,也就是&a传递给changeNumber()函数,这实际上就是将a的地址拷贝一份过去给changeNumber()函数,在前面的例子中,main()拷贝并传递的是a,这里main()拷贝并传递的是&a,两者都可以理解为按值传递,只不过第二个例子中的“值”是a的地址而已

2.changeNumber()函数被调用之后,它根据传过来的地址值(请注意,这里说的是地址值,因为地址本身也是一个可见的数值),在内存中开辟一块新的空间,这块空间是用来存储这个地址值的,换句话说,这块空间上的内容就是a的地址,这似乎有点难以理解,但事实就是这样的,然后使用 * 运算符对x进行操作,*x操作的就是a的具体的值,而x作为一个指针,它存有a的地址(或者说它指向a的地址),那么对*x所做的任何操作都会影响a的值。

拓展:

    对于第二个例子,如果使用cout输出x,结果得到的将会是一个地址,并且这个地址与a的相同,这符合我前面所叙述的内容。

C/C++按值传递和按地址传递_地址传递_03

好,现在把注意点集中到这行代码上:

cout << "&x = " << &x << endl;

对这个&x进行输出,结果得到的又是另一个地址,事实上,这个地址就是调用changeNumber()函数时分配的内存空间,这块内存空间存储的便是x也是a的地址,当函数结束后,这块空间会被收回,上面的x的内容也会消失。

前面说了x存放的是a的地址,也就是说,x指向a的地址,如果有操作:

x = x + 5



把这行代码添加到changeNumber()函数的最前面,即:

void changeNumber(int* x)










{










x = x +
5;










*x = *x +
5;










cout <<
"x = " << x << endl;










}



这样会发生的事情是:这个函数又无法完成修改main中a的值了,原因就是,x存放的不再是a的地址,x的值已经发生了移动,换句话说,x指向了别的地址。

由于C和C++语法的相似性,经过C环境下写出的代码,同样符合这个逻辑


之所以写这个东西,是因为看到有博主写了关于Java按值传递和按引用传递的文章

刚好最近在学Java,文章所述Java的按值传递和按引用传递使我对C++按值传递和按地址传递的理解产生了疑问,一番实验之后终于弄清楚了。原文章写的非常不错,建议同样正在学习Java的同学可以看一看。


C/C++的按值传递和按地址传递有明显不同,下面对他们作个区别:

按值传递:在调用函数中将原函数的值拷贝一份过去被调用的函数,在被调用函数中对该值的修改不会影响原函数的值。

按地址传递:在调用函数的时候将原函数的值所在的地址拷贝一份过去,被调用函数对这个地址所作的修改会影响原来的值。

鉴于本人表达能力有限,这样说可能有点迷惑,下面直接上图:

一、按值传递

这里是一个十分简单的程序,其中包含了一个changeNumber()函数,意图是改变在main()函数中变量 a 的值,显而易见,这是一种按值传递,changeNumber()函数不可能完成任务:

C/C++按值传递和按地址传递_地址传递

可以看到,a并没有被改变。原因很简单,按值传递,当调用changeNumber()函数的时候,以 a 作为实际参数,在程序跳到changeNumber()函数的时候,会拷贝一份a的数据,也就是说,在内存空间中重新开辟了一块空间,它的作用就是用来存储a的值,并且这块空间的名称为 x,也就是changeNumber()中的这个x,注意,这个x所在的空间和a所在的空间是完全不同的两块内存(通过对他们分别输出地址可以得出),既然他们根本不属于同个地方,那么对x所作的任何修改都无法影响a。

二、按地址传递

如果这么写代码:

这里的代码就是按地址传递,首先在changeNumber()的声明中,使用了int*类型而不是int类型,其次在main()函数调用changeNumber()函数的时候使用的实参是&a而不是a,这就传递了一个地址给changeNumber()函数,这个changeNumber()就可以完成修改a的任务:

C/C++按值传递和按地址传递_开发语言_02

按照我的理解,按地址传递实际上是一种特殊的按值传递,原因如下:

1.main()函数调用changeNumber()的时候,将a的地址,也就是&a传递给changeNumber()函数,这实际上就是将a的地址拷贝一份过去给changeNumber()函数,在前面的例子中,main()拷贝并传递的是a,这里main()拷贝并传递的是&a,两者都可以理解为按值传递,只不过第二个例子中的“值”是a的地址而已

2.changeNumber()函数被调用之后,它根据传过来的地址值(请注意,这里说的是地址值,因为地址本身也是一个可见的数值),在内存中开辟一块新的空间,这块空间是用来存储这个地址值的,换句话说,这块空间上的内容就是a的地址,这似乎有点难以理解,但事实就是这样的,然后使用 * 运算符对x进行操作,*x操作的就是a的具体的值,而x作为一个指针,它存有a的地址(或者说它指向a的地址),那么对*x所做的任何操作都会影响a的值。

拓展:

    对于第二个例子,如果使用cout输出x,结果得到的将会是一个地址,并且这个地址与a的相同,这符合我前面所叙述的内容。

C/C++按值传递和按地址传递_地址传递_03

好,现在把注意点集中到这行代码上:

cout << "&x = " << &x << endl;

对这个&x进行输出,结果得到的又是另一个地址,事实上,这个地址就是调用changeNumber()函数时分配的内存空间,这块内存空间存储的便是x也是a的地址,当函数结束后,这块空间会被收回,上面的x的内容也会消失。

前面说了x存放的是a的地址,也就是说,x指向a的地址,如果有操作:

x = x + 5



把这行代码添加到changeNumber()函数的最前面,即:

void changeNumber(int* x)










{










x = x +
5;










*x = *x +
5;










cout <<
"x = " << x << endl;










}



这样会发生的事情是:这个函数又无法完成修改main中a的值了,原因就是,x存放的不再是a的地址,x的值已经发生了移动,换句话说,x指向了别的地址。

由于C和C++语法的相似性,经过C环境下写出的代码,同样符合这个逻辑


之所以写这个东西,是因为看到有博主写了关于Java按值传递和按引用传递的文章

刚好最近在学Java,文章所述Java的按值传递和按引用传递使我对C++按值传递和按地址传递的理解产生了疑问,一番实验之后终于弄清楚了。原文章写的非常不错,建议同样正在学习Java的同学可以看一看。







标签:函数,C++,changeNumber,传递,地址,main,按值
From: https://blog.51cto.com/u_14682436/5983391

相关文章

  • C++ Stack
    C++Stack基本操作头文件#include<stack>常用成员函数push(x)//x压入栈顶top()//返回栈顶元素的引用pop()//弹出栈顶元素empty()//栈为空返回true......
  • 《C++ —— 笔记》
      this指针在C++中成员变量和成员函数是分开存储的。每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码。那么问题是:这一块代码是......
  • C/C++备件管理系统
    C/C++备件管理系统综合项目(二)为某制造企业设计备件管理系统,主要包括如下功能:1)用户登录管理:管理员和普通用户权限及职能:管理员仅1名,为初始成员;普通用户可以是多名,普通用......
  • C/C++ 调用标准库函数实现 std::string to std::wstring 相互字符集变换(转)
    转自:https://blog.csdn.net/liulilittle/article/details/127697458#include<locale>#include<codecvt>#include<string>#include<vector>#if_MSC_VER>=1600......
  • C++ Primer第三章知识点(想起来啥记啥版)
    命名空间#include<iostream>//using声明,当我们使用名字cin时,从命名空间std中获取它usingstd::cin;intmain(){inti;cin>>i;//正确:cin和st......
  • 算法之Floyd-Warshall算法【c++】【图论】【最短路】
    我们作为刚学图论的小蒟蒻,先接触到的算法一定是图上最短路径算法。而最短路算法中最简单的当属Floyd-Warshall算法。下面是一些基本介绍:​该算法可以计算图上任意两点间......
  • C++ | 2-移动
    如何实现移动有分开的拷贝构造和移动构造函数。有swap成员函数,支持和另外一个对象快速交换成员。你的对象的名空间下,应当有一个全局的swap函数,调用成员函数swap来......
  • C++公司员工考勤管理系统[2023-01-01]
    C++公司员工考勤管理系统[2023-01-01]题目15“公司员工考勤管理系统设计”1、问题描述某公司需要存储雇员的编号、姓名、性别、所在部门,级别,并进行工资的计算。其中,雇......
  • 面试笔试刷题 C++ (持续更新)
    阅读C++语言代码输出()​​int​​​​main()​​​​{​​​​int​​​​arr[]={​​​​1​​......
  • OpenCV+yolov3实现目标检测(C++,Python)
    OpenCV+yolov3实现目标检测(C++,Python)  目标检测算法主要分为两类:一类是基于RegionProposal(候选区域)的算法,如R-CNN系算法(R-CNN,FastR-CNN,FasterR-CNN),它们是two-st......