КаталогИндекс раздела
НазадОглавлениеВперед


Лабораторная работа ╧10

Структуры и массивы структур

1. Цель работы

     Целью лабораторной работы является получение практических навыков в работе с интегрированными типами данных - структурами и массивами структур языка C.

2. Темы для предварительной проработки

3. Задания для выполнения

     Составить программу, в которой будут вводиться 7 - 10 строк таблицы, образец которой приведен в Вашем варианте индивидуального задания к лабораторной работе ╧2 и выводится на экран таблица - сразу же после ввода и после сортировки ее по значениям в первом столбце. Примечания к таблице, которые есть в работе ╧2, можно не выводить.

4. Варианты индивидуальных заданий

 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      

5. Пример решения задачи (вариант 30)

     Решения приводится со ссылками на работу ╧2.

5.1. Разработка алгоритма решения.

     Алгоритм решения, приведенный на рисунке ниже, является типовым алгоритмом обработки массива, элементами которого являются описания монастырей.

     Алгоритм начинается с ввода значений элементов этого массива. Ввод происходит в цикле со счетчиком n, который изменяется от 0 до 9 (блок 2), но как мы увидим ниже, выход из цикла может происходить и до того, как счетчик достигнет последнего значения. В каждой итерации циклу выводится приглашение (блок 3) и вводятся значения составных частей описания монастыря (блоки 4, 6, 7, 8). Но сразу же после ввода первой составляющей - названия - проверяется ее значения (блок 5). Если введено название "***", то дальнейшего ввода не происходит, а сразу выполняется выход из цикла. В любом случае после выхода в переменной n остается количество введенных элементов. Таким образом, программа может обрабатывать массив из 10 или меньше элементов - сколько их было введено. Признаком конца ввода является название "***".

     Далее печатаем заголовок таблицы (блок 9) и в цикле (блоки 10, 11) - строки таблицы с данными. Поскольку параметр этого цикла изменяется от 0 до n-1, будет напечатано n строк.

     Следующий сложный цикл реализует сортировку таблицы по алгоритму простой обменной выборки. Сортировка выполняется с помощью вложенного цикла (блок 12). В первой итерации внешнего цикла выполняется поиск элемента массива с минимальным значением поля name. Для этого сначала минимальным элементом считается первый элемент (блок 13). Потом в цикле (блок 14) пересматриваются остальные элементы массива, и каждый сравнивается с минимальным (блок 15). Если поле name очередного элемента меньше, чем минимального, то теперь этот элемент считается минимальным (блок 16). Индекс минимального элемента записывается в переменную m. После выхода из внутреннего цикла, если найденный минимальный элемент не первый (блок 17), то он меняется местами с первым (блок 18). Таким образом, минимальный элемент массива становится на свое место. В следующей итерации внешнего цикла выполняется поиск минимума среди элементов массива, начиная со второго, в третьей - начиная с третьего и т.д. После выхода из внешнего цикла массив оказывается отсортированным.

     Вывод отсортированного массива (блоки 19 - 21) происходит точно так же, как и вывод начального массива (блоки 9 - 11).

5.2. Определение переменных программы

     Как мы отметили, элементом массива является описание объекта. Поскольку описание состоит из нескольких составных частей разного типа, для него используем структуру языка C. Описание этой структуры будет иметь вид:

    struct mon {
      char name[15]; /* название */
      char sc;       /* школа */
      int cnt;       /* количество монахов */
      float sq;      /* площадь */
      }; 

     Тут мы резервируем для названия больше символов, чем в работе ╧2, предвидя возможность появления более длинных названий, а также даем тип int полю cnt, допуская, что его значения может быть больше, чем 255.

     Нам нужно будет иметь массив элементов указанного типа, следовательно, объявляем:

   struct mon mm[10];

     Для выполнения перестановки элементов массива нужна будет еще рабочая область памяти того же типа, что и элементы массива, поэтому вводимо еще:

    struct mon x;

     Как видно из схемы алгоритма, нужны будут переменные целого типа для: количества введенных элементов n, индексов внешнего (i) и внутреннего (j) циклов и индекса минимального элемента - m. Поэтому объявляем:

    int i, j, n, m;

5.3. Разработка текста программы

     Текст программы начинаем с включения файла stdio.h.

     Поскольку нам придется проводить сравнение (блок 15) поля name в элементах массива, а это поле - символьная строка, включаем также файл string.h, где описаны функции работы с символьными строками. В самом начале программы вводим также описание структуры mon и одновременно - объявление массива mm. Массив будет размещен в статической памяти.

     Потом открывается главная функция программы, и в ней объявляются остальные переменные. Объявление:

    float sqx; 
мы прокомментируем ниже.

     Открывается простой цикл со счетчиком n, в каждой итерации цикла выводится приглашение и вводятся значения полей очередного элемента массива. Сравнение поля name с константой "***" - признаком конца ввода выполняется с помощью функции strcmp(). Если введен признак конца, происходит досрочный выход из цикла за оператором break.

     Следует, однако, остановиться на вводе значения для поля sq. Тут мы столкнулись (не впервые в нашей практике) с явлением, которое не можем объяснить иначе, чем ошибкой в системе программирования: функция scanf() работает ненадежно при вводе значений типа float и double, если это - значения полей элементов массива структур. Поэтому мы объявили рабочую переменную sqx типа float и значение поля sq сначала вводится в эту переменную, а потом присваивается полю структуры.

     Вывод массива состоит из вывода заголовка как нескольких строк-констант и вывода в цикле строк с фактическими данными - так же, как в работе ╧2.

     Следующие операторы программы подробно реализуют блоки 12 - 17 схемы алгоритма (для сравнения символьных строк применяется функция strcmp()). Детального рассмотрения требует только реализация блока 18 - перестановка элементов. Во-первых, при перестановке используется рабочая структура x: сначала содержимое i-го элемента пересылается в x, потом содержимое m-го элемента пересылается в i-ый элемент, а потом содержимое x пересылается в m-ый элемент. Во-вторых, операция присваивания, которая обычно применяется для пересылки значений, не может применяться к структуре в целом, так что присваивания происходит для каждого поля отдельно. К тому же, поле name является символьной строкой, а строки тоже не могут присваиваться прямо, а только - через функцию strcpy(). (Впрочем, для присваивания структур можно использовать функцию пересылки в памяти - memcpy().)

     Вывод таблицы-результата - такой же, как и начальной таблицы.

     Полный текст программы приведен ниже.

