Копирование массива в СИ
У меня есть заданный массив array_1, можно как то создать точно такой же массив array_2? или это придется делать в цикле с i?
Отслеживать
задан 1 апр 2020 в 10:51
13 3 3 бронзовых знака
Приведи пример того, что не получилось. Это «превентивный» вопрос. То есть из серии «я ничего не попробовал, скажите, можно ли так попробовать»? Ответ: можно. Пробуй. Если не получится, покажи проблемное место. Пока выглядит как попытка узнать решение для учебного задания. Я отмечаю как «Рекомендовать закрытие» вопроса. Дальше пусть модераторы решают.
Как создать копию массива значений и массива указателей без std?
А как сделать копию без массива значений(int *keys_) и массива указателей(Node **children_) без std не понятно. Изначальный объект надо удалить, поэтому сслыки можно скопировать, хотя не уверен.
- Вопрос задан более двух лет назад
- 500 просмотров
4 комментария
Простой 4 комментария

Не до конца понятно задание.
int *keys_ — это массив или просто указатель на одно число? Если массив то какова размерность?
Node **children_ — каков размер этого массива?
int count_ — возможно размер?
Ну а в целом:
— для keys выделяй память в размер массива и просто скопируй память (например memcpy)
— для children_ также выделяй память и копируй, на сколько я понял, сами объекты Node копировать не нужно, только их ссылки
calculator212 @calculator212
Что вообще значит без std или имеется ввиду copy? В c++ юзают copy в C memcpy, но можете написать свой велосипед по копированию.
Если int *keys_; указатель на массив, то передаете в функцию указатель на него и размер, создаете новый массив и выделяете ему память, а потом копируете значения в цикле, Node **children_ +/- тут не скажу сразу, т.к. непонятно что за структура данных под капотом, если список то копируете как список, если массив, то как массив.
Евгений Шатунов @MarkusD Куратор тега C++
поэтому сслыки можно скопировать
В представленном участке определения типа ссылок нет.
Изначальный объект надо удалить
А как сделать копию без массива значений и массива указателей без std не понятно.
Как это не понятно? В нули их и дело с концом.
Т.к. это полностью твой участок кода, только тебе полностью ясна вся его суть. Я на это смотрю со своей стороны и абсолютно не понимаю этот код. Равно как я не понимаю и твой вопрос, в котором ты высказываешь свое личное мнение как конечное и очевидное остальным людям.
Мне интересно: почему тебе не понятно, как сделать копию без массива значений и массива указателей без std? Зачем тебе в этом вопросе std?
Я не понимаю цели использовать struct вместе с private . Можешь ли ты объяснить свой ход мыслей, приведший к этой комбинации?
Я не понимаю цели существования голых указателей в полях этой структуры. Какой смысл ты вкладываешь в существование этих голых указателей? Особенно двойного указателя.
Без точного понимания, что стоит за указателями в классе (это динамические массивы или что-то другое) тут не дать правильного ответа.
Но в общем случае, если предположить, что keys и children это указатели на динамическую память, то если первоначальный объект удаляется, указатели можно просто скопировать (т.е. скопировать сами указатели, а не сделать копию памяти на которую указывает указатель), а на прежнем месте указатели обнулить, чтоб память выделенная по указателю не освободилась в процессе удаление первоначального объекта.
Это как с rvalue ссылками и move семантикой, но вам ничего не мешает делать то же самое руками.
Но можно воспользоваться средствами С++ — для этого реализуйте оператор перемещающего присваивавания и/или конструктор перемещения.
Решения вопроса 1
Wataru @wataru Куратор тега C++
Разработчик на С++, экс-олимпиадник.
Чтобы скопировать массив можно воспользоваться memcpy , или делать это циклом.
Массив указателей от массива значений не отличается ничем. Просто там значения — это указатели. Аккуратно не допустите ошибки при использовании sizeof — если ему передать сам массив (указатель), то это будет размер указателя, а не всего массива. Надо брать размер одного элемента и домножать на их количество.
Если изначальный объект можно удалить, то вам надо переопределить оператор перемещения, а не копирования. Внутри ваши массивы — это просто указатели и их можно перемещать как переменные:
keys_ = node.keys_; node.keys_ = nullptr;
Не забудьте изначальное место затереть нулевым указателем, чтобы нечайнно потом два раза не удалить.
Так делать при копировании нельзя — ибо вы создаете несколько указателей на один и тот же массив и вообще непонятно, кто потом должен это удалять. Только при перемещении.
Когда вы определили оператор перемещения (или конструктор перемещения), то далее оберните элемент источник в std::move() при присваивании или передаче в конструктор. Тогда вызовется действительно перемещающий метод.
Как копировать массив в С++?

