#c #pointers #reference #pass-by-reference
#c #указатели #ссылка #передача по ссылке
Вопрос:
Я из Javascript и экспериментировал с c , где я хотел изменить элемент struct в массиве в вызывающей функции, как показано ниже.
#include<iostream>
#include<vector>
using namespace std;
typedef struct Node{
int value;
Node(int val){
this->value = val;
}
};
void changeValueByDot(Node* p, int idx){
Node n = *(p idx);
n.value = 54;
}
void changeValueByArrow(Node* p, int idx){
Node* n = (p idx);
n->value = 32;
};
int main(){
vector<Node> v = {
Node(1),
Node(2)
};
changeValueByDot(v.data(), 1);
cout<<"After changing by dot:"<<v[1].value<<endl;
changeValueByArrow(v.data(), 1);
cout<<"After changing by arrow:"<<v[1].value<<endl;
return 0;
}
Теперь мое замешательство заключается в том, почему оператор точки не может выполнить постоянное изменение, в то время как оператор стрелки мог.
Мое ожидание с точкой состояло в том, чтобы сначала добраться до места получения узла и изменить его значение. Я не уверен, копируется ли узел в этом местоположении и вносятся ли изменения в скопированный узел.
Я пробовал как с векторным, так и с массивом фиксированного размера, чтобы получить тот же результат.
Пожалуйста, помогите мне понять это. Заранее спасибо!
Ответ №1:
В этой строке:
Node n = *(p idx);
переменная n
является копией узла с правой стороны. Изменение n.value
не изменит узел, указанный в правой части.
Если вы хотите n
сослаться на разыменованный узел, используйте ссылку:
Node amp; n = *(p idx);
// ^
Теперь изменения в n
будут отражены в изменениях в *(p idx)
Обратите внимание, что это не проблема, когда вы делаете:
Node* n = (p idx);
потому что, хотя n
это все еще копия, это копия указателя, и изменение n->value
фактически изменит value
элемент того же объекта, на который указывает p idx
.
Ответ №2:
В Java нет переменных типа object . В Java есть переменные, которые ссылаются на объекты.
Это потому, что Java gc требует, чтобы объекты существовали в куче, и практически никогда не там, где вы их размещаете. В терминах C объектные переменные Java являются модными интеллектуальными указателями.
void changeValueByDot(Node* p, int idx){
Node n = *(p idx);
n.value = 54;
}
этот код создает локальный (в стеке) объект, если Node
вызывается тип n
.
Грубый эквивалент «псевдокода» Java либо:
void changeValueByDot(Node p, int idx){
Node n = (p idx).clone();
n.value = 54;
}
или
void changeValueByDot(int reference p, int idx){
int n = p;
n = 54;
}
в первом случае мы делаем неявное дублирование объекта в C явным. Во втором мы используем тип, который Java неявно не превращает в ссылку.
В обоих случаях, очевидно, изменяются только локальные данные. То же самое происходит и с версией C .
Отсутствие переменных экземпляра объекта в Java означает, что он обрабатывает примитивы и объекты асимметрично. Объекты C , с другой стороны, действуют как примитивы. Вы можете написать замену int
на C , и ее семантика будет идентична базовому int , но под капотом это bigint произвольной точности с переменным размером.