/********************************************************/
/*                Лабораторная работа ╧10               */
/*               Структуры и массивы структур           */
/*              Пример выполнения. ВарЁант ╧30.         */
/********************************************************/
#include <stdio.h>
#include <string.h>
/* Описание структуры, которая представляет монастырь */
struct mon {
  char name[15]; /* название */
  char sc;       /* школа */
  int cnt;       /* количество монахов */
  float sq;      /* площадь */
  } mm[10]; /* определение массива монастирей */
int main(void) {
 struct mmm x; /* рабочая переменная */
 int n;    /* количество элементов в массиве */
 int i, j; /* текущие индексы в массиве */
 int m;    /* индекс минимального элемента */
 float sqx;/* рабочая переменная */
  /* Ввод данных */
  for (n=0; n<10; n++){
    printf("%d. Введите: название, школу, количество, площадь >", 
      n+1);
    scanf("%s",mm[n].name);
    if (!strcmp(mm[n].name,"***")) break;
    scanf("%s",&mm[n].sc);
    scanf("%d",&mm[n].cnt);
    /* Внимание! Мы обходим ошибку в системе программирования */
    scanf("%f",&sqx); mm[n].sq=sqx;
    }
  /* Вывод таблицы */
  printf("---------------------------------------------\n");
  printf("|Буддийське монастыри Японии перiода Нара    |\n");
  printf("|--------------------------------------------|\n");
  printf("| Название  | Школа |Количество|   Площадь   |\n");
  printf("|           |       |  монахов | земель(га)  |\n");
  printf("|-----------|-------|----------|-------------|\n");
  /* вывод строк фактических данных */
  for (i=0; i<n; i++)
    printf("| %9s |   %c   |       %3d | %-5.1f       |\n",
      mm[i].name,mm[i].sc,mm[i].cnt,mm[i].sq);
  printf("---------------------------------------------\n");
  /* сортировка массива */
  for (i=0; i<n-1; i++) {
    m=i; /* минимальный элемент - первый */
    for (j=i+1; j<n; j++)
      /* если текущий элемент > минимального, 
         он становится минимальным */
      if (strcmp(mm[m].name,mm[j].name)>0) m=j;
    if (m>i) {
      /* перестановка первого и минимального элементов */
      strcpy(x.name,mm[i].name); x.sc=mm[i].sc;
      x.cnt=mm[i].cnt; x.sq=mm[i].sq;
      strcpy(mm[i].name,mm[m].name); mm[i].sc=mm[m].sc;
      mm[i].cnt=mm[m].cnt; mm[i].sq=mm[m].sq;
      strcpy(mm[m].name,x.name); mm[m].sc=x.sc;
      mm[m].cnt=x.cnt; mm[m].sq=x.sq;
      }
    }
  /* Вывод таблицы */
  printf("---------------------------------------------\n");
  printf("|Буддийське монастыри Японии перiода Нара    |\n");
  printf("|--------------------------------------------|\n");
  printf("| Название  | Школа |Количество|   Площадь   |\n");
  printf("|           |       |  монахов | земель(га)  |\n");
  printf("|-----------|-------|----------|-------------|\n");
   for (i=0; i<n; i++)
    printf("| %9s |   %c   |       %3d | %-5.1f       |\n",
      mm[i].name,mm[i].sc,mm[i].cnt,mm[i].sq);
  printf("---------------------------------------------\n");
  return 0;
}

5.4. Отладка программы

     При отладке программы можно использовать пошаговый режим с отслеживанием значений переменных - тех, которые вводятся. Если возникают проблемы с вводом переменных, целесообразно вводить каждую переменную отдельным оператором.

     Самой сложной может быть отладка той части программы, которая выполняет сортировку массива. Пересмотр всего массива структур средствами отладчика системы программирования хотя и возможен, но может быть достаточно громоздким. Поэтому лучше при ошибках в этой части программы вставить промежуточные выводы - например, выводить всю таблицу после каждого цикла сортировки. В пошаговом режиме можно наблюдать значение найденного минимума в каждом циклЁ.

5.5. Результаты работы программы

     При работе программы на экран было выведено следующее:

1. Введите: название, школу, количество, площадь > Тодайдзи Т 220 368.8  
2. Введите: название, школу, количество, площадь > Якусидзи С 50 54.7       
3. Введите: название, школу, количество, площадь > Дайаедзи Д 10 12.2       
-----------------------------------------------
|Буддийские монастыри Японии периода Нара     |
|---------------------------------------------|
| Название  | Школа | Количество| Площадь     |
|           |       | монахов   | земель(га)  |
|-----------|-------|-----------|-------------|
|  Тодайдзи |   Т   |       220 | 368.8       |
|  Якусидзи |   С   |        50 |  54.7       |
|  Дайаедзи |   Д   |        10 |  12.2       |
-----------------------------------------------

5.6. Выводы

     При выполнении лабораторной работы изучены вопросы:


КаталогИндекс раздела
НазадОглавлениеВперед