c memcpy struct по значению - PullRequest
       26

c memcpy struct по значению

3 голосов
/ 16 марта 2020

Я просто пытаюсь скопировать одну структуру в другую (копировать по значению, а не по ссылке). Вот полностью рабочий код

/* memcpy example */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE (80*sizeof(char))

typedef struct {
    char* name;
} person;

int main ()
{
  person p1;
  p1.name = (char*) malloc( SIZE );

  person p2;
  p2.name = (char*) malloc( SIZE );

  // set p1
  strcpy(p1.name, "John");

  // copy p1 > p2
  memcpy ( &p2, &p1, SIZE );

  printf ("p1.name: %s (%u)\n", p1.name, &p1.name );
  printf ("p2.name: %s (%u)\n", p2.name, &p2.name );

  // change p1 only
  printf("Changing p1.name\n");
  strcpy(p1.name, "ONLY p1.name Changed");

  // now, why did p2 change?
  printf ("p1.name: %s (%u)\n", p1.name, &p1.name );
  printf ("p2.name: %s (%u)\n", p2.name, &p2.name );

  free(p1.name);
  free(p2.name);

  return 0;
}

Вот скрипка http://cpp.sh/57skb

Этот код выводит

p1.name: John (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)
Changing p1.name
p1.name: ONLY p1.name Changed (0x791b3cdd6270)
p2.name: ONLY p1.name Changed (0x791b3cdd6280)

Ожидаемый результат будет

p1.name: John (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)
Changing p1.name
p1.name: ONLY p1.name Changed (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)

Вопрос: почему меняется p2 ?

Обратите внимание, что выполнение того же действия без структуры работает, как и ожидалось: http://cpp.sh/6qevd

Ответы [ 3 ]

3 голосов
/ 16 марта 2020

При создании этой копии оба элемента структуры name будут иметь одинаковое значение, поэтому они указывают на одну и ту же область памяти. Ваш код не показывает это, так как вы не печатаете значение указателя должным образом. Попробуйте, чтобы увидеть, что они действительно одинаковы

  printf ("p1.name: %s (%p)\n", p1.name, p1.name );
  printf ("p2.name: %s (%p)\n", p2.name, p2.name );

Вывод

p1.name: John (0x3ee8d60)
p2.name: John (0x3ee8d60)

p2 не меняется после strcpy(p1.name, "ONLY p1.name Changed");. Просто p2.name также указывает на эту новую строку.

2 голосов
/ 16 марта 2020

Если вы просто копируете структуру, вы перезаписываете указатель, а не то, на что он указывает. Что вы, вероятно, захотите сделать вместо memcpy:

size_t bytes = strlen(p1.name)+1;
p2.name = realloc(p2.name, bytes);
if (p2.name != NULL) {
    memcpy(p2.name, p1.name, bytes);
}

Здесь bytes - это количество символов в имени плюс строка nul-terminator, и вызов realloc изменяется размер p2.name, чтобы соответствовать этому. Теперь, гарантируя, что места достаточно, вы можете memcpy ввести первое имя во второе.

Использование reallo c здесь, вероятно, неэффективно, поскольку оно сохраняет исходное содержимое p2.name, которое мы надеваем не нужно В качестве альтернативы можно было бы сначала освободить старую строку, прежде чем выделять место для новой:

size_t bytes = strlen(p1.name)+1;
free(p2.name);
p2.name = malloc(bytes);
if (p2.name != NULL) {
    memcpy(p2.name, p1.name, bytes);
}

Помните, что оба mallo c и reallo c могут потерпеть неудачу и вернут NULL, если ваша программа не хватает памяти, поэтому рекомендуется всегда проверять это.

1 голос
/ 16 марта 2020

вам нужно скопировать выделенные области памяти, а не сами структуры

memcpy ( p2.name, p1.name, SIZE );
...