Динамический массив структур мы разберем на примере. Нам предстоит решить следующую задачу: пользователь вводит данные о спонсорах какого-то проекта. А именно – прізвище, имя и сумму пожертвования. После каждого ввода данных программа задает вопрос: продолжить ввод или нет.
Каждый раз, коли користувач вибирає “продолжить” – надо выделить участок памяти еще под одну структуру. Таким образом динамический массив структур будет расти, пока пользователь не приостановит ввод. После завершения ввода, вивести таблицю з даними про спонсорів на екран.
| 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
GEA2B