Как вывести динамический массив c
Как вывести динамический массив c
В этой статье вы научитесь работать с массивами: объявлять, инициализировать и получать доступ к элементам
Содержание
Объявление массива в C/C++
В программировании часто встречается задача обработки множества экземпляров однотипных данных. Представьте себе ситуацию: мы провели опрос 100 человек и узнали их возраст. Чтобы сохранить собранные данные, вы можете создать целочисленный массив, содержащий 100 элементов:
В C++ массивы статичны: вы не сможете изменить размер или тип элементов после объявления.
Доступ к элементам массива
Инициализация массива при объявлении
Можно инициализировать массив при объявлении. Для этого надо указать в списке столько значений, сколько вмещает массив, либо одно значение 0, чтобы заполнить массив нулями:
Обход элементов массива в цикле
Узнать число элементов в массиве можно функцией std::size. Обойти можно, используя цикл по индексам либо range-based for:
Неопределённое поведение: выход за границы (out of bounds)
Выход за пределы массива является неопределённым поведением (англ. undefined behavior). Нет гарантий, как поведёт себя программа в этом случае. Высока вероятность, что вы испортите память других переменных, но эффект может различаться в разных режимах компиляции:
Передача массива как параметра функции
Массив в стиле языка C хранит только указатель на начало и не хранит свой размер, что и создаёт сложность в передаче в функцию. Размер массива известен во время компиляции, но не известен во время выполнения. Поэтому передать размер можно несколькими не очень очевидными путями:
Динамически изменяемый массив
Обычные массивы имеют неизменный размер. Вы можете ввести вспомогательную переменную, которая бы хранила число реально используемых ячеек массива. Но и в этом случае вы не сможете использовать элементов больше, чем задано при компиляции в виде размера массива.
Так мог бы выглядеть имитация динамического массива:
Класс std::vector
Стандартная библиотека C++ содержит шаблонный класс vector, который работает как динамический массив произвольного размера. Размер может расти до тех пор, пока у операционной системы есть область памяти подходящего размера (вплоть до нескольких гигабайт).
Класс является шаблонным, то есть при объявлении переменной потребуется параметризовать шаблон класса vector типом элемента:
Использование вектора похоже на использование массива:
Добавление элементов в конец массива
Для добавления существует два метода: push_back и emplace_back
Вы можете практически всегда использовать push_back. Метод pop_back можно использовать для удаления элемента:
В документации std::vector можно прочитать о других методах.
Перемещение элементов в памяти при изменении массива
Динамический массив использует для хранения элементов динамическую память (так же известную как “куча”, англ. heap). При добавлении большого числа элементов динамический массив несколько раз перераспределяет память, поскольку выделенной ранее линейной области памяти уже не хватает для хранения всех элементов. Обычно при нехватке памяти под очередной элемент vector запрашивает новую область памяти в 1,5-2 раза больше предыдущей, перемещает в неё уже существующие элементы и добавляет в конец новый, а затем освобождает старую область памяти.
Если не сообразили, как это происходит, взгляните на картинку:
Новая область находится уже другом месте, потому что менеджер динамической памяти не мог просто взять и расширить старую область (ведь сразу за ней находилась чужая память). Поэтому все итераторы, ссылки и указатели на элементы могут стать некорректными после любого изменения массива!
Метод erase для удаления элементов из середины
Метод erase класса vector получает итератор и уничтожает элемент, на который итератор указывает:
Последствия перемещения элементов: ошибка в простом цикле с erase
Использование итератора, ссылки или указателя на элемент после перераспределения памяти в массиве является неопределённым поведением: скорее всего произойдёт падение программы либо будет пропущено несколько элементов коллекции. Это показано в примере ниже:
Для решения этой проблемы метод erase возвращает новый, валидный итератор на элемент, следующий после удалённого. Если элемент был последним, erase вернёт итератор end. Учитывая это, мы можем исправить код, чтобы новое значение it либо получалось из erase, либо получалось путём инкремента:
Динамический массив структур C++
Динамический массив структур мы разберем на примере. Нам предстоит решить следующую задачу: пользователь вводит данные о спонсорах какого-то проекта. А именно – фамилию, имя и сумму пожертвования. После каждого ввода данных программа задает вопрос: продолжить ввод или нет.
Каждый раз, когда пользователь выбирает “продолжить” – надо выделить участок памяти еще под одну структуру. Таким образом динамический массив структур будет расти, пока пользователь не приостановит ввод. После завершения ввода, вывести таблицу с данными о спонсорах на экран.
Чтобы создать динамический массив структур, надо, как и для создания обычного динамического массива, объявить указатель. Только вместо встроенного типа указать дескриптор структуры – строка 20. Этот указатель пока ни на что не указывает. Можно было бы выделить память под массив структур сразу. Например:
Но мы организуем более гибкое выделение памяти под этот динамический массив структур – она будет выделяться по необходимости. Есть один спонсор – выделится память под одну структуру. Есть 3 спонсора – память выделится сначала под одну структуру, потом под вторую и далее под третью. Все будет зависеть от того – решит ли пользователь продолжить ввод.
В строках 21 – 22, объявлены переменные sponsorAmount – счетчик количества спонсоров и YesOrNot – выбор пользователя (продолжить или прервать ввод).
Надо помнить, что указатель OurSponsors уже ссылается на участок памяти с записанными данными. Поэтому не получится просто перевыделить память. Сначала необходимо позаботиться о сохранении данных. Посмотрите на блок else строки 48 – 59. В строке 50 создаем временный указатель. Под него выделяем память для amount + 1 структур (т.е. на одну структуру больше, чем приняла функция). Далее копируем данные из принятого объекта.
Последний объект массива структур tempObj останется незаполненным. Когда данные скопированы, освобождаем память Obj – строка 57 и записываем в этот указатель новый адрес. Теперь он будет указывать на память, в которой есть сохраненные данные и дополнительный выделенный участок памяти для заполнения новыми данными.
Когда пользователь решит больше не вводить данные – он нажимает ноль. После этого сработает функция showData() и на экране отобразится таблица с данными со всех структур динамического массива. В самом конце программы не забываем освободить память, которую занимает динамический массив структур.
Как реализовать динамический массив? C++
Есть программа сортировки одномерного массива из 25 элементов. Как сделать программу, которая могла бы сортировать одномерный массив любой размерности? Если вас не затруднит, объясните, как правильно выделять память под динамический массив, пользоваться указателями и оператором «&» для получения значения по указанному адресу, спасибо за помощь, вот код для массива из 25 элементов.
Спасибо всем кто помог. Вот код через указатели.
2 ответа 2
Раз тег с++ стоит, так будем делать по с++сному.
Вначале в самом верху добавим ещё один инклуд
Вместо int N = 25; пишем int N; cin >> N; Вместо int A[N]; пишем так vector A(N);
Память под «голый» массив неизвестного размера в С++ можно выделить так
Элементы такого массива будут изначально содержать «мусор». В вашем коде вам фактически не нужна изначальная инициализация элементов массива, но если вам так больше нравится, вы можете сделать
В этих вариантах содержимое массива будет изначально обнулено.
Когда такой массив становится ненужным, память следует освободить через
Остальной код при этом менять не нужно.
Однако, если уж вам нужен «голый» массив, то лучше поступить так
С таким указателем/массивом можно работать обычным образом (т.е. A[i] ), но память будет освобождена автоматически.
Динамические массивы в C
Если вы используете относительно современный ЯП вроде JS, то массивы в С могут ввести вас в ступор.
Вступление
Массив в JavaScript:
Приведенный выше пример показывает, как бы мы создали массив в JS. Хорошо видно, что возможно добавить столько строк, сколько нам нужно.
Первое выражение numbers[3] говорит компилятору, что массив сохранит в памяти 3 числа. Далее сохраним 1,2 и 3 под соответствующими индексами и выведем на дисплей.
Пока все прекрасно, но но нельзя добавить ещё элементы:
Таким образом, мы получаем исключение за пределами границ памяти. Места в нашем массиве недостаточно, чтобы вместить ещё элементы.
Что же, если мы нуждаемся в динамическом массиве, в который можно добавить n элементов?
На С мы можем создать собственную имплементацию массива с динамически растущим размером.
Для этого используем блоки памяти.
malloc, realloc и указатели (pointers)
В С каждый тип данных имеет свой размер хранилища:
В моей системе это 4 байта для целых чисел (integers). Просто имея эти данные можно создавать динамические массивы любого размера.
Размер типа данных можно получить при помощи функций sizeof(int), sizeof(double) или для тех типов данных, которые вам требуются.
Используя функции malloc и realloc мы можем создавать динамические блоки памяти.
Допустим, мы хотим начать с возможности хранить 3 целых числа (integers),это можно сделать, выделив блок памяти из 12 байт:
Теперь есть возможность добавлять элементы в блок памяти динамически.
Собрав все это вместе, получим следующую программу:
Статья Как создать динамический массив в c#
Создание динамического массива в языке c#
В языке c# под словом массив подразумевается объект с заранее заданным неизменяемым размером. То есть, к примеру, если Вы создали массив, который содержит пять элементов, то увеличить данный размер динамически Вы уже не сможете, так как он является фиксированным. В этом можно легко убедиться, воспользовавшись свойством IsFixedSize.
С помощью данного свойства Вы можете определить, имеет ли созданный массив фиксированную длину. Если результатом является значение true, как в данном примере, то это значит, что мы не можем добавлять или удалять элементы в уже созданном массиве, то есть изменять его текущий размер. Но, при этом мы можем изменять его существующие элементы.
Так как задача довольно актуальная, то какой-то способ решения всё-таки должен быть. И он есть. Если Вам необходимо создать динамический массив, то Вы можете воспользоваться, например методом Resize класса System.Array.
Данный метод принимает два параметра: имя массива и его новый размер. В ходе выполнения метода, будет создан новый массив указанной нами длины, после чего все значения из старого массива будут скопированы в него. В результате мы получаем динамический массив. Задача решена.
Либо мы можем схитрить и всё-таки решить данную задачу, воспользовавшись обобщенным списком List класса System.Collections.Generic, например:
Вместо массива мы используем список, который, как уже говорилось ранее, по умолчанию является динамическим. С помощью него мы выполняем всю необходимую работу и как только добиваемся нужного результата, то с помощью метода ToArray преобразуем список в массив.




