精华内容
下载资源
问答
  • 最近Garena面试的过程中,面试官提了一个问题,C++中引用传递和指针传递的区别? 根据自己的经验,联想到了swap函数,只知道既可以用引用来实现,又可以用指针传递来实现,至于二者有何区别,自己还真没有考虑过。 ...
  • 总结:在实际使用中,值传递一方面会占用内存空间,内置类型还好(int等),如果是类(class)类型,赋值可能会是很大一笔...而对于指针传递,则在涉及数组的情况下使用较多,因为指针本身会给代码增加复杂性,难维护性
  • 详细介绍了C++中通过指针和通过引用传递参数的区别
  • 主要介绍了C语言中 值传递和指针传递实例详解的相关资料,需要的朋友可以参考下
  • 文章目录1 C++ 值传递、指针传递、引用传递详解值传递:指针传递:引用传递:2 数组作为函数的形参2.1 一维数组传递2.2 二维数组传递总结 1 C++ 值传递、指针传递、引用传递详解 值传递: 形参是实参的拷贝,改变...

    1 C++ 值传递、指针传递、引用传递详解

    值传递:

    形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。

    指针传递:

    形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作

    引用传递:

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

    下面的代码对此作出细致解释(从实参,形参在内存中存放地址的角度 说明了问题的本质,容易理解 )

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    #include<iostream>
    using namespace std;
    //值传递
    void change1(int n){
        cout<<"值传递--函数操作地址"<<&n<<endl;         //显示的是拷贝的地址而不是源地址
        n++;
    }
    
    //引用传递
    void change2(int & n){
        cout<<"引用传递--函数操作地址"<<&n<<endl;
        n++;
    }
    //指针传递
    void change3(int *n){
        cout<<"指针传递--函数操作地址 "<<n<<endl;
        *n=*n+1;
    }
    int main(){
        int n=10;
        cout<<"实参的地址"<<&n<<endl;
        change1(n);
        cout<<"after change1() n="<<n<<endl;
        change2(n);
        cout<<"after change2() n="<<n<<endl;
        change3(&n);
        cout<<"after change3() n="<<n<<endl;
        return true;
    }
    

    在这里插入图片描述
    引用的规则:

    (1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
    (2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
    (3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。

    参考链接:https://www.cnblogs.com/yanlingyin/archive/2011/12/07/2278961.html

    2 数组作为函数的形参

    2.1 一维数组传递

    然而,由于在C和C++中数组不能直接复制,传递时只传递一个首地址,在函数中需要使用的时候再跟据首地址和下标去寻找对应的值。
    至于为何数组不能直接复制,有一种解释的说法:

    • 是为了避免不必要的复制开销,因为数组的复制将导致连续的内存读与内存写,其时间开销取决于数组长度,有可能会变得非常大。为了避免复制数组的开销,才用指针代替数组。因此C语言使得当数组作为实参传递给函数的时候,将退化为同类型的指针,再传递指针的值。
      因此,在函数中修改数组值时,修改的是真的值。
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    #include<iostream>
    using namespace std;
    //值传递
      void printdz(int a[])
      {
      	cout<<"子函数里a0的地址为"<<&a[0]<<endl;
      	cout<<"子函数里a的地址为"<<a<<endl; //a本身即为指针 无需取地址符
      	cout<<"子函数里a1的首地址为"<<&a[1]<<endl;
      	a[1]=2;
      }
      int main()
      {
        int a[10]={1};
        cout<<"主函数里a的首地址为"<<&a[0]<<endl;
      	cout<<"开始的a1为 "<<a[1]<<endl;
      	printdz(a);
      	cout<<"函数里改过的a1 为"<<a[1]<<endl;
      	return 0;
      }
    
    

    在这里插入图片描述

    • 在这里我们可以看到子函数里的首地址a[0]与主函数的首地址是相同的。
    • a已经是一个指针了。由于是通过指针传递,因此无法得到数组的长度

    除了退化为指针传递,还可以直接通过指针传递和通过引用传递。

    指针传递:

    void printdzyy(int *aa) //传入指针 or void printdzyy(int aa[])
    {
    	cout<<"函数里参数的地址为"<<&aa[0]<<endl;
    }
    int main()
    {
      int a[10]={1};
    	int b[5]={1};
      cout<<"主函数里a[0]的首地址为"<<&a[0]<<endl;
    	printdzyy(a);
      printdzyy(b);//传入指针时 编译器无法知道数组长度 因此可以随便传
    	return 0;
    }
    

    在这里插入图片描述

    通过引用传递::

    void printdzyy(int (&aa)[10]) //引用就可以传递数组长度 因此需要写出数组大小
    {
    	cout<<"函数里aa的地址为"<<aa<<endl;
    }
    int main()
    {
      int a[10]={1};
    	int b[5]={1};
      cout<<"主函数里a[0]的首地址为"<<&a[0]<<endl;
    	printdzyy(a);
      //printdzyy(b);  incorrect  //如果传入b则编译不通过
    	return 0;
    }
    

    在这里插入图片描述

    • 从上述程序可以知道,传入指针时,编译器无法知道数组长度,因此可以传递进去不同长度的数组,也可以不写出数组长度。
    • 但是传递引用时,同时将数组长度也传递进去了,所以传入时必须为相应长度的数组。并且,在传递引用时,需要注意用()将&aa括起来,否则编译器报错。
    • 对于引用,也叫“别名”,某种意义上可作为无地址的指针,相比指针,引用不存在地址,必须被初始化,不存在NULL,不可改变对象,引用无法被多重引用。因此更加安全

    2.2 二维数组传递

    可以理解为数组的定义等同于指针的定义,即*a等同于a[],因此可以作如下变换

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    //1.5
    void func1(int iArray[][10])  //等同于 void func1(int (*iArray)[10])
    {
    }  //等同于void func1(int iArray[10][10])
    int main()
    {
        int array[10][10];
        func1(array);
    }
    
    

    注意(iAarray)可通过,去掉括号会编译错误*

    由于二维数组在栈内分配的内存是连续的,需要告诉编译器偏移的点,所以第二维度不可省,必须符合,而第一维度如一维数组一样随意。因此在上述代码1.5 中void func1(int iArray[9][10])不会报错,而void func1(int iArray[10][9])会报错。

    同一维数组,这边推荐使用引用,使用引用时需要保证两个维度都要ok:

    //1.6
    void func3(int (&pArray)[10][10])  
    {  }  
    int main()  
    {  
        int array[10][10];  
        func3(array);  
    }  
    

    也可以指针的指针来表示二维数组,动态分配内存的形式,此时,严格来说,并不是二维数组。

    #include <iostream>
    #include <stdio.h>
    void out(double **a,int m, int n)
    {
        int i, j;
        double b=0.0;
        for(i=0; i<m; i++)
        {for (j=0; j<n; j++)
            {
                a[i][j] = b;
                b += 1.2;
                printf("%5.1f",a[i][j]);
            }
            std::cout << std::endl; }   
    }
    int main(int argc, char * agrv)
    {
        int i, j, m=2, n=3;
        double **a;
        a = new double*[m];
        for (i=0; i<m; i++)
            a[i] = new double[n];
        out(a,m,n);
        return 1;
    }
    
    

    总结

    在传递数组参数时,首要推荐通过引用来传递参数,精准传入数组大小值,函数中参数定义为
    vtype (&name)[size][size],引用时传入名字即可。

    在通过指针传递时,需要另外传入参数来传递数组的大小。

    参考:
    https://blog.csdn.net/qq_30600259/article/details/101551220
    https://blog.csdn.net/desilting/article/details/7983530

    展开全文
  • C/C++语言中值传递、指针传递和引用传递

    万次阅读 多人点赞 2018-01-06 00:09:00
    在C语言中值传递、指针传递和引用传递这三种函数参数传递方式是比较基本的知识,用的比较普遍,但不仔细分析其实质的话,时间长容易记混了。网上的资料也较多但多数都不系统,本文力求用最白话的表达和简单的示例把...

    在C/C++语言中值传递、指针传递和引用传递(C++ only)这三种函数参数传递方式是比较基本的知识,用的比较普遍,但不仔细分析其实质的话,时间长容易记混了。网上的资料也较多但多数都不系统,本文力求用最白话的表达和简单的示例把这三种方式描述清楚。没时间看分析的直接看简述就可以了。

    简述

    值传递就是最普通的传递方式,比如函数定义为fun(int a),在调用的地方有int x=6, 使用fun(x)就可以了。这种方式在fun(int a)函数内部的对a的修改 不能 导致外部x的变化。
    指针传递其实也就是地址传递,函数定义为fun(int *a),形参为指针,这就要求调用的时候传递进去一个参数的地址,例如int x=6; fun(&x)。 这种方式在fun(int a)函数内部的对a的修改 导致外部x的变化。
    引用传递只有C++支持,相比前两种方式用的比较少,但也非常有用。引用传递函数定义为fun(int &a),这里&符号是引用而不是取地址的意思,调用方式和值传递类似,例如int x=6; fun(x)。 但是这种方式在fun(int a)函数内部的对a的修改 导致外部x的变化。

    表格是一种比较直接的表达方式,列个表格可以对这三种方式一目了然,假设调用fun函数之前都有定义int x=6,这三种方式异同如下表所示:

    传递方式函数定义函数调用函数内对a修改的影响
    值传递fun(int a)fun(x)外部x不变
    指针传递fun(int *a)fun(&x)外部x同步更改
    引用传递(C++)fun(int &a)fun(x)外部x同步更改

    分析

    下面三部分代码都尝试在swap函数内对输入参数进行数值交换,通过打印其数值和指针来分析。

    值传递

    函数内部使用这个参数,对这个参数的修改对函数外的原始数据不起作用。

    示例:

    #include <stdio.h>
    
    void swap(int a, int b){
        printf("swap enter\n");
        printf("a = %d, ptr = %p\n", a, &a);
        printf("b = %d, ptr = %p\n", a, &b);
    
        int tmp = b;
        b = a;
        a = tmp;
    
        printf("a = %d, ptr = %p\n", a, &a);
        printf("b = %d, ptr = %p\n", b, &b);
        printf("swap leave\n");
    }
    
    int main() {
        int x = 1;
        int y = 2;
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        swap(x, y);
    
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        return 0;
    }
    

    运行结果:

    x = 1, ptr = 000000000022FE4C
    y = 2, ptr = 000000000022FE48
    swap enter
    a = 1, ptr = 000000000022FE20
    b = 1, ptr = 000000000022FE28
    a = 2, ptr = 000000000022FE20
    b = 1, ptr = 000000000022FE28
    swap leave
    x = 1, ptr = 000000000022FE4C
    y = 2, ptr = 000000000022FE48
    

    结果表明:
    swap函数内部a b的数值进行交换,但是没有影响到x y的值。swap函数形参a b所指向的内存地址和外部x y的地址不一样。
    实质:
    swap为形式参数 a b创建了内存空间,main函数调用swap函数的时候,把x y的值copy给新创建的 a ba bx y分别在不同的内存位置中,因而对这个新创建的 a b 操作不会影响外部的 x y的值。

    带有返回值的函数,比如int fun(){int x=7; return x},外部调用方式为int a=fun();,这时是把x的数值copy了一份给外部a所在的内存空间,并释放了x所在的内存空间(系统自动分配的栈内存),在fun函数调用后即使知道x的内存地址也可能取不到相应的数据。
    返回值为指针的函数,比如char *fun(){...; return str;},函数中待返回的变量必须是使用malloc等函数手动申请空间(堆内存)的数据,且外部使用后要手动释放。因为系统自动申请的栈内存会在函数调用后自动释放。

    指针传递(地址传递)

    形参为指向实参地址的指针,当对形参的指向操作时,就相当于操作实参本身。

    示例:

    #include <stdio.h>
    
    void swap(int *a, int *b){
        printf("swap enter\n");
        printf("a = %d, ptr = %p\n", *a, a);
        printf("b = %d, ptr = %p\n", *a, b);
    
        int tmp = *b;
        *b = *a;
        *a = tmp;
    
        printf("a = %d, ptr = %p\n", *a, a);
        printf("b = %d, ptr = %p\n", *b, b);
        printf("swap leave\n");
    }
    
    int main() {
        int x = 1;
        int y = 2;
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        swap(&x, &y);
    
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        return 0;
    }
    

    运行结果:

    x = 1, ptr = 000000000022FE4C
    y = 2, ptr = 000000000022FE48
    swap enter
    a = 1, ptr = 000000000022FE4C
    b = 1, ptr = 000000000022FE48
    a = 2, ptr = 000000000022FE4C
    b = 1, ptr = 000000000022FE48
    swap leave
    x = 2, ptr = 000000000022FE4C
    y = 1, ptr = 000000000022FE48
    

    结果表明:
    swap函数内部a b的数值进行交换,外部的x y的值也发生了交换。swap函数形参a b所指向的内存地址和外部x y的地址分别都相同。
    实质是:
    swap函数形式参数其实是一个指针,可能把fun(int *a)写成fun(int* a)就比较容易理解了,形参a为地址指针。*a就是xa就是&x。函数内部要想修改其数值就要使用*a取数值,打印其地址直接打印a就可以了。
    函数内部对a b的操作实际上是操作x y所在的内存空间,所以函数内的修改会影响到外部x y的数值。

    引用传递

    引用传递的形参加一个&符号,这个形参相当于实参的一个别名,对形参的操作都相当于对实参的操作。
    注意形参带&符号的引用传递在C语言中是不可用的,只有C++中支持。
    C语言中函数参数总是通过值传递,可以通过显式传递指针值模拟引用传递。

    Function parameters are always passed by value. Pass-by-reference is simulated in C by explicitly passing pointer values. – https://en.wikipedia.org/wiki/C_(programming_language)

    示例:

    #include <stdio.h>
    
    void swap(int &a, int &b){
        printf("swap enter\n");
        printf("a = %d, ptr = %p\n", a, &a);
        printf("b = %d, ptr = %p\n", a, &b);
    
        int tmp = b;
        b = a;
        a = tmp;
    
        printf("a = %d, ptr = %p\n", a, &a);
        printf("b = %d, ptr = %p\n", b, &b);
        printf("swap leave\n");
    }
    
    int main() {
        int x = 1;
        int y = 2;
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        swap(x, y);
    
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        return 0;
    }
    

    运行结果:

    x = 1, ptr = 000000000022FE4C
    y = 2, ptr = 000000000022FE48
    swap enter
    a = 1, ptr = 000000000022FE4C
    b = 1, ptr = 000000000022FE48
    a = 2, ptr = 000000000022FE4C
    b = 1, ptr = 000000000022FE48
    swap leave
    x = 2, ptr = 000000000022FE4C
    y = 1, ptr = 000000000022FE48
    

    结果表明:
    函数内对形参的使用方式和值传递相同,产生的效果和指针传递相同。
    swap函数内部a b的数值进行交换,外部的x y的值也发生了交换。swap函数形参a b所指向的内存地址和外部x y的地址分别都相同。

    实质是:
    形式参数前加&符号,这个形参相当于实参的一个别名,对这个形参的操作等同于对实参的操作,有点类似快捷方式。a等同于x,比如fun(int &a)函数内对a的操作和值传递的函数fun(int a)中对形参的操作一样,但是修改形参同时也是修改实参。

    展开全文
  • 易语言指针传递对象源码,指针传递对象,模拟DLL传递对象,取文本,置文本,API取指针,拷贝内存
  • 易语言源码易语言指针传递对象源码.rar 易语言源码易语言指针传递对象源码.rar 易语言源码易语言指针传递对象源码.rar 易语言源码易语言指针传递对象源码.rar 易语言源码易语言指针传递对象源码.rar 易语言源码...
  • C语言中值传递、指针传递和引用传递

    千次阅读 多人点赞 2018-07-07 19:42:12
    在C语言中值传递、指针传递和引用传递这三种函数参数传递方式是比较基本的知识,用的比较普遍,但不仔细分析其实质的话,时间长容易记混了。网上的资料也较多但多数都不系统,本文力求用最白话的表达和简单的示例把...


    在C语言中值传递、指针传递和引用传递这三种函数参数传递方式是比较基本的知识,用的比较普遍,但不仔细分析其实质的话,时间长容易记混了。网上的资料也较多但多数都不系统,本文力求用最白话的表达和简单的示例把这三种方式描述清楚。没时间看分析的直接看简述就可以了。

    简述

    值传递就是最普通的传递方式,比如函数定义为fun(int a),在调用的地方有int x=6, 使用fun(x)就可以了。这种方式在fun(int a)函数内部的对a的修改 不能 导致外部x的变化。 
    - 指针传递其实也就是地址传递,函数定义为fun(int *a),形参为指针,这就要求调用的时候传递进去一个参数的地址,例如int x=6; fun(&x)。 这种方式在fun(int a)函数内部的对a的修改  导致外部x的变化。 
    - 引用传递相比前两种方式用的比较少,但也非常有用。引用传递函数定义为fun(int &a),这里&符号是引用而不是取地址的意思,调用方式和值传递类似,例如int x=6; fun(x)。 但是这种方式在fun(int a)函数内部的对a的修改  导致外部x的变化。

    表格是一种比较直接的表达方式,列个表格可以对这三种方式一目了然,假设调用fun函数之前都有定义int x=6,这三种方式异同如下表所示:

    传递方式函数定义函数调用函数内对a修改的影响
    值传递fun(int a)fun(x)外部x不变
    指针传递fun(int *a)fun(&x)外部x同步更改
    引用传递fun(int &a)fun(x)外部x同步更改

    分析

    下面三部分代码都尝试在swap函数内对输入参数进行数值交换,通过打印其数值和指针来分析。

    值传递

    函数内部使用这个参数,对这个参数的修改对函数外的原始数据不起作用。

    示例:

    #include <stdio.h>
    
    void swap(int a, int b){
        printf("swap enter\n");
        printf("a = %d, ptr = %p\n", a, &a);
        printf("b = %d, ptr = %p\n", a, &b);
    
        int tmp = b;
        b = a;
        a = tmp;
    
        printf("a = %d, ptr = %p\n", a, &a);
        printf("b = %d, ptr = %p\n", b, &b);
        printf("swap leave\n");
    }
    
    int main() {
        int x = 1;
        int y = 2;
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        swap(x, y);
    
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        return 0;
    }
    • 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

    运行结果:

    x = 1, ptr = 000000000022FE4C
    y = 2, ptr = 000000000022FE48
    swap enter
    a = 1, ptr = 000000000022FE20
    b = 1, ptr = 000000000022FE28
    a = 2, ptr = 000000000022FE20
    b = 1, ptr = 000000000022FE28
    swap leave
    x = 1, ptr = 000000000022FE4C
    y = 2, ptr = 000000000022FE48
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果表明: 
    swap函数内部a b的数值进行交换,但是没有影响到x y的值。swap函数形参a b所指向的内存地址和外部x y的地址不一样。 
    实质: 
    swap为形式参数 a b创建了内存空间,main函数调用swap函数的时候,把x y的值copy给新创建的 a b 。a bx y分别在不同的内存位置中,因而对这个新创建的 a b 操作不会影响外部的 x y的值。

    带有返回值的函数,比如int fun(){int x=7; return x},外部调用方式为int a=fun();,这时是把x的数值copy了一份给外部a所在的内存空间,并释放了x所在的内存空间(系统自动分配的栈内存),在fun函数调用后即使知道x的内存地址也可能取不到相应的数据。 
    返回值为指针的函数,比如char *fun(){...; return str;},函数中待返回的变量必须是使用malloc等函数手动申请空间(堆内存)的数据,且外部使用后要手动释放。因为系统自动申请的栈内存会在函数调用后自动释放。

    指针传递(地址传递)

    形参为指向实参地址的指针,当对形参的指向操作时,就相当于操作实参本身。

    示例:

    #include <stdio.h>
    
    void swap(int *a, int *b){
        printf("swap enter\n");
        printf("a = %d, ptr = %p\n", *a, a);
        printf("b = %d, ptr = %p\n", *a, b);
    
        int tmp = *b;
        *b = *a;
        *a = tmp;
    
        printf("a = %d, ptr = %p\n", *a, a);
        printf("b = %d, ptr = %p\n", *b, b);
        printf("swap leave\n");
    }
    
    int main() {
        int x = 1;
        int y = 2;
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        swap(&x, &y);
    
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        return 0;
    }
    • 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

    运行结果:

    x = 1, ptr = 000000000022FE4C
    y = 2, ptr = 000000000022FE48
    swap enter
    a = 1, ptr = 000000000022FE4C
    b = 1, ptr = 000000000022FE48
    a = 2, ptr = 000000000022FE4C
    b = 1, ptr = 000000000022FE48
    swap leave
    x = 2, ptr = 000000000022FE4C
    y = 1, ptr = 000000000022FE48
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果表明: 
    swap函数内部a b的数值进行交换,外部的x y的值也发生了交换。swap函数形参a b所指向的内存地址和外部x y的地址分别都相同。 
    实质是: 
    swap函数形式参数其实是一个指针,可能把fun(int *a)写成fun(int* a)就比较容易理解了,形参a为地址指针。*a就是xa就是&x。函数内部要想修改其数值就要使用*a取数值,打印其地址直接打印a就可以了。 
    函数内部对a b的操作实际上是操作x y所在的内存空间,所以函数内的修改会影响到外部x y的数值。

    引用传递

    引用传递的形参加一个&符号,这个形参相当于实参的一个别名,对形参的操作都相当于对实参的操作。

    示例:

    #include <stdio.h>
    
    void swap(int &a, int &b){
        printf("swap enter\n");
        printf("a = %d, ptr = %p\n", a, &a);
        printf("b = %d, ptr = %p\n", a, &b);
    
        int tmp = b;
        b = a;
        a = tmp;
    
        printf("a = %d, ptr = %p\n", a, &a);
        printf("b = %d, ptr = %p\n", b, &b);
        printf("swap leave\n");
    }
    
    int main() {
        int x = 1;
        int y = 2;
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        swap(x, y);
    
        printf("x = %d, ptr = %p\n", x, &x);
        printf("y = %d, ptr = %p\n", y, &y);
    
        return 0;
    }
    • 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

    运行结果:

    x = 1, ptr = 000000000022FE4C
    y = 2, ptr = 000000000022FE48
    swap enter
    a = 1, ptr = 000000000022FE4C
    b = 1, ptr = 000000000022FE48
    a = 2, ptr = 000000000022FE4C
    b = 1, ptr = 000000000022FE48
    swap leave
    x = 2, ptr = 000000000022FE4C
    y = 1, ptr = 000000000022FE48
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果表明: 
    函数内对形参的使用方式和值传递相同,产生的效果和指针传递相同。 
    swap函数内部a b的数值进行交换,外部的x y的值也发生了交换。swap函数形参a b所指向的内存地址和外部x y的地址分别都相同。

    实质是: 
    形式参数前加&符号,这个形参相当于实参的一个别名,对这个形参的操作等同于对实参的操作,有点类似快捷方式。a等同于x,比如fun(int &a)函数内对a的操作和值传递的函数fun(int a)中对形参的操作一样,但是修改形参同时也是修改实参。

    展开全文
  • C++ 值传递、指针传递、引用传递详解 最近写了几篇深层次讨论数组和指针的文章,其中提到了“C语言中,所有非数组的形式参数传递均以值传递形式” 数组和指针背后——内存角度 语义"陷阱"---数组和...

    C++ 值传递、指针传递、引用传递详解

    最近写了几篇深层次讨论数组和指针的文章,其中提到了“C语言中,所有非数组的形式参数传递均以值传递形式”

    数组和指针背后——内存角度

    语义"陷阱"---数组和指针

    而关于值传递,指针传递,引用传递这几个方面还会存在误区, 所有我觉的有必要在这里也说明一下~

    下文会通过例子详细说明哦

    值传递:

    形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,

    不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。

    指针传递:

    形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作

    引用传递:

    形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈

    中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过

    栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

     

    理论性的就不多说,

    下面的代码对此作出了细致解释(从实参,形参在内存中存放地址的角度 说明了问题的本质,容易理解  )

    复制代码
     1 #include<iostream>
    2 using namespace std;
    3 //值传递
    4 void change1(int n){
    5 cout<<"值传递--函数操作地址"<<&n<<endl; //显示的是拷贝的地址而不是源地址
    6 n++;
    7 }
    8
    9 //引用传递
    10 void change2(int & n){
    11 cout<<"引用传递--函数操作地址"<<&n<<endl;
    12 n++;
    13 }
    14 //指针传递
    15 void change3(int *n){
    16 cout<<"指针传递--函数操作地址 "<<n<<endl;
    17 *n=*n+1;
    18 }
    19 int main(){
    20 int n=10;
    21 cout<<"实参的地址"<<&n<<endl;
    22 change1(n);
    23 cout<<"after change1() n="<<n<<endl;
    24 change2(n);
    25 cout<<"after change2() n="<<n<<endl;
    26 change3(&n);
    27 cout<<"after change3() n="<<n<<endl;
    28 return true;
    29 }
    复制代码

    运行结果如下,(不同的机器可能会有所差别)

    可以看出,实参的地址为0x22ff44

    采用值传递的时候,函数操作的地址是0x22ff20并不是实参本身,所以对它进行操作并不能改变实参的值

    再看引用传递,操作地址就是实参地址 ,只是相当于实参的一个别名,对它的操作就是对实参的操作

    接下来是指针传递,也可发现操作地址是实参地址

    那么,引用传递和指针传递有什么区别吗?

      引用的规则: 
    (1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。 

    (2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。 
    (3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。 

    指针传递的实质:

    指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,

    即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的

    任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值(这里是在说实参指针本身的地址值不会变)如果理解不了大可跳过这段

    指针传递和引用传递一般适用于

    函数内部修改参数并且希望改动影响调用者。对比指针/引用传递可以将改变由形参“传给”实参(实际上就是直接在实参的内存上修改,

    不像值传递将实参的值拷贝到另外的内存地址中才修改)。

    另外一种用法是:当一个函数实际需要返回多个值,而只能显式返回一个值时,可以将另外需要返回的变量以指针/引用传递

    给函数,这样在函数内部修改并且返回后,调用者可以拿到被修改过后的变量,也相当于一个隐式的返回值传递吧。

     

     

    以下是我觉得关于指针和引用写得很不错的文章,大家可参照看一下,原文出处地址http://xinklabi.iteye.com/blog/653643 

    从概念上讲。指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。

    而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)。

    C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的:

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

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

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

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

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

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

    ★相同点:

    ●都是地址的概念;

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

    ★不同点:

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

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

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

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

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

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

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

    复制代码
    一、引用的概念

    引用引入了对象的一个同义词。定义引用的表示方法与定义指针相似,只是用&代替了*。
    例如: Point pt1(10,10);
    Point &pt2=pt1; 定义了pt2为pt1的引用。通过这样的定义,pt1和pt2表示同一对象。
    需要特别强调的是引用并不产生对象的副本,仅仅是对象的同义词。因此,当下面的语句执行后:
    pt1.offset(22);
    pt1和pt2都具有(1212)的值。
    引用必须在定义时马上被初始化,因为它必须是某个东西的同义词。你不能先定义一个引用后才
    初始化它。例如下面语句是非法的:
    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;
    复制代码
    展开全文
  • C++中引用传递与指针传递的区别

    万次阅读 多人点赞 2018-06-25 19:16:40
    精简版:指针:变量,独立,可变,可空,替身,无类型检查;引用:别名,依赖,不变,非空,本体,有类型检查;完整版:1. 概念 指针从本质上讲是一个变量,变量的值是另一个变量的地址,指针在逻辑上是独立的,它...
  • 易语言源码易语言指针传递窗口组件源码.rar 易语言源码易语言指针传递窗口组件源码.rar 易语言源码易语言指针传递窗口组件源码.rar 易语言源码易语言指针传递窗口组件源码.rar 易语言源码易语言指针传递窗口组件...
  • 使用指针变量作为函数参数|地址传递与指针传递实例总结地址传递值传递错误写法1错误写法2 地址传递 指针类型可以作为函数参数的类型,这时视为把变量的地址传入函数。如果在函数中对这个地址的元素进行改变,原先的...
  •  值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数  声明一个值类型变量时,编译器会在栈中分配一个空间,空间里存储的就是该变量的值  go语言...
  • C语言中指针传递问题

    千次阅读 2018-08-08 20:23:25
    C语言中指针传递问题 要求:用C语言通过调用函数实现两个值的交换 例如:输入5,9 —– 输出9,5 不能到达预期的结果的代码 #include&amp;amp;amp;amp;lt;stdio.h&amp;amp;amp;amp;gt; void main...
  • 引用传递与指针传递区别

    千次阅读 2017-11-13 20:18:00
    #include using namespace std; //值传递 void change1(int n){ cout n++; } //引用传递 void change2(int & n){ ...//指针传递 void change3(int *n){ cout *n=*n+1; } int main(){ int n=10;
  • 区别1:指针传递和引用传递是以不同的方式实现相同的效果,但是指针传递的本质还是值传递,只是传递的值是地址。 就拿 交换两个数的函数来举例: // 指针传递 void swap(int * val1, int * val2) { int temp...
  • 先说总结: 要想用指针传递通过函数改变主函数中字符串指针变量的值,必须使用char**的二级指针! 先举个例子(错误示范) #include <stdio.h> #include <stdlib.h> #include <...
  • 易语言指针传递窗口组件源码,指针传递窗口组件,模拟dll中的函数,API_CopyMemory
  • C语言:通过指针传递参数

    千次阅读 2019-04-30 17:20:54
    } 在参数列表的每个形参前面添加了一个星号(*),表示是一个指针,即对应该参数的实参应该是一个保存相同类型数据的地址。 第16~23行定义函数swap0,在该函数的代码中,也使用了指针运算符。使用指针运算符取得传入...
  • 零 结论 接收者类型 接收者值 指针 只能为指针 值 值与类型都可以 ...三 指针传递 type user struct { name string email string } func (u *user) notify() { // 这里的接收者是指针类型
  • 1.值传递 值传递的意思就是把实际参数的值传递给对应的形式参数,形式参数接收的是实际参数的一个副本,在方法内部操作的是形参而非实参,其值的改变并不影响实参。 2.引用传递 ...3.指针传递 C++
  • 数组作为函数参数传递会退化为指针,以下三种写法都一样 1.void func(int a[]); 2. vpid func(int * a); 3. void func(int a[4]); 那么用指针的引用的方式传递数组代表的是什么含义呢? 首先: int **p1; //p1是一个...
  • 关于指针传递和指针的引用传递

    千次阅读 2017-12-04 14:27:29
    指针传递的实质: 指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为...
  • 目录 一、互调的基本原理 ...三、指针传递 四、函数指针传递 五、结构体的传递 六、完整代码 最近在编写Warensoft3D游戏引擎,并预计明年年初发布测试版本,底层引擎使用DirectX和MONO来编写,上层...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 476,728
精华内容 190,691
关键字:

指针传递