#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