Структуры и алгоритмы компьютерной обработки данных

Структуры

Показывать лекцию целиком

Цель лекции: изучить понятия, оформления и определения структур, доступа к элементам структур, научиться решать задачи с использованием структур на языке C++.

В языке С++ возможно формирование производных (пользовательских) типов данных прежде всего на основе массивов, структур и объединений. Комбинирование этих типов данных позволяет программно моделировать достаточно сложные объекты реальности.

Агрегатным типом данных называется тип, конструируемый из элементов независимых (возможно различных) типов.

Структура – это составной объект, в который входят элементы любых типов, за исключением функций. В отличие от массива, который является однородным объектом (все элементы относятся к одному типу данных), структура может быть неоднородной. Таким образом, структура – это тип данных, сформированный из объектов однородных либо разнообразных типов данных.

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

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

Традиционный пример структуры – строка платежной ведомости. Она содержит такие сведения о служащем, как его полное имя, адрес, номер карточки социального страхования, зарплата и т.д. Некоторые из этих характеристик сами могут быть структурами: например, полное имя состоит из нескольких компонент (фамилии, имени и отчества); аналогично адрес и даже зарплата. Другой пример – из области графики: точка на плоскости есть пара вещественных координат, шар в пространстве моделируется четырьмя вещественными числами и т. д.

Объявление структур и определение структурных объектов

Использование в программе структуры предполагает вначале определение (объявление) структуры-шаблона (типа структуры) и его структурного объекта (структурной переменной). Возможны их раздельное и совместное определения. Для шаблона структуры (с именем или без него) компилятор не выделяет в памяти компьютера место под структуру, а лишь фиксирует правила, необходимые для формирования структурного объекта (структурной переменной).

В момент определения структурного объекта компилятор выделяет место в памяти, где размещаются все компоненты структуры в соответствии с заданным шаблоном.

Ключевое слово struct сообщает компилятору об объявлении структуры. Допустимы три основные формы объявления структур.

1) С поименованным шаблоном:

struct ИмяСтруктурногоТипа {ОпределенияЭлементов};

где ИмяСтруктурногоТипа – идентификатор типа структуры. Следует обратить внимание на точку с запятой, которой заканчивается определяемая структура;

ОпределенияЭлементов – список определений типизированных компонентов (полей), из которых образуется шаблон структуры. Он в общем случае представляется так:

Тип1 Компонент11 [,Компонент12,...];
...................................
ТипК КомпонентК1 [,КомпонентК2,...];

Здесь допустимы компоненты различных типов. Все имена компонентов уникальны. Шаблон имеет видимость. Если он объявлен внутри блока, то это локальный шаблон, видимый только внутри него.

Например:

struct STUDENT {
                char name[50]; //Ф.И.О
                int passw; //шифр зачетной книжки
               };

При указанной форме объявления структуры структурные объекты определяются ниже в виде отдельной строки:

ИмяСтруктурногоТипа СписокСтруктур;

где СписокСтруктур – список идентификаторов, соответствующих именам структурных объектов.

Структурные объекты можно определить так:

STUDENT group0l, group02, //структурные объекты
        *univers, //указатель на структурный объект
        fam[100]; //массив структурных объектов

При определении структурного объекта (структурной переменной) СтруктурныйОбъект допустима инициализация его компонентов (полей):

struct ИмяСтруктурногоТипа СтруктурныйОбъект = {Инициализатор1,
                                               Инициализатор2,
                                               ..............
                                               ИнициализаторK
                                              };

Для вышеприведённого примера возможно следующее:

struct STUDENT group0l = {
                          "Сидоров ", 
                          6374268 
                         };

2) С совмещением определения структуры и структурных объектов:

struct ИмяСтруктурногоТипа {ОпределенияЭлементов} 
       СписокСтруктур;

Структурный объект при такой схеме определения может быть также инициализирован.

