【问题标题】:*& vs & in passing variable to function*& vs & 将变量传递给函数
【发布时间】:2020-01-19 15:20:45
【问题描述】:

我试图理解 C++ 中的引用和指针,我偶然发现了这个

#include<iostream> 
using namespace std; 

void swap(char * &str1, char * &str2) 
{ 
char *temp = str1; 
str1 = str2; 
str2 = temp; 
} 

int main() 
{ 
const char *str1 = "GEEKS"; 
const char *str2 = "FOR GEEKS"; 
swap(str1, str2); 
cout<<"str1 is "<<str1<<endl; 
cout<<"str2 is "<<str2<<endl; 
return 0; 
} 

什么是函数Swap中的*&amp;,和&amp;比较(按引用传递)我了解到,在性能上有什么不同,或者它们是如何工作的,我应该使用什么?

void swap(char &str1, char &str2) 
{ 
char temp = str1; 
str1 = str2; 
str2 = temp; 
} 

【问题讨论】:

  • 这能回答你的问题吗? Meaning of *& and **& in C++
  • 这取决于你需要什么。 char&amp; 是对 char 的引用,而 char*&amp; 是对 char 指针的引用。非常不同的东西。
  • @Yksisarvinen 我已经读过这篇文章,这对我来说有点高级,基本上我想了解为什么不直接使用&amp;。在什么情况下*&amp;优于&amp;
  • @Phineas 你的类型是char*,而不是char,所以这个类型的引用是char* &amp;,而不是char &amp;。没有“在什么情况下更好”。对于给定的类型,您使用给定的语法,仅此而已。

标签: c++ pointers reference swap


【解决方案1】:

它是对指针的引用。这样,函数不仅可以访问指针指向的内容,还可以修改传入的指针本身(它可以更改传入的指针指向的内容,因此它指向其他东西)。

