#c #pointers
#c #указатели
Вопрос:
Я думал, что где-то читал, что при использовании указателей и мы хотим скопировать содержимое одного в другое, есть два варианта:
- используя memcpy или
- просто назначая им = ?
Однако в приведенном ниже примере я просто протестировал его, выделив память для двух указателей, затем назначив второй, изменив первый … но затем запись моего второго указателя также меняется.. Что я делаю не так:/.
typedef struct {
int a;
int b;
int c;
} my_struct;
int main(int argc, char** argv) {
my_struct* first = malloc(sizeof(my_struct));
first->a = 100; first->b = 101; first->c = 1000;
my_struct* bb = malloc(sizeof(my_struct));
printf("first %d %d %dn", first->a, first->b, first->c);
bb = first;
printf("second %d %d %dn", bb->a, first->b, bb->c);
first->a = 55; first->b = 55; first->c = 89;
printf("second %d %d %dn", bb->a, first->b, bb->c);
}
Ответ №1:
В тот момент, когда вы это делаете bb = first;
, bb
и first
указываете на одно и то же местоположение памяти. first->a = 55; first->b = 55; first->c = 89;
изменит значения для a
, b
, и c
в этом расположении. Исходное значение first
, все еще сохраняется в памяти, но к нему больше нет доступа.
Я думаю, что вы можете захотеть сделать это *bb = *first;
.
Комментарии:
1. Хорошо, большое спасибо за объяснение, оно сделало его немного более понятным.. Но каково соглашение в C о копировании содержимого, является ли memcpy более распространенным или назначением, которое вы написали?
2. Я не думаю, что существует соглашение как таковое . Это действительно зависит от сценария, поскольку копирование данных, содержащих указатели, является довольно сложной темой, IMO.
3. Итак, у
*pointer = *other_pointer
меня всегда есть гарантия, что содержимое, стоящее заother_pointer
, скопировано в местоположениеpointer
?4. …Исходное значение bb все еще сохраняется в памяти..
Ответ №2:
Ваши знания memcpy
верны, но вы не можете назначить содержимое «местоположения, на которое указывают указатели«, просто назначив указатели, как вы сделали в своем заявлении, упомянутом выше.
Вы присваиваете один указатель другому в следующем операторе:
bb = first;
Теперь оба они указывают на одну и ту же ячейку памяти (считайте bb
, что это псевдоним first
).
Если вы хотите скопировать данные, вы копируете, используя «данные, на которые указывают указатели» *bb = *first
Комментарии:
1. Хорошо, значит, в этих случаях нет способа обойти использование memcpy?
2. @malajedala
*bb = *first;
Ответ №3:
Как уже указывалось, если у вас есть указатель first
, который указывает на некоторое местоположение в памяти, и вы выполняете присваивание bb
= first
, где bb
— совместимый тип указателя, тогда bb
указывает на тот же адрес, first
что и . Это не копирует содержимое памяти, на которую ссылается, first
в местоположение, на которое первоначально ссылается bb
. Он копирует значение указателя, которое является адресом, в bb
.
Если вы определяете массив A
, вы не можете выполнить присваивание B = A
для копирования содержимого A
в B
. Вы должны использовать strcpy()
или memcpy()
или какую-то такую функцию. Но структуры разные. Вы можете назначить содержимое одной структуры совместимой структуре.
В вашем примере bb
и first
являются указателями на структуры, и когда вы пишете bb = first
, теперь оба указателя ссылаются на один и тот же адрес в памяти, и у вас больше нет доступа к памяти, на которую первоначально ссылается bb
— так что теперь у вас утечка памяти! Но *bb
и *first
являются структурами, и когда вы пишете *bb = *first
, содержимое структуры *first
копируется в структуру *bb
. Итак, теперь у вас есть две разные структуры в разных местах памяти, каждая с копиями одних и тех же трех int
файлов.
Если ваш my_struct
тип содержит указатель на int
, то после назначения *bb = *first
каждый из них будет содержать копию указателя на одно и то же место в памяти, но данные, на которые ссылаются эти указатели, не будут скопированы. Итак, если структуры содержали указатель на массив, копировался бы только указатель, а не содержимое массива, которое было бы общим для двух структур.
Ответ №4:
вам нужно скопировать данные, на которые указывают такие указатели, как *p1 = *p2
. Но помните, это не сработает, если у вас снова есть указатели внутри копируемых структур.