Например, структура типа STUDENT с элементами ФИО и номером зачётной книжки:

struct STUDENT {
                char name[50]; 
                int passw;
               } *univers,//указатель на структурный объект
                 fam[100],//массив структурных объектов 
                 group0l = {"Сидоров А.И.", 26276};
                           //инициализированный объект

При рассматриваемом подходе ИмяСтруктурногоТипа (STUDENT) можно опустить.

В пределах программы допустим один непоименованный тип структуры.

3) С использованием оператора typedef:

typedef struct [ИмяСтруктурногоТипа] 
               {ОпределенияЭлементов} 
               ОбозначениеСтруктурногоТипа;

где ОбозначениеСтруктурногоТипа – синонимы типа структуры. Это упрощает программу при определении структурных объектов. Кроме того, в упрощённом определении имя типа структуры можно опустить.

Например:

typedef struct {
                char name[50];
                int passw;
               } NSTUstudent; 
                 //NSTUstudent - псевдоним типа структуры

Определение структурного объекта для данного случая можно организовать так:

NSTUstudent *pt, //указатель на структуру
groupStudent; //структурная переменная

Здесь также допускается инициализация определяемых структурных объектов.

Можно определить структуру с использованием макроопределения:

#define Идентификатор struct ИмяТипа

Далее следует

Идентификатор {ОпределенияЭлементов};

Например:

#define COMPLEX struct R7 
COMPLEX {
         float real;
         float imag;
        };

Инициализация структуры

Инициализация структуры заключается в присваивании начальных значений элементам структуры. Структуры могут быть проинициализированы при их объявлении.

Инициализирующая запись – это заключенный в фигурные скобки список, элементы которого разделяются запятыми и являются константами. Любые неинициализированные элементы внешних или статических структур по умолчанию равны 0. Значения неинициализированных элементов автоматических структур не определены.

Для инициализации структур значения ее полей перечисляются в фигурных скобках.

Например:

Первый способ

struct Student {
                char name[20];
                int kurs;
                float rating;
               };
Student s={"Королев",1,3.5};

Второй способ

struct {
        char name[20];
        char title[30];
        float rate;
       } employee={"Петров", "программист",58000};

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

Например:

stuct mix {int N; double *d;}
struct hole {
             struct mix exit;
             float b;
            }

Присваивание структур

Для переменных одного и того же структурного типа определена операция присваивания. При этом происходит поэлементное копирование.

Student t=s;

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

Например:

#include <stdio.h>
void main(){
struct {
        int a;
        int b;
       } x, y;
  x.a = 10;
  x.b = 20;
  y = x;
  printf("Содержимое y: %d %d", y.a, y.b);
}

Доступ к элементам структур (полям данных)

С помощью операций прямого и косвенного выбора (соответственно символы точка '.' и '->') организуется доступ к элементам структур. Первая операция используется со структурными объектами, а вторая – при наличии указателя на структурный объект.

Операция прямого доступа к элементам структуры ('.') – результатом является значение элемента структуры.

Синтаксис операции прямого доступа к элементам структуры:

ИмяСтруктуры.ИмяЭлементаСтруктуры

Данная операция используется для доступа к элементу структуры с тем, чтобы присвоить ему значение, напечатать его, использовать его значение в арифметической операции и т.д. Эта операция является первичной и находится в самой верхней строке таблицы приоритетов операций языка С++.

Именем структуры можно пользоваться сразу же после его появления в программе.

Например:

struct A {
          int j;
          char titl[10]; 
          char x;
          } Аа, Аb = {128,"Мир",'Q'};

Здесь допустимы операторы присваивания вида Аа=Аb;. В этом случае элементы структурного объекта Аа будут иметь значения, совпадающие со значениями соответствующих элементов объекта Аb.

Пример 1.

