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

Asked
Viewd21579

6

Я давно не использую язык 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 прошло давно, поэтому сейчас я немного потерялся :(

  • Что является прототипом copySolution ??

    vinit dhatrak07 ноября 2009, 17:54

6 ответов

18

Это должно сработать:

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

РЕДАКТИРОВАТЬ : Кстати: он сохранит копию a в b.

  • @SteveJessop Поскольку размеры известны во время компиляции, static_assert() здесь - хороший вариант.

    Davislor04 декабря 2015, 23:39
  • Используйте memmove () - это гарантированно безопасно даже для перекрывающихся копий, в отличие от memcpy ().

    Jonathan Leffler07 ноября 2009, 19:58
  • @onebyone: По крайней мере, с условием вы можете попытаться корректно завершить работу, а не завершить приложение.

    Fred07 ноября 2009, 22:39
  • Или, что более вероятно, утверждение, поскольку обычно программа ничего не может сделать, чтобы компенсировать ошибку программиста…

    Steve Jessop07 ноября 2009, 19:33
  • Ну, за то короткое время, что я использовал C, я никогда не использовал & для массивов, чтобы получить их адреса, я всегда предполагал, что это просто незаконно и будет вести себя так, как если бы вы пытались получить указатель на адрес, что не имеет особого смысла.Спасибо, что разъяснили мне это :)

    rboy02 июня 2016, 04:49
  • @rboy указатель на массив (&a) и указатель на первый элемент (a, поскольку массивы распадаются на указатели на первый элемент, если lvalues) имеют одинаковое (указательное) значение.Однако они имеют разные типы, что здесь не имеет значения, поскольку memcpy обрабатывает все типы одинаково.Я должен был пойти на memcpy(b, a, sizeof(a)), я уже не знаю, почему я этого не сделал, но оба работают здесь :)

    Johannes Weiss01 июня 2016, 23:02
  • … и, конечно, вы должны считать, что вам повезло, если assert действительно что-то делает.Если ваш абонент просит вас сделать что-то неопределенное сейчас, есть все шансы, что это не в первый раз.Программа могла делать что угодно.Если вы не сделаете аборт, скорее всего, он будет не последним.Просто отложите процесс и медленно отступайте.

    Steve Jessop09 ноября 2009, 01:06
  • Вы можете добавить «if (sizeof (b)> = sizeof (a))», также отметьте.

    Fred07 ноября 2009, 18:10
  • Правильно ли использовать в этом контексте оператор указателя (&)?разве a и b уже не являются указателями на начало массива?Разве это не должно быть memcpy(b, a, sizeof(a)). Но поскольку этот ответ настолько старый и никто не указал на него, я, должно быть, что-то упускаю ... и я, вероятно, сейчас просто идиот

    rboy30 мая 2016, 10:26
  • @Jonathan: вопрос говорит о копировании «одного массива в другой».Таким образом, они не пересекаются[email protected]: «Изящно терпите неудачу или не терпите неудачу изящно.Нет попытки ».Некоторые программисты думают, что массив A помещается внутри массива B, но это не так.Ваша программа находится в состоянии, в котором вы (программист этой процедуры) уверены, что это результат ошибочного предположения программиста.В таких ужасных обстоятельствах утверждение терпит неудачу.Лучше остановиться прямо сейчас с диагностикой, чем просто продолжать выполнять сломанный код, пока в конце концов демоны не вылетят из вашего носа.

    Steve Jessop09 ноября 2009, 01:03
  • Фред, да, верно!В реальных программах это нужно делать :-)

    Johannes Weiss07 ноября 2009, 19:20
  • Прекрасно работает.Спасибо!

    Víctor07 ноября 2009, 17:55
3

Как сказал Йоханнес Вайс, memcpy() - хорошее решение.

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

 for (i=0; i<4; i++) {
    b[i] = a[i]; /* copy the whole struct a[i] to b[i] */
}
 
  • каждый компилятор, который я видел, вызывал memcpy при использовании ‘=’ при копировании структур.

    fdk134202 февраля 2012, 18:55
-3

Вероятно, самый простой способ

  b=a
 

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

  • Вы можете получить указатель, указывающий на тот же массив с помощью структур, но тогда это не копия.

    Fred07 ноября 2009, 18:14
  • b = a просто копирует значение указателя a в b, чего не хочет OP

    Ponting07 ноября 2009, 18:11
  • b=a; не работает, если, как здесь, a и b являются массивами.

    pmg07 ноября 2009, 18:10
  • @Adam Rosenfield: Массивы - это lvalue в C. Каждый объект, имеющий место в памяти, в C. называется lvalue . Массивы не являются исключением.Однако массивы в C являются неизменяемыми значениями l.Вот почему вы не можете назначать массив.

    AnT07 ноября 2009, 18:16
  • @No Name: Назовите имя! и это тоже неправильно.b нельзя присвоить, поскольку это массив.

    pmg07 ноября 2009, 18:14
  • b=a не работает - массивы не являются l-значениями в C, поэтому их нельзя назначать таким образом.

    Adam Rosenfield07 ноября 2009, 18:11
-1

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

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

 void copySolution(struct group* a, struct group* b, size_t size) {
    memcpy(a, b, size * sizeof(*a));
} 
 
  • @ Виктор: Твой звонок неправильный.Должно быть chooseNeighbour(candidateSolution, nGroups). Примечание: нет оператора &.

    AnT07 ноября 2009, 18:20
  • Я тоже пытаюсь это сделать, так как мне нужно передать массив другой функции, и он говорит следующее:

    simulated_annealing.c: В функции «main»: simulated_annealing.c: 39: предупреждение: передача аргумента 1 «chooseNeighbour» из несовместимого типа указателя

    Код:

    chooseNeighbour (& кандидатаSolution, nGroups) void chooseNeighbour (struct group * g [], int size) { printf («% i \ n», г [0] -> вес); }

    Víctor07 ноября 2009, 18:15
  • Неправда.Исходный код передает массивы как указатели типа struct group (*)[4], а не как указатели типа struct group *.При правильно объявленном copySolution размер массива встроен в тип указателя.Исходный код с вашим определением просто не будет компилироваться не только из-за отсутствия третьего параметра, но и из-за того, что тип аргумента не соответствует типу параметра.

    AnT07 ноября 2009, 18:06
0

Это похоже на плохо замаскированное домашнее задание ... В любом случае, учитывая заранее определенный формат вызова для 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);
}
 

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

  • Это своего рода домашнее задание, так как это моя последняя проектная карьера: П действительно, прошло какое-то время, и я никогда не мог ужиться друг с другом :)

    Víctor07 ноября 2009, 18:19
0

В моем случае предыдущие решения не работали должным образом!Например, Решение @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, потому что в части '// заполнение' я выполнял операции, требующие инициализированных данных.

  • Я думаю, что должен был.Я удалю неуместный комментарий.

    Davislor07 декабря 2015, 19:22