Путаница с назначением в C

#c

Вопрос:

Я новичок в C, поэтому мне нужна помощь.

например, у меня есть этот объект структуры

 struct Frac {
   int num; 
   int dec
}
 

что я и делаю в c:

 struct Frac fract1 = {1, 2};
struct Frac temp; 
temp = fract1;
 

Указывает ли temp на копию фракт1 или она указывает на фактический фракт1?
Я попробовал это на компьютере, напечатав адрес, и он указывает на копию fract1.
Если это на Java, то это будет указывать на фактический фракт1. Поправьте меня, если я ошибаюсь. Могу я спросить, почему temp указывает на копию fract1 в C, а не на сам объект, спасибо!

Комментарии:

1. Потому что это присвоение значения, а не объекта. Если вы хотите назначить один и тот же объект, вам нужно указать указатель. Поскольку я не уверен, как это написать, я предпочитаю, чтобы вам ответили более компетентные люди 🙂

Ответ №1:

Ничто ни на что не указывает. Присвоение копирует значения. Присвоение всегда копирует значения. Иногда эти значения являются указателями, но если вы не видите указателя, значит, указателя нет. В C нет дихотомии Java между простыми типами с семантикой значений и всем остальным с семантикой ссылок.

Ответ №2:

« temp Указывает на копию fract1 или указывает на фактическое fract1 «?

Прежде всего, temp и fract1 не являются указателями. Существуют типы объектов структур.

Содержимое frac1 копируется temp , но temp является другим объектом.

Ответ №3:

Указывает ли temp на копию фракт1 или она указывает на фактический фракт1? Я попробовал это на компьютере, напечатав адрес, и он указывает на копию fract1.

Вы правы. Это указывало бы на копию fract1.

Если это на Java, то это будет указывать на фактический фракт1.

Вы правы, в Java было бы две ссылки на один и тот же объект.

Могу ли я спросить, почему temp указывает на копию fract1 в C, а не на сам фактический объект

C автоматически не выделяет объекты в куче, если вы не попросите его об этом. Вы могли бы воспроизвести что-то похожее на Java, используя указатели и распределение кучи. Но обратите внимание, что вы обязаны освобождать объекты явно, в отличие от Java.

 struct Fraction *frac1 = malloc(sizeof(struct Fraction));
frac1->num = 1;
frac1->dec = 2;

struct Fraction *temp; 
temp = frac1;

// Both frac1 and temp point to the same object
...

// Make sure you free the object eventually
free(frac1);
 

Ответ №4:

Оба frac1 и temp являются переменными. Эти переменные занимают два разных места в памяти.

То, что происходит в C, заключается в том, что temp = frac1 содержимое названной памяти копируется frac1 в названную память temp .

Если вы имеете дело с указателем, эти представления о пространствах в памяти и копировании содержимого по-прежнему применимы.

Например:

int *p; — в памяти есть пространство с именем p; однако содержимое этого пространства в памяти содержит адрес. Этот адрес, в свою очередь (вероятно), относится к другому пространству в памяти. Таким образом p = ... , будет обновлено содержимое p (которое является указателем), чтобы оно указывало на что-то новое. Тем *p = ... временем изменяется содержимое памяти, на которое указано содержимое p .

Ответ №5:

Да, оператор присваивания всегда создает копию. Это то, чего вы обычно ожидаете. Поведение Java на самом деле является отклоняющимся.

Например, в C или Java,

 int a = 3;
int b = a;
 

Ожидали бы вы b указать на «фактическое» a или b это будет копия a , содержащая то же значение 3 ?
Это именно то, что делает C, даже для структур, в отличие от Java. Для всех нетривиальных объектов Java неявно выделяет память в куче и создает ссылку (эквивалентную указателю). То, что вы называете «объектом» в Java, на самом деле является ссылкой на объект, и когда вы копируете его с помощью оператора присваивания, вы фактически копируете эту ссылку. Выделение составных объектов в стеке, которое возможно в C, невозможно на таком языке, как Java.

Если вы хотите создать ссылку, вы все равно можете сделать это, используя указатели в C. Вам придется «разыменовать» этот указатель, чтобы фактически получить объект, стоящий за ним.

Изменение исходного примера:

 struct Frac fract1 = {1, 2};
struct Frac *temp;
struct Frac *temp2; 
temp = amp;fract1; // Now temp points to the original fract1
temp2 = temp;   // Copying a reference: temp2 is a copy of temp but both point to the same fract1

temp->num = 3;  // This modifies fract1 indirectly