Динамический массив структур мы разберем на примере. Нам предстоит решить следующую задачу: пользователь вводит данные о спонсорах какого-то проекта. А именно – фамилию, имя и сумму пожертвования. После каждого ввода данных программа задает вопрос: продолжить ввод или нет.
Каждый раз, когда пользователь выбирает “продолжить” – надо выделить участок памяти еще под одну структуру. Таким образом динамический массив структур будет расти, пока пользователь не приостановит ввод. После завершения ввода, вывести таблицу с данными о спонсорах на экран.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | #include<iostream> #include<windows.h> using namespace std; struct Sponsor { char name[32]; char surname[32]; double sum; }; Sponsor* AddStruct(Sponsor* Obj, const int amount); void setData(Sponsor* Obj, const int amount); void showData(const Sponsor* Obj, const int amount); int main() { setlocale(LC_ALL, "rus"); Sponsor* OurSponsors = 0; int sponsorAmount = 0; int YesOrNot = 0; // продолжить или остановить ввод данных do { OurSponsors = AddStruct(OurSponsors, sponsorAmount); setData(OurSponsors, sponsorAmount); sponsorAmount++; cout << "Продолжить ввод данных (1 - да, 0 - нет): "; cin >> YesOrNot; cin.get(); } while (YesOrNot != 0); showData(OurSponsors, sponsorAmount); delete[] OurSponsors; return 0; } Sponsor* AddStruct(Sponsor* Obj, const int amount) { if (amount == 0) { Obj = new Sponsor[amount + 1]; // выделение памяти для первой структуры } else { Sponsor* tempObj = new Sponsor[amount + 1]; for (int i = 0; i < amount; i++) { tempObj[i] = Obj[i]; // копируем во временный объект } delete [] Obj; Obj = tempObj; } return Obj; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void setData(Sponsor* Obj, const int amount) { cout << "Фамилия: "; cin.getline(Obj[amount].surname, 32); cout << "Имя: "; cin.getline(Obj[amount].name, 32); cout << "Сумма пожертвования: "; cin >> Obj[amount].sum; cin.get(); cout << endl; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void showData(const Sponsor* Obj, const int amount) { system("cls"); cout << "№ " << "Фамилия\t" << "Имя\t" << "Сумма\t" << endl; cout << "========================================" << endl; for (int i = 0; i < amount; i++) { cout << i + 1 << " " << Obj[i].surname << '\t' << Obj[i].name << '\t' << Obj[i].sum << endl; } } |
Определение структуры находится в строках 5 – 10. В ней объявлены три элемента name, surname, sum. Ниже объявлены прототипы функций, необходимых для решения задачи. Первая функция Sponsor* AddStruct(Sponsor* Obj, const int amount); будет выделять память для элементов массива структур. Вторая void setData(Sponsor* Obj, const int amount); отвечает за ввод данных в структуру. Третья void showData(const Sponsor* Obj, const int amount); – выводит на экран все данные в виде таблицы. Определения этих функций мы рассмотрим ниже.
Чтобы создать динамический массив структур, надо, как и для создания обычного динамического массива, объявить указатель. Только вместо встроенного типа указать дескриптор структуры – строка 20. Этот указатель пока ни на что не указывает. Можно было бы выделить память под массив структур сразу. Например:
Но мы организуем более гибкое выделение памяти под этот динамический массив структур – она будет выделяться по необходимости. Есть один спонсор – выделится память под одну структуру. Есть 3 спонсора – память выделится сначала под одну структуру, потом под вторую и далее под третью. Все будет зависеть от того – решит ли пользователь продолжить ввод.
В строках 21 – 22, объявлены переменные sponsorAmount – счетчик количества спонсоров и YesOrNot – выбор пользователя (продолжить или прервать ввод).
Строки 24 – 34: здесь расположен цикл do while. Он выполняется до тех пор, пока пользователю необходимо вводить данные. В строке 26 вызываем функцию, которая выделяет память под структуру OurSponsors = AddStruct(OurSponsors, sponsorAmount); Опустимся к ее определению в строках 42 – 61. Тут видно, что данная функция будет возвращать указатель на структуру Sponsor.
Она принимает два параметра – указатель на структуру и количество структур. Когда она вызывается в первый раз – в нее будет передан объявленный в main указатель OurSponsors и переменная sponsorAmount, которая равна нулю. В функции выполнится блок if – выделится память для одной структуры (строки 44 – 47). Потом функция вернет адрес (указатель) на этот участок памяти и он будет записан в OurSponsors – строка 26.
В строке 27 вызываем функцию, которая позволит внести данные в структуру. Её определение находится в строках 63 – 73. После внесения данных, переменная sponsorAmount увеличивается на единицу. Пользователю предлагаем сделать выбор – продолжить ввод или завершить работу. Если продолжаем – снова вызывается функция AddStruct().
Надо помнить, что указатель OurSponsors уже ссылается на участок памяти с записанными данными. Поэтому не получится просто перевыделить память. Сначала необходимо позаботиться о сохранении данных. Посмотрите на блок else строки 48 – 59. В строке 50 создаем временный указатель. Под него выделяем память для amount + 1 структур (т.е. на одну структуру больше, чем приняла функция). Далее копируем данные из принятого объекта.
Последний объект массива структур tempObj останется незаполненным. Когда данные скопированы, освобождаем память Obj – строка 57 и записываем в этот указатель новый адрес. Теперь он будет указывать на память, в которой есть сохраненные данные и дополнительный выделенный участок памяти для заполнения новыми данными.
И снова вызывается функция setData(), которая позволит внести данные в новый выделенный участок памяти – в последний элемент массива структур.
Когда пользователь решит больше не вводить данные – он нажимает ноль. После этого сработает функция showData() и на экране отобразится таблица с данными со всех структур динамического массива. В самом конце программы не забываем освободить память, которую занимает динамический массив структур.
Результат – ввод данных:
Таблица:
int YesOrNot = 1;
Почему в addstruct не удаляем tempObj если в конце все значения уже переданы в Obj?
+1 Освобождается ли память, выделенная под переменную tempObj после завершения функции?
А, пардон, мы же в выделенной под tempObj памяти теперь и храним массив!
Всё, что вы выделяете в своей программе через оператор new, не будет удалятся автоматически, все такие объекты программы выделяются в отдельной “куче” памяти, и вы обязаны их удалять вручную, оператором delete, после того, как в них исчезнет необходимость.
В этом конкретном примере tempObj – это указатель на начало размещения массива, вы его присваиваете такому же указателю Obj (который и возвращается из функции AddStruct), а само значение указателя tempObj уничтожается в точке завершения функции AddStruct.
почему в 46 строке выделяется память amount + 1??? можно, пожалуйста конкретное объяснение??
1u6bqc