* & vs & при передаче переменной в функцию - PullRequest
1 голос
/ 19 января 2020

Я пытаюсь понять ссылку и указатель в 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 и сравнивает с & (передача по ссылке) Я узнал, есть ли различия в производительности или как они работают, что я должен использовать?

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

Ответы [ 4 ]

2 голосов
/ 19 января 2020

Любой тип может быть указан в объявлении.

Например,

#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.

2 голосов
/ 19 января 2020

Это ссылка на указатель. Таким образом, функция может получить доступ не только к тому, на что указывает указатель на , но также может изменить сам переданный указатель (он может изменить то, на что указывает указатель, переданный в, так что он указывает на что-то еще).

1 голос
/ 19 января 2020

Если вы передадите ссылку на целое число в функцию подкачки, вы скопируете данные одной переменной в другую, как показано ниже:

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, в функцию swap.

С другой стороны, если вы передадите ссылку на указатель на функцию подкачки, вы будете просто выбирать, куда указывают указатели. Например:

#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;
}

Обратите внимание, что в выводе, где a и b изменяются точки после 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 указывает, где temp указывает (указывает x). Таким образом, он просто поменял местами указатели и не скопировал значимых данных. Поэтому, если вам нужно поменять объекты больших данных, ссылка на указатель лучше подходит для времени и пространства.

1 голос
/ 19 января 2020

Передача ссылки на указатель очень похожа на передачу ссылки на любой другой тип переменной. Итак, в функции:

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

типы из двух аргументов char* (строки указателя или C в стиле).

На самом деле, ссылка на самом деле является адресом каждого аргумента, поэтому, когда функция «меняет местами» указатели, в вызывающем коде также действует свопинг.

Если бы аргументы были просто char* (а не char* &), то переданные «указатели» были бы копиями их значений в вызывающем коде и всем, что было сделано с ними или с ними в функции не будет иметь никакого эффекта в этом вызывающем коде. (Но обратите внимание: функция может по-прежнему изменять данные , на которые указывают аргументы - она ​​просто не может изменять / модифицировать фактические указатели, как это необходимо!)

Однако, в вашей «предложенной альтернативе», где у вас есть:

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

, вы меняете фактический тип аргументов! Здесь вы передаете ссылки на (т.е. адреса из ) одиночных символов (char переменных), а не (начальные адреса) символьных строк.

...