Массивы структур

Содержание

Структуры часто образуют массивы. Чтобы объявить массив структур, вначале необходимо определить структуру (то есть определить агрегатный тип данных), а затем объявить переменную массива этого же типа. Например, чтобы объявить 100-элементный массив структур типа addr, который был определен ранее, напишите следующее:

struct addr addr_list[100];

Это выражение создаст 100 наборов переменных, каждый из которых организован так, как определено в структуре addr.

Чтобы получить доступ к определенной структуре, указывайте имя массива с индексом. Например, чтобы вывести ZIP-код из третьей структуры, напишите следующее:

printf("%d", addr_list[2].zip);

Как и в других массивах переменных, в массивах структур индексирование начинается с 0.

Для справки: чтобы указать определенную структуру, находящуюся в массиве структур, необходимо указать имя этого массива с определенным индексом. А если нужно указать индекс определенного элемента в структуре, то необходимо указать индекс этого элемента. Таким образом, в результате выполнения следующего выражения первому символу члена name, находящегося в третьей структуре из addr_list, присваивается значение ‘X’.

addr_list[2].name[0] = 'X';

Пример со списком рассылки


Чтобы показать, как используются структуры и массивы структур, в этом разделе создается простая программа работы со списком рассылки, и в ее массиве структур будут храниться адреса и связанная с ними информация. Эта информация записывается в следующие поля: name (имя), street (улица), city (город), state (штат) и zip (почтовый код, индекс).

Вся эта информация, как показано ниже, находится в массиве структур типа addr:

struct addr {
  char name[30];
  char street[40];
  char city[20];
  char state[3];
  unsigned long int zip;
} addr_list[MAX];

Обратите внимание, что поле zip имеет целый тип unsigned long. Правда, чаще можно встретить хранение почтовых кодов, в которых используются строки символов, потому что этот способ подходит для почтовых кодов, в которых вместе с цифрами используются и буквы (как, например, в Канаде и других странах). Однако в нашем примере почтовый индекс хранится в виде целого числа; это делается для того, чтобы показать использование числового элемента в структуре.

Вот main() — первая функция, которая нужна программе:

int main(void)
{
  char choice;

  init_list(); /* инициализация массива структур */

  for(;;) {
    choice = menu_select();
    switch(choice) {
      case 1: enter();
        break;
      case 2: delete();
        break;
      case 3: list();
        break;
      case 4: exit(0);
    }
  }

  return 0;
}

Функция начинает выполнение с инициализации массива структур, а затем реагирует на выбранный пользователем пункт меню.

Функция init_list() готовит массив структур к использованию, обнуляя первый байт поля name каждой структуры массива. (В программе предполагается, что если поле name пустое, то элемент массива не используется.) А вот сама функция init_list():

/* Инициализация списка. */
void init_list(void)
{
  register int t;

  for(t=0; t<MAX; ++t) addr_list[t].name[0] = '\0';
}

Функция menu_select() выводит меню на экран и возвращает то, что выбрал пользователь.

/* Получения значения, выбранного в меню. */
int menu_select(void)
{
  char s[80];
  int c;

  printf("1. Введите имя\n");
  printf("2. Удалите имя\n");
  printf("3. Выведите список\n");
  printf("4. Выход\n");

  do {
    printf("\nВведите номер нужного пункта: ");
    gets(s);
    c = atoi(s);
  } while(c<0 || c>4);

  return c;
}

Функция enter() подсказывает пользователю, что именно требуется ввести, и сохраняет введенную информацию в следующей свободной структуре. Если массив заполнен, то выводится сообщение Список заполнен. Функция find_free() ищет в массиве структур свободный элемент.

/* Ввод адреса в список. */
void enter(void)
{
  int slot;
  char s[80];

  slot = find_free();
  if(slot==-1) {
    printf("\nСписок заполнен");
    return;
  }

  printf("Введите имя: ");
  gets(addr_list[slot].name);

  printf("Введите улицу: ");
  gets(addr_list[slot].street);

  printf("Введите город: ");
  gets(addr_list[slot].city);

  printf("Введите штат: ");
  gets(addr_list[slot].state);

  printf("Введите почтовый код: ");
  gets(s);
  addr_list[slot].zip = strtoul(s, '\0', 10);
}