【讨论】:

    【解决方案2】:

    任何类型都可以在声明中引用。

    例如

    #include <iostream>
    
    int main()
    {
        const char *s = "Hello";
    
        const char * &reference_to_s = s;
    
        std::cout << reference_to_s << '\n';
    }
    

    同样的程序也可以改写如下

    #include <iostream>
    
    using T = const char *;
    
    int main()
    {
        T s = "Hello";
    
        T & reference_to_s = s;
    
        std::cout << reference_to_s << '\n';
    }
    

    因此函数swap的参数

    void swap(char * &str1, char * &str2); 
    

    是对指向非常量字符串/数组的指针的引用。

    在第一次调用中,尝试交换通过引用传递的两个指针的值。

    但是这个调用

    swap(str1, str2); 
    

    不正确,因为参数的类型为 const char *,而声明的参数没有限定符 const

    使用上面显示的别名声明,您的程序可以写成这样

    #include <iostream>
    
    using T = const char *;
    
    void swap( T &s1, T &s2 )
    {
        T temp = s1;
        s1 = s2;
        s2 = temp;
    }
    
    int main()
    {
        T str1 = "GEEKS"; 
        T str2 = "FOR GEEKS"; 
    
        std::cout << "str1 is " << str1 << '\n'; 
        std::cout << "str2 is " << str2 << '\n';
        std::cout << '\n';
    
        swap( str1, str2 ); 
    
        std::cout << "str1 is " << str1 << '\n'; 
        std::cout << "str2 is " << str2 << '\n'; 
        std::cout << '\n';
    }
    

    它的输出是

    str1 is GEEKS
    str2 is FOR GEEKS
    
    str1 is FOR GEEKS
    str2 is GEEKS
    

    使引用更清晰的下一步是将别名声明和非模板函数swap 替换为模板函数swap

    #include <iostream>
    
    template <typename T>
    void swap( T &s1, T &s2 )
    {
        T temp = s1;
        s1 = s2;
        s2 = temp;
    }
    
    int main()
    {
        const char *str1 = "GEEKS"; 
        const char *str2 = "FOR GEEKS"; 
    
        std::cout << "str1 is " << str1 << '\n'; 
        std::cout << "str2 is " << str2 << '\n';
        std::cout << '\n';
    
        swap( str1, str2 ); 
    
        std::cout << "str1 is " << str1 << '\n'; 
        std::cout << "str2 is " << str2 << '\n'; 
        std::cout << '\n';
    
        char c1 = 'A';
        char c2 = 'Z';
    
        std::cout << "c1 is " << c1 << '\n'; 
        std::cout << "x2 is " << c2 << '\n'; 
        std::cout << '\n';
    
        swap( c1, c2 );
    
        std::cout << "c1 is " << c1 << '\n'; 
        std::cout << "x2 is " << c2 << '\n'; 
        std::cout << '\n';
    }
    

    程序输出是

    str1 is GEEKS
    str2 is FOR GEEKS
    
    str1 is FOR GEEKS
    str2 is GEEKS
    
    c1 is A
    x2 is Z
    
    c1 is Z
    x2 is A
    

    所以在swap 的第一次调用中,引用的类型是const char *。在swap的第二次调用中,引用的类型是char

    【讨论】:

      【解决方案3】:

      传递对指针的引用很像传递对任何其他类型变量的引用。所以,在函数中:

      void swap(char * &str1, char * &str2) {
      \\..
      

      两个参数的类型char*(指向字符的指针,或C 风格的字符串)。

      实际上,引用实际上是每个参数的地址,因此,当函数“交换”指针时,交换在调用代码中也是有效的。

      如果参数只是char*(而不是char* &amp;),那么传递的“指针”将是调用代码中它们的值的副本,以及对它们进行的任何操作在函数中对该调用代码没有影响。 (但请注意:函数可以仍然改变参数指向的数据——它只是不能改变/修改实际的指针,因为它需要!)

      但是,在您的“建议替代方案”中,您有:

      void swap(char &str1, char &str2) {
      //..
      

      您正在更改参数的实际类型!在这里,您传递引用(即地址)单个字符(char 变量),而不是字符串(起始地址)。

      【讨论】:

      • 我很好奇他们为什么输出相同的结果?
      • @Phineas 我很好奇为什么第二个版本还能编译!
      • @Phineas ... 当然,除非您的代码中有 both 函数定义,在这种情况下,您有所谓的 重载 - 并且编译器将使用与调用(最好)匹配的那个,在您的情况下,这将是“原始”那个(所以甚至不使用第二个函数)。
      • 不,非常好,只有 1 个函数,在 Visual Studio 上编译。 (cpp.sh/3pie4)
      • @Phineas 您的问题在于using namespace std; 行 - 它定义了自己的swap 函数,该函数正在用于代替您提供的函数。见这里:Why is “using namespace std;” considered bad practice?.
      【解决方案4】:

      如果您将整数的引用传递给交换函数,您将像这样将一个变量的数据复制到另一个变量:

      void swap(int &a, int &b) 
      { 
          int temp = a; 
          a = b; 
          b = temp;
      } 
      
      int main() 
      { 
          int a = 1; 
          int b = 5; 
          std::cout<<"a's adress before swap: "<< &a <<'\n'; 
          std::cout<<"b's adress before swap: "<< &b <<'\n'; 
          swap(a, b); 
          std::cout<<"a's adress after swap: "<< &a <<'\n'; 
          std::cout<<"b's adress after swap: "<< &b <<'\n'; 
          return 0; 
      } 
      

      输出是:

      a's adress before swap: 0x7ffeeccaba68
      b's adress before swap: 0x7ffeeccaba64
      a's adress after swap: 0x7ffeeccaba68
      b's adress after swap: 0x7ffeeccaba64
      

      所以它把a’s的数据复制到temp,然后把b’s的数据复制到a,最后把temp’s的数据复制到b。如果您传递像整数这样的小对象是可以的,但是如果您将像 Class 对象这样的大对象传递给交换函数,则可能会花费大量的时间和空间。

      另一方面,如果您将指针的引用传递给交换函数,您将只是随机指针指向的位置。例如:

      #include <iostream>
      void swap(int *&a, int *&b){
          int *temp = a;
          a = b;
          b = temp;
      }
      
      int main(){
          int x = 1;
          int y = 5;
          int *a = &x;
          int *b = &y;
          std::cout << "where a points before swap: " << a << '\n';
          std::cout << "where b points before swap: "<< b << '\n';
          swap(a, b);
          std::cout << "where a points after swap: " << a << '\n';
          std::cout << "where b points after swap: "<< b << '\n';
          return 0;
      }
      

      请注意,在输出中,ab 指向 swap 之后的机会:

      where a points before swap: 0x7ffee1738a68
      where b points before swap: 0x7ffee1738a64
      where a points after swap: 0x7ffee1738a64
      where b points after swap: 0x7ffee1738a68
      

      在交换函数中,首先temp指向a(指向x)指向,然后a指向b(指向y)指向,最后b指向@987654341指向@点(指向x)。因此,它只是交换了指针指向的位置,并没有复制任何重要数据。因此,如果您需要交换大数据对象,则对指针的引用在时间和空间上会更好。

      【讨论】:

        猜你喜欢
        • 2020-07-28
        • 1970-01-01
        • 1970-01-01
        • 2012-03-02
        • 2011-01-18
        • 2015-05-02
        • 2015-12-17
        • 2013-04-20
        相关资源
        最近更新 更多