//Инициализация структуры и вывод значений ее элементов
#include "stdafx.h"
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[]) {
  struct goods {
                char* name;
                long price;
                float percent;
                int vol;
                char date[9];
               };
  struct goods coat={"пиджак черный",4000,7.5,220,"12.01.09"};
  printf("\n Товар на складе:");
  printf("\n Наименование: %s.", coat.name);
  printf("\n Оптовая цена: %ld руб.", coat.price);
  printf("\n Наценка: %3.1f %%.", coat.percent);  
  printf("\n Цена товара: %ld руб.",
          (long)(coat.price*(1.0+coat.percent/100)));  
  printf("\n Объем партии: %d штук.", coat.vol);
  printf("\n Дата поставки: %s.",coat.date);
  system("pause");
  return 0;
}

Пример 2. Сложение комплексных чисел

#include "stdafx.h"
#include <iostream>
using namespace std;
typedef  struct {
                 double real;
                 double imag;
                } complex;

int _tmain(int argc, _TCHAR* argv[]) {
  complex x,y,z;
  printf("\n Введите два комплексных числа:");
  printf("\n Вещественная часть:");  scanf("%lf", x.real);
  printf("\n Мнимая часть:");  scanf("%lf", x.imag);
  printf("\n Вещественная часть:");  scanf("%lf", y.real);
  printf("\n Мнимая часть:");  scanf("%lf", y.imag);
  z.real=x.real+y.real;
  z.imag=x.imag+y.imag;
  printf("\n Результат: z.real=%f z.imag=%f", z.real,z.imag);
  system("pause");
  return 0;
}

Определение размера памяти, выделяемой под структуру

Размер памяти, занимаемый структурным объектом, можно вычислить, исходя из размеров элементов структуры либо с помощью операции:

sizeof (ИмяСтруктуры)
sizeof (ИмяСтруктурногоТипа)

Определение структурного типа не связано с выделением памяти под сам тип, а при каждом определении структуры (объекта) ей выделяется память в таком количестве, чтобы могли разместиться данные всех элементов. Однако стандарт языка С++ не дает гарантий, что элементы структур будут размещаться непрерывно. Причиной появления неиспользованных участков памяти ("дыр") могут явиться требования выравнивания данных по границам участков адресного пространства. Эти требования зависят от реализации, от аппаратных возможностей системы и иногда от режимов (опций) работы компилятора.

Например:

sizeof(struct goods) – 24 байта (из Примера 1)

sizeof(goods) – 24 байта (из Примера 1)

sizeof coat – 24 байта (из Примера 1)

sizeof(complex) – 16 байтов (из Примера 2)

Пример 3. Программа вывода размера памяти для структурного объекта

#include "stdafx.h"
#include <iostream>
using namespace std;
  struct A {
            int j;
            char titl[10];
            char x;
           } Aa, Ab={128, "Мир", 'Q'};

int _tmain(int argc, _TCHAR* argv[]) {
  printf("\nAb.j=%d Ab.titl=%s Ab.x=%c", Ab.j, Ab.titl, Ab.x);
  printf("\nПамять для объекта Аа равна %d байт ", sizeof (Aa));
  system("pause");
  return 0;
}

Результат выполнения программы:

Ab.j=128 Ab.titl=Мир Ab.x=Q
Память для объекта Аа равна 16 байт

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

Массив структур – это массив, каждый элемент которого является структурой. В памяти элементы массива структур размещаются последовательно.

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

Из элементов структурного типа можно организовать массивы также как из элементов стандартного типа. Для объявления массива структур следует сначала определить структуру, а затем объявить массив переменных данного типа. Как и массивы переменных, массивы структур индексируются с нуля.

Например:

#include "stdafx.h"
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[]) {
  struct Student {
                  char name[30];
                  char group[10];
                  float rating;
                 };
  Student mas[35]; //массив структур
  int i;

  //ввод значений массива
  for(int i=0;i<35;i++){
    cout << "\nВведите имя: ";cin >> mas[i].name;
    cout << "\nВведите группу: ";cin >> mas[i].group;
    cout << "\nВведите рейтинг: ";cin >> mas[i].rating;
  }
  //вывод студентов, у которых рейтинг меньше 3
  cout << "Рейтинг < 3: ";
  for(i=0; i<35; i++)
    if(mas[i].rating<3)
      cout << "\n" << mas[i].name;
  system("pause");
  return 0;
}

Пример 4. Программа определяет и печатает название самой высокой вершины из списка

#include "stdafx.h"
#include <iostream>
using namespace std;
struct peak {
             char name[15];//название вершины
             int height; //высота вершины
            } list[30]; //массив структурного типа peak
int N;

void InputDate();
void PrintMaxPic();

int _tmain(int argc, _TCHAR* argv[]) {
  InputDate();
  printf("\n");
  PrintMaxPic();
  system("pause");
  return 0;
}

void InputDate() {
int i;
  printf("Введите количество вершин: "); scanf("%d",N);
  printf("\n");
  for (i=0; i<N; i++) {
    printf("Название: ");
    scanf("%s",list[i].name);
    printf("Вершина: ");
    scanf("%d",list[i].height);
  }
}

void PrintMaxPic(){
int i,max=list[0].height,num=0;
  for (i=1; i<N; i++)
    if (list[i].height>max) {
      max=list[i].height;
      num=i;
    }
  printf("Самая высокая вершина - %s, она равна ­ %d", 
          list[num].name,max);
}

Пример 5. Программа инициализирует массив структур, сортирует и выводит его на печать.

#include "stdafx.h"
#include <iostream>
using namespace std;
#include <time.h>
#define num 5
struct {
        char name[15];
        int grade;
       } x[num];

void init(void);
int sorts(const void *p1, const void *p2);
void print(void);

int _tmain(int argc, _TCHAR* argv[]) {
  printf("\n Введите имена:\n");
  init();
  printf("\n Первоначальный массив\n"); 
  print();
  printf("\n Отсортированный массив\n");
  qsort((void *)x, num, sizeof(x[0]), sorts);
  print();
  system("pause");
  return 0;
}

void init(void){
  int i, a=-10, b=10;  
  srand(time(NULL)*1000);
  for (i=0; i!=num; i++){
    gets(x[i].name);
    x[i].grade =int(rand()*1.0/(RAND_MAX)*(b-a)+a);
  }
}

//сортируем по имени
int sorts(const void *p1, const void *p2){
  return( strcmp((char *)p1,(char *)p2));
}

void print(void){
  int t;
  for (t = 0; t != num; t++)
    printf("%s\t\t%d\n", x[t].name, x[t].grade);
}

Ключевые термины

Агрегатный тип данных – это тип, конструируемый из элементов независимых (возможно различных) типов.

Инициализирующая запись – это заключенный в фигурные скобки список, элементы которого разделяются запятыми и являются константами.

Массив структур – это массив, каждый элемент которого является структурой.

Поименованный шаблон – это одна из основных форм объявления структур, задаваемая именем структурного типа и определениями элементов.

Поля структуры – это составные части структуры, характеризующиеся именем, типом и размером.

Размер структуры – это объем памяти, занимаемой структурой.

Структура – это составной объект, в который входят элементы любых типов, за исключением функций.

Краткие итоги

  • Структура является представителем агрегатного типа данных в языке С++.
  • Существует три основные формы объявления структур: с поименованным шаблоном, с совмещением определения структуры структурных объектов, с использованием оператора typedef.
  • Инициализация структуры заключается в присваивании начальных значений элементам структуры.
  • Для структур можно выполнить операцию прямого присваивания.
  • Доступ к элементам структур (полям данным) можно осуществить с помощью операций прямого и косвенного выбора.
  • Размер памяти, занимаемой структурой, зависит от реализации и вычисляется с помощью операции sizeof.
  • Для решения прикладных задач используются массивы структур.
  • Лабораторная работа 15. Структуры

    Цель работы: изучить понятия, оформления и определения структур, доступа к элементам структур, научиться решать задачи с использованием структур на языке C++.

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

    Теоретические сведения.

    Ознакомьтесь с материалом лекции 15.

    Задания к лабораторной работе.

    Выполните приведенные ниже задания.

  • Описать переменную "студент", содержащую: имя, фамилию, отчество, название учебного заведения, номер группы. Создать список студентов ( N>10 ). Определить и распечатать фамилии студентов, учащихся заданной группы и заданного учебного заведения.
  • Задана следующая структура:
    struct point {
                  float x,y;
                 } A, B;
    Описать переменную d, равную расстоянию между точками A и B.
  • Описать переменную "круг", в которой содержатся все данные для построения круга на плоскости в декартовой системе координат. Определить площадь круга и длину окружности, ограничивающей круг.
  • Задана следующая структура:
    struct card {
       // масть карт 
       enum {spades, clubs, diamonds, hearts} suit; 
       // достоинство карт 
       enum{six, seven, eight, nine, ten, jack, queen, king, ace} value;
       } c1, c2;
    Описать логическую функцию Kick(с1, с2, сs), проверяющую, бьёт ли карта с1 карту с2, с учётом того, что масть cs является козырной.

    Описать переменную "адрес", содержащую: название города, название улицы, номер дома, корпус, номер квартиры. Создать массив адресов. Поменять местами номер дома в N -ом адресе и номер квартиры в M -ом адресе.

  • Указания к выполнению работы.

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

    Следует реализовать каждое задание в соответствии с приведенными этапами:

  • изучить словесную постановку задачи, выделив при этом все виды данных;
  • сформулировать математическую постановку задачи;
  • выбрать метод решения задачи, если это необходимо;
  • разработать графическую схему алгоритма;
  • записать разработанный алгоритм на языке С++;
  • разработать контрольный тест к программе;
  • отладить программу;
  • представить отчет по работе.
  • Требования к отчету.

    Отчет по лабораторной работе должен соответствовать следующей структуре.

  • Титульный лист.
  • Словесная постановка задачи. В этом подразделе проводится полное описание задачи. Описывается суть задачи, анализ входящих в нее физических величин, область их допустимых значений, единицы их измерения, возможные ограничения, анализ условий при которых задача имеет решение (не имеет решения), анализ ожидаемых результатов.
  • Математическая модель. В этом подразделе вводятся математические описания физических величин и математическое описание их взаимодействий. Цель подраздела – представить решаемую задачу в математической формулировке.
  • Алгоритм решения задачи. В подразделе описывается разработка структуры алгоритма, обосновывается абстракция данных, задача разбивается на подзадачи. Схема алгоритма выполняется по ЕСПД (ГОСТ 19.003-80 и ГОСТ 19.002-80).
  • Листинг программы. Подраздел должен содержать текст программы на языке программирования С++, реализованный в среде MS Visual Studio 2010.
  • Контрольный тест. Подраздел содержит наборы исходных данных и полученные в ходе выполнения программы результаты.
  • Выводы по лабораторной работе.
  • Ответы на контрольные вопросы.
  • Контрольные вопросы

  • В чем принципиальное отличие типов массив и структура?
  • Как располагаются в памяти элементы структуры?
  • Почему размер структуры не всегда совпадает с суммарным размером ее полей?
  • Для моделирования каких данных целесообразно использовать структуры?
  • Какими способами можно обратиться к данным структуры?
  • В чем отличие прямого и косвенного доступа к полям структуры?
  • Всегда ли возможно выполнить напрямую операцию присваивания значений объектов структуры с одинаковым набором полей?
  • При каком объявлении структурных объектов возможно выполнить напрямую операцию присваивания значений объектов структуры?
  • Для моделирования каких данных целесообразно использовать массив структур?
  • Вернуться к учебному плану