/* Поиск свободной структуры. */
int find_free(void)
{
  register int t;

  for(t=0; addr_list[t].name[0] && t<MAX; ++t) ;

  if(t==MAX) return -1; /* свободных структур нет */
  return t;
}

Обратите внимание, что если все элементы массива структур заняты, то find_free() возвращает -1. Это удобное число, потому что в массиве нет -1-го элемента.

Функция delete() предлагает пользователю указать индекс той записи с адресом, которую требуется удалить. Затем функция обнуляет первый байт поля name.

/* Удаление адреса. */
void delete(void)
{
  register int slot;
  char s[80];

  printf("Введите № записи: ");
  gets(s);
  slot = atoi(s);
  if(slot>=0 && slot < MAX)
    addr_list[slot].name[0] = '\0';
}

И последняя функция, которая требуется программе, — это list(), которая выводит на экран весь список рассылки. Из-за большого разнообразия компьютерных сред язык С не определяет стандартную функцию, которая бы отправляла вывод на принтер. Однако все нужные для этого средства имеются во всех компиляторах С. Возможно, вам самим захочется сделать так, чтобы программа работы со списками могла еще и распечатывать список рассылки.

/* Вывод списка на экран. */
void list(void)
{
  register int t;

  for(t=0; t<MAX; ++t) {
    if(addr_list[t].name[0]) {
      printf("%s\n", addr_list[t].name);
      printf("%s\n", addr_list[t].street);
      printf("%s\n", addr_list[t].city);
      printf("%s\n", addr_list[t].state);
      printf("%lu\n\n", addr_list[t].zip);
    }
  }
  printf("\n\n");
}

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

/* Простой пример программы обработки списка,
   в которой используется массив структур. */
#include <stdio.h>
#include <stdlib.h>

#define MAX 100

struct addr {
  char name[30];
  char street[40];
  char city[20];
  char state[3];
  unsigned long int zip;
} addr_list[MAX];

void init_list(void), enter(void);
void delete(void), list(void);
int menu_select(void), find_free(void);

int main(void)
{
  char choice;

  init_list(); /* инициализация массива структур */
  for(;;) {
    choice = menu_select();
    switch(choice) {
      case 1: enter();
        break;
      case 2: delete();
        break;
      case 3: list();
        break;
      case 4: exit(0);
    }
  }

  return 0;
}

/* Инициализация списка. */
void init_list(void)
{
  register int t;

  for(t=0; t<MAX; ++t) addr_list[t].name[0] = '\0';
}

/* Получения значения, выбранного меню. */
int menu_select(void)
{
  char s[80];
  int c;

  printf("1. Введите имя\n");
  printf("2. Удалите имя\n");
  printf("3. Выведите список\n");
  printf("4. Выход\n");
  do {
    printf("\nВведите номер нужного пункта: ");
    gets(s);
    c = atoi(s);
  } while(c<0 || c>4);
  return c;
}

/* Ввод адреса в список. */
void enter(void)
{
  int slot;
  char s[80];

  slot = find_free();

  if(slot==-1) {
    printf("\nСписо заполнен");
    return;
  }

  printf("Введите имя: ");
  gets(addr_list[slot].name);

  printf("Введите улицу: ");
  gets(addr_list[slot].street);

  printf("Введите город: ");
  gets(addr_list[slot].city);

  printf("Введите штат: ");
  gets(addr_list[slot].state);

  printf("Введите почтовый индекс: ");
  gets(s);
  addr_list[slot].zip = strtoul(s, '\0', 10);
}

/* Поиск свободной структуры. */
int find_free(void)
{
  register int t;

  for(t=0; addr_list[t].name[0] && t<MAX; ++t) ;

  if(t==MAX) return -1; /* свободных структур нет */
  return t;
}

/* Удаление адреса. */
void delete(void)
{
  register int slot;
  char s[80];

  printf("Введите № записи: ");
  gets(s);
  slot = atoi(s);

  if(slot>=0 && slot < MAX)
    addr_list[slot].name[0] = '\0';
}

/* Вывод списка на экран. */
void list(void)
{
  register int t;

  for(t=0; t<MAX; ++t) {
    if(addr_list[t].name[0]) {
      printf("%s\n", addr_list[t].name);
      printf("%s\n", addr_list[t].street);
      printf("%s\n", addr_list[t].city);
      printf("%s\n", addr_list[t].state);
      printf("%lu\n\n", addr_list[t].zip);
    }
  }
  printf("\n\n");
}