Копирование массивов структур в C

Я давно не пользуюсь языком C, и это сводит меня с ума. У меня есть массив структур, и мне нужно создать функцию, которая будет копировать один массив в другой (мне нужна точная копия), но я не знаю, как определить вызов функции. Я думаю, мне нужно использовать указатели, но когда я пытаюсь, это дает мне ошибку.

struct group{
    int weight;
    int x_pos;
    int y_pos;
    int width;
    int height;
};

struct group a[4];
struct group b[4];

copySolution(&a, &b);

Последнее объявление выдает мне ошибку. Как я уже сказал, программирование на C прошло уже давно, поэтому сейчас я немного растерялся :(


person Víctor    schedule 07.11.2009    source источник
comment
каков прототип copySolution ??   -  person Vinit Dhatrak    schedule 07.11.2009


Ответы (6)


Это должно сделать это:

memcpy(&b, &a, sizeof(a));

EDIT: Кстати: копия a будет сохранена в b.

person Johannes Weiss    schedule 07.11.2009
comment
Работает как шарм. Благодарю вас! - person Víctor; 07.11.2009
comment
Вы можете добавить if(sizeof(b) ›= sizeof(a)) , также проверьте. - person Fred; 07.11.2009
comment
Фред, да, верно! В реальных программах это нужно делать :-) - person Johannes Weiss; 07.11.2009
comment
Или, что более вероятно, утверждение, поскольку обычно программа ничего не может сделать, чтобы компенсировать ошибку программиста... - person Steve Jessop; 07.11.2009
comment
Используйте memmove() — это гарантированно безопасно даже для перекрывающихся копий, в отличие от memcpy(). - person Jonathan Leffler; 07.11.2009
comment
@onebyone: По крайней мере, с условным выражением вы можете попытаться изящно завершить работу приложения, а не завершить его. - person Fred; 08.11.2009
comment
@Jonathan: вопрос говорит о копировании одного массива в другой. Так они не пересекаются. @Fred: ошибиться изящно или не ошибиться изящно. Нет попытки. Некоторые программисты думают, что массив A помещается внутри массива B, когда это не так. Ваша программа находится в состоянии, в котором вы (программист этой процедуры) уверены, что это результат неправильного предположения программиста. При таких ужасных обстоятельствах утверждение является изящным сбоем. Лучше остановиться прямо сейчас с диагностикой, чем просто продолжать выполнять сломанный код, пока в конце концов демоны не вылетят из вашего носа. - person Steve Jessop; 09.11.2009
comment
... и, конечно, вы должны считать себя счастливчиком, если утверждение действительно что-то делает. Если ваш абонент просит вас сделать что-то неопределенное сейчас, есть все шансы, что это происходит не в первый раз. Программа может делать что угодно. Если не абортировать, есть все шансы, что он не будет последним. Просто отложите процесс и медленно отойдите назад. - person Steve Jessop; 09.11.2009
comment
@SteveJessop Поскольку размеры известны во время компиляции, static_assert() здесь является хорошим вариантом. - person Davislor; 05.12.2015
comment
Правильно ли использовать оператор указателя (&) в этом контексте? разве a и b уже не указывают на начало массива? Разве это не должно быть memcpy(b, a, sizeof(a)). Но так как этот ответ такой старый, и никто не указал на него, я должен что-то упустить ... и, вероятно, сейчас я просто идиот - person rboy; 30.05.2016
comment
@rboy указатель на массив (&a) и указатель на первый элемент (a, поскольку массивы распадаются на указатели на первый элемент, если lvalues) имеют одно и то же значение (указатель). Однако они имеют разные типы, что здесь не имеет значения, поскольку memcpy обрабатывает все типы одинаково. Я должен был пойти на memcpy(b, a, sizeof(a)), больше не понимаю, почему я этого не сделал, но оба работают здесь :) - person Johannes Weiss; 02.06.2016
comment
Ну, в течение короткого периода, когда я использовал C, я никогда не использовал & для массивов, чтобы получить их адрес, я всегда предполагал, что это просто незаконно, и это будет вести себя так, как будто вы пытаетесь получить указатель на адрес, который не не имеет большого смысла. Спасибо, что разъяснили мне это :) - person rboy; 02.06.2016

Как говорит Йоханнес Вайс, memcpy() — хорошее решение.

Я просто хочу отметить, что вы можете копировать структуры как обычные типы:

for (i=0; i<4; i++) {
    b[i] = a[i]; /* copy the whole struct a[i] to b[i] */
}
person pmg    schedule 07.11.2009
comment
каждый компилятор, который я видел, вызывал memcpy при использовании '=' при копировании структур. - person fdk1342; 02.02.2012

Это похоже на плохо замаскированное домашнее задание... В любом случае, учитывая предопределенный формат вызова для copySolution в исходном посте, правильное определение copySolution будет выглядеть следующим образом.

void copySolution(struct group (*a)[4], struct group (*b)[4])
{
  /* whatever */
}

Теперь внутри copySolution вы можете копировать массивы любым удобным для вас способом. Либо используйте цикл

void copySolution(struct group (*a)[4], struct group (*b)[4])
{
  const struct group *pb, *pbe;
  struct group *pa;

  for (pa = *a, pb = *b, pbe = pb + sizeof *b / sizeof **b; 
       pb != pbe; 
       ++pa, ++pb)
    *pa = *pb;
}

или используйте memcpy как предложено выше

void copySolution(struct group (*a)[4], struct group (*b)[4])
{
  memcpy(b, a, sizeof *b);
}

Конечно, вы должны сначала решить, в каком направлении вы хотите, чтобы ваши массивы копировались. Вы не предоставили никакой информации, поэтому все просто сделали какой-то вывод.

person AnT    schedule 07.11.2009
comment
Это своего рода домашняя работа, так как это моя последняя проектная карьера: P действительно, это было давно, и я и C никогда не могли ладить друг с другом :) - person Víctor; 07.11.2009

В моем случае предыдущие решения не работали должным образом! Например, решение @Johannes Weiß не скопировало «достаточно» данных (оно скопировало около половины первого элемента).
Так что, если кому-то нужно решение, которое даст вам правильные результаты, вот оно:

int i, n = 50;
struct YourStruct *a, *b;

a = calloc(n, sizeof(*a));
b = malloc(n * sizeof(*b));
for (i = 0; i < n; ++i) { 
    // filling a
}

memcpy(b, a, n * sizeof(*a)); // <----- see memcpy here

if (a != NULL) free(a);
a = calloc(n*2, sizeof(*a));

memcpy(a, b, n * sizeof(*b)); // <------ see memcpy here again

Некоторые примечания: я использовал calloc для a, потому что в части «// заполнение a» я выполнял операции, требующие инициализированных данных.

person Snowman    schedule 04.12.2015
comment
Я думаю, что должен был. Я удалю неуместный комментарий. - person Davislor; 07.12.2015

Компилятор не имеет информации о размере массива после передачи их в качестве указателя в функцию. Поэтому вам часто нужен третий параметр: размер копируемых массивов.

Решение (без проверки ошибок) может быть:

void copySolution(struct group* a, struct group* b, size_t size) {
    memcpy(a, b, size * sizeof(*a));
} 
person dmeister    schedule 07.11.2009
comment
Не правда. Исходный код передает массивы как указатели типа struct group (*)[4], а не как указатели типа struct group *. При правильном объявлении copySolution размер массива встроен в тип указателя. С вашим определением исходный код просто не скомпилируется не только из-за отсутствия третьего параметра, но и из-за того, что тип аргумента не соответствует типу параметра. - person AnT; 07.11.2009
comment
Я также пытаюсь это сделать, так как мне нужно передать массив другой функции, и она говорит следующее: симуляция_аннелинга.с: В функции 'main': симуляция_аннелинга.с:39: предупреждение: передача аргумента 1 "выбрать соседа" из несовместимого тип указателя Код: ChooseNeighbour(&candidateSolution, nGroups) void ChooseNeighbour(struct group *g[], int size){ printf(%i\n, g[0]-›weight); } - person Víctor; 07.11.2009
comment
@Víctor Виктор: твой звонок неверен. Должно быть chooseNeighbour(candidateSolution, nGroups). Примечание: нет оператора &. - person AnT; 07.11.2009

Самый простой способ, наверное

 b=a

хотя решение с memcpy() тоже сработает.

person Thomas    schedule 07.11.2009
comment
b=a; не работает, когда, как здесь, a и b являются массивами. - person pmg; 07.11.2009
comment
b=a просто копирует значение указателя a в b, чего не хочет OP - person Ponting; 07.11.2009
comment
b=a не работает - массивы не являются lvalue в C, поэтому их нельзя присваивать таким образом. - person Adam Rosenfield; 07.11.2009
comment
Вы можете получить указатель, указывающий на тот же массив со структурами, но тогда это не копия. - person Fred; 07.11.2009
comment
@No Name: получить имя! и это тоже неправильно. b нельзя присвоить, так как это массив. - person pmg; 07.11.2009
comment
@Adam Rosenfield: Массивы - это lvalues в C. Каждый объект, который имеет место в памяти, называется lvalue в C. Массивы не являются исключением. Однако массивы в C являются неизменяемыми lvalue. Вот почему вы не можете присваивать массиву. - person AnT; 07.11.2009