Почему значение оператора с точкой не изменяется в c ?

#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 произвольной точности с переменным размером.