ссылка в аргументе функции - PullRequest
0 голосов
/ 16 апреля 2020
#include <iostream>
using namespace std;

struct Vector{
int sz; // no of elements
double * elem; // pointer to elements
};

void vector_init(Vector& v, int s){ // & indicates that we pass v by non-const reference
v.elem = new double[s]; // allocate an array of s doubles
v.sz = s;
}

double read_and_sum(int s){
Vector v;
vector_init(v,s);
for (int i=0; i!=s; i++)
cin>>v.elem[i]; // read into elements
double sum = 0;
for (int i=0; i!=s; i++)
sum += v.elem[i];

return sum;
}

int main(){
cout << read_and_sum(4) <<endl;
}

Почему мы передаем v по неконстантной ссылке в функции vector_init? Из того, что я понимаю, можно получить доступ к аргументу, не делая его копию, используя ссылки. Но почему мы не можем передать Vector v непосредственно в функцию (что означает void vector_init(Vector v, int s))? Я попытался, и компилятор выдал ошибку («Ошибка сегментации (ядро сброшено)»).

Ответы [ 5 ]

1 голос
/ 16 апреля 2020

Хорошо, ошибка сегментации возникает, когда вы хотите записать в ячейку памяти, доступную только для чтения. Когда вы передаете вектор по ссылке, как вы сказали, он не будет его копией, поэтому, если вы измените его, он изменит место, где вы объявили эту переменную. Но если вы передадите его как не ссылочный, он скопирует его, поэтому, когда вы выделите память для элементов, он выделит это для копии Vector, поэтому переменная v будет иметь нулевой указатель на свой элемент переменная. Когда вы попытаетесь прочитать элементы, они ничего не будут указывать, поэтому вы получаете ошибку сегментации.

1 голос
/ 16 апреля 2020

Когда вы передаете его как константную ссылку, вы не можете его изменить, когда вы просто делаете void vector_init(Vector v, int s), вы передаете его копию, поэтому вы создаете временную v. Когда вы делаете Vector& v, вы используя тот же v, что и в основной функции, поэтому все сделанные изменения будут сохранены.

1 голос
/ 16 апреля 2020

Но почему мы не можем передать вектор v непосредственно в функцию (что означает void vector_init (Vector v, int s))? Я попытался, и компилятор выдал ошибку ('Ошибка сегментации (ядро выгружено)').

Если вы передадите значение vector_init(Vector v, int s), то копия оригинала v от вызывающей стороны будет передана вызываемый (vector_init). Не будет никаких изменений в исходных v, ie, для него не будет выделено ни одной памяти, и, таким образом, он будет зависать при попытке доступа к нераспределенному элементу в for l oop v.elem[i];

0 голосов
/ 16 апреля 2020

Сегфоут происходит, потому что, когда вы передаете v в vector_init по значению, происходит то, что функция на самом деле получает копию v, а не v.

Это означает, что vector_init на самом деле не инициализирует v, а скорее инициализирует свою собственную копию v (которая, кстати, уничтожается при завершении функции, что приводит к утечке памяти).

Поскольку v неинициализирован, read_and_sum работает с ним, но поскольку он пытается получить доступ к элементам также неинициализированного v.elem (который к тому времени указывает на очень вероятную запрещенную часть памяти), программа падает, и вы получаете ошибку сегментации.

Решение, очевидно, передается по ссылке (или указателю, если вы хотите), тогда vector_init может фактически инициализировать v, который вы передаете ему, следовательно, все работает нормально.

В качестве примечания, я считаю, что должна быть реализована функция destroy_vector, которая вызывает delete[] v.elem, поэтому, когда вы закончите с v, вы можете освободить память. Или, на что указывает v.elem, что касается того, как сейчас, там определенно происходит утечка памяти.

0 голосов
/ 16 апреля 2020

Так что вы спрашиваете; почему, если мы сделаем копию и изменим копию, это не повлияет на оригинал? Я думаю, что ответ очевиден.

void vector_init(Vector v, int s){
    v.elem = new double[s]; 
    v.sz = s;
}

Vector v;
vector_init(v,s); // here v is copied and the copy is changed by vector_init

for (int i=0; i!=s; i++)
    cin>>v.elem[i]; // here we use the original v, which has not been changed

Если вы используете ссылку в vector_init, то копия не создается, и v в вызывающей функции изменяется.

...