vanyamba-electronics, он вывел два адреса ячеек памяти:


Мария, Массивы в C/C++ — это просто синтаксический сахар над указателями к памяти. Никаких дополнительных возможностей они не имеют. В переменной хранится только указатель на нулевой элемент массива. Размер массива при операциях с ним не контролируется, никаких служебных функций нет.
Либо используйте вариант vanyamba-electronics с memcpy, либо пишите свою функцию копирования void array_copy(int *dst, int *src, int size)
vanyamba-electronics @vanyamba-electronics
using namespace std; void outArray(int* array, int size) < for (int n = 0; n < size-1; ++n) cout . // cout
Muriam @Muriam Автор вопроса

Вроде копировалось, но пока не понятно как.
Ладно, придется с этим разбираться.
#include #include #include #include #include using namespace std; void outArray(int *arr, int size) < for (int n = 0; n < size-1; ++n) cout int main() < const int size = 10; int arr[size] = < 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 >; int arr2[size]; memcpy(arr2, arr, sizeof(int)*size); outArray(arr, size); outArray(arr2, size); getch(); return 0; >
Muriam @Muriam Автор вопроса
vanyamba-electronics @vanyamba-electronics
Мария, функция memcpy копирует данные из памяти в память.
Евгений Шатунов @MarkusD Куратор тега C++
Мария , с memcpy стоит быть осторожным. Функция дает ожидаемый результат только для тривиальных типов.
memcpy - это функция прямого копирования блоков памяти. Функция ничего не знает про инвариант объекта в памяти.
std::copy , наоборот, умеет понимать инварианты объектов и производить копирование не нарушая инвариант источника. Дополнительно, эта функция не даст скомпилировать код если тип объектов не является копируемым.
Функции std::begin и std::end являются частью C++11. Если тебе компилятор пишет что не может найти их объявление, значит ты просишь его собирать код используя стандарт до C++11.
Muriam @Muriam Автор вопроса
Я пытаюсь в этом коде сделать так, чтоб обе сортировки сортировали один и тот же массив. Пока не получается.
/*Отсортировать список: пузырьковой, методом прямого выбора, и шейкерной сортировками. Подчситать кол-во сравнений и пересылок*/ #include #include #include #include #include #define SIZE 10 using namespace std; void random_array(int arr[SIZE]); void bubble_sort(int arr[SIZE], int &comparison, int &transfer); void select_sort(int arr[SIZE], int &comparison2, int &transfer2); int main() < setlocale(LC_ALL, "rus"); srand(time(0)); // при каждом новом запуске программы генерирует другие случайные числа int array[SIZE]; int array2[SIZE]; memcpy(array2, array, sizeof(int)*SIZE); int compar = 0; int transf = 0; int compar2 = 0; int transf2 = 0; random_array(array); bubble_sort(array, compar, transf); for (int i = 0; i void random_array(int array[SIZE]) < cout > void bubble_sort(int array[SIZE], int &comparison, int &transfer) < cout = i; j--) < comparison++; // инкремент сравнений if (array[j] >array[j+1]) // если предыдущий элемент больше следующего < int temp = array[j]; // array[j] = array[j+1]; // меняю их местами array[j+1] = temp; // transfer++; // инкремент пересылок >> > > /* 1. Выбираем элемент с min значением и помещаем в a[0] 2. Снова выбираем элемент с min значением из оставшихся несортированных элементов и помещаем его в a[1] 3. И т.д., с каждым несортированным элементом, до конца. */ void select_sort(int array2[SIZE], int &comparison2, int &transfer2) < int min, temp; cout if (min == i) continue; temp = array2[i]; // array2[i] = array2[min]; // меняю их местами array2[min] = temp; // transfer2++; // инкремент пересылок > comparison2 = ((SIZE * SIZE) - SIZE) / 2; // сравнений >
Евгений Шатунов @MarkusD Куратор тега C++
Мария, а ты просто больно рано копированием занимаешься. 🙂
int array[SIZE]; int array2[SIZE]; memcpy(array2, array, sizeof(int)*SIZE);
Подскажи, а зачем копировать массив до его инициализации? Ведь инициализация у тебя происходит ниже, вот тут:
random_array(array);
Если тебе хочется отсортировать одинаковые данные разными алгоритмами, тебе стоит подойти к вопросу непосредственно.
Ты хочешь опробовать некие алгоритмы на одинаковых данных, значит тебе нужен своего рода эталон. Вот и заводишь память под эталонный массив.
Перед запуском алгоритма эталонный массив копируется во временный, а далее алгоритм запускается уже строго на временном массиве.
И, опять же, очень важно вкладывать смысл в имена. Этот момент у тебя все так же провисает.
Евгений Шатунов @MarkusD Куратор тега C++
Мария, Твой код мог бы выглядеть вот так (опуская прочие проблемы в коде).
Muriam @Muriam Автор вопроса
Евгений Шатунов, спасибо большое, ваш код расширил мой кругозор.
И за анализ моего кода, в комментарии выше, тоже спасибо!
int main() < int arr[size] = < 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 >; int arr2[size]; .
В переменной хранится только указатель на нулевой элемент массива
Rsa97, в данном случае это не так, в чём легко убедиться, посмотрев на содержимое памяти &arr .

jcmvbkbc, &arr - это память по указателю, записанному в переменной arr.
Сама переменная ничего, кроме указателя, не хранит.
Запись arr[0] и *arr вернут одно и то же значение, arr[1] ~ *(arr+1) и т.д.
Напишите в своём примере
arr2 = arr; arr2[0] = 0;
и увидите, что arr[0] тоже изменился, то есть вы получили не копию массива, а указатель на тот же участок памяти.
по указателю, записанному в переменной arr
Rsa97, я вот об этом говорю. Во время выполнения программы в переменную arr не записан никакой адрес. Переменная arr ассоциирована с памятью в которую записаны элементы массива, но сам адрес этой памяти в ней не хранится.
Напишите в своём примере
arr2 = arr;
В том-то и дело, что в моём примере так написать нельзя.

jcmvbkbc, Да, действительно не даст, переменная arr2 зафиксирована от изменений. Однако изменить по указателю всё равно можно, так же как и вывести значение указателя.
*arr = 0; *(arr+1) = -1; printf("%p | %p | %d | %d | %d\n", arr, &(arr[0]), arr[0], arr[1], arr[2]);
Как в C++ создать копию массива?
Создай новый массив у которого тип элементов и размер такой же как у копируемого массива. А потом в цикле делай копию каждого элемента и пихай ее в новый массив. Очевидно же.
Для пущей простоты и безопасности можно использовать стандартную библиотеку, тогда весь процесс выглядел бы так: auto new_array = std::copy(begin(old_array), end(old_array));
Вадим БулгаковУченик (238) 8 лет назад
это как-то не круто.
diabloМыслитель (7019) 8 лет назад
про цикл прикольно
а как же CopyMemory . ну да ладно
Duality Просветленный (29346) Чет тупанул, действительно. Давно ужо с голыми массивами не работал. В качестве оправдания: если массив не из POD, то memcpy может наломать дров, так шо цикл надежнее.
Похожие вопросы