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

Структуры и указатели

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

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

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

Указатели на структуры

Указатель на структуру объявляется точно так же, как и указатель на данные простых типов: используется операция '*' и указывается тип данных. Тип данных структуры указывается заданием ключевого слова struct и имени шаблона этой структуры.

Синтаксис:

ИмяСтруктурногоТипа *ИмяУказателяНаСтруктуру

Например:

struct goods *p_goods;
struct student *p_stu1, *p_stu2;

Указатели на структуры могут вводиться и для безымянных (не имеющих имен) структурных типов.

Например:

struct  {
         char *name;
         int age;
        } *person; //указатель на структуру

Если структура объявлена с помощью typedef, то при определении указателей название этого типа может использоваться без служебного слова struct.

Например:

complex *cc, *ss, comp;

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

Например:

struct particle {
                 double mass;
                 float coord[3];
                } dot[3], point, *pinega;

//Инициализация указателей
struct particle *p_d=dot[1], *pinta=point;

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

Например:

pinega=dot[0];

При определении элемента структуры запрещено указание в качестве элемента самого себя (через структурный объект).

Например:

struct STUD { //некорректное объявление поля структуры
             STUD t;
            } a, b;

Однако элемент структуры может быть указателем на определяемую структуру.

Например:

struct STUD { //корректное объявление поля структуры
             STUD *pt;
            } a, b;

Кроме того, допустимо неполное определение типа структуры, если ее указатель является элементом другой структуры.

Например:

struct A; //неполное определение структурного типа
struct B {struct A *pta;};
struct A {struct B *ptb;};

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

Например:

struct part {
             double modul;
             struct cell *element_cell;
             struct part *element_part;
            };
struct cell {
             long summa;
             struct cell *one;
             struct part *two;
            };

Доступ к элементам структур через указатель

Указатель на структуру обеспечивает доступ к ее элементам двумя способами:

(*УказательНаСтруктуру).ИмяЭлемента

или

УказательНаСтруктуру->ИмяЭлемента

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

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

Например:

(*pinega).mass       эквивалентно     pinega -> mass

(*pinega).coord[0]   эквивалентно     pinega -> coord[0]

Пример 1.

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
struct student {
                char name[10];
                char surname[15];
                int age;
               } stud;  
       //переменная stud объявлена как структура типа student
int _tmain(int argc, _TCHAR* argv[]) {
  struct student *s;  // указатель на структуру student
  s=stud;            // инициализация указателя
  strcpy(s->name,"Larry"); 
  //обращение как к указателю на структуру
  strcpy(s->surname,"Johnson");
  (*s).age=34;    //обращение как к переменной 
  printf("\n Имя: %s \n Фамилия: %s \n Возраст = %i",
           s->name,s->surname,s->age);
  system("pause");
  return 0;
}

Операции над указателями на структуры

Эти операции не отличаются от операций над другими указателями на данные. Исключение составляет операция "стрелка" ( -> ). Если присвоить указателю на структуру конкретного структурного типа значение адреса одного из элементов массива структур того же типа, то, изменяя значение указателя (например, с помощью операций ++ или -- ), можно равномерно "перемещаться" по массиву структур.

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

#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdio.h>
struct complex {//Опредение структуры
                float x;
                float y;
               }array[]={1.0,2.0,3.0,-4.0,-5.0,-6.0,-7.0,-8.0};
  struct complex summa = {0.0, 0.0};
  struct complex *point = array[0];

int _tmain(int argc, _TCHAR* argv[]) {
  int i;
  int k;
  k=sizeof(array)/sizeof(array[0]);
  for (i=0; i<k; i++){
    summa.x+=point->x;   
    summa.y+=point->y; }
  printf("\n Сумма: real=%f, \t  imag=%f", summa.x, summa.y);
  system("pause");
  return 0;
}

Пример 3. Программа считывает системное время компьютера и переводит его во время по Гринвичу.

#include "stdafx.h"
#include <iostream>
using namespace std;
#include <time.h>
int _tmain(int argc, _TCHAR* argv[]) {
  struct tm {
  int tm_sec;   //Секунды
  int tm_min;   //Минуты
  int tm_hour;  //Часы (0-23)
  int tm_mday;  //День месяца (1-31)
  int tm_mon;   //Месяц (0-11)
  int tm_year;  //Год (календарный год минус 1900)
  int tm_wday;  //День недели (0-6; Воскресенье = 0) 
  int tm_yday;  //День года (0-365)
  int tm_isdst; 
  //0, если переход на летнее время не используется
  };
  time_t t;
  struct tm *gmt, *area;
  t = time(NULL);
  //Преобразует дату и время в структуру
  area=localtime(t); 
  printf("Секунды: %d\n", area->tm_sec);
  printf("Минуты: %d\n", area->tm_min);
  printf("Часы: %d\n", area->tm_hour);
  printf("День: %d\n", area->tm_mday);
  printf("Месяц: %d\n", area->tm_mon);
  printf("Год: %d\n", area->tm_year);
  printf("День недели: %d\n", area->tm_wday);
  printf("День года: %d\n", area->tm_yday);
  printf("Местное время: %s", asctime(area));
  //Преобразуем структуру в строку
  gmt=gmtime(t);
  //Преобразует дату и время во время по Гривинчу
  printf("Время по Гринвичу: %s", asctime(gmt));
  system("pause");
  return 0;
}

Структуры и функции

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

Например:

//Определение структурного типа
struct person {
               char *name; 
               int age;
              };
  • Функция может возвращать структуру как результат:
    //Прототип функции
    struct person f (int N);
  • Функция может возвращать указатель на структуру:
    //Прототип функции
    struct person *ff (void);
  • Параметром функции может быть структура:
    //Прототип функции
    void fff (struct person str);
  • Параметром функции может быть указатель на объект структурного типа:
    //Прототип функции
    void ffff (struct person *pst);
  • При вызове функции fff() выделяется память для формального параметра, т.е. для вспомогательного объекта типа struct person. В этот объект переносится значение фактического параметра, заменяющего формальный параметр – структуру str. Далее выполняются действия, предусмотренные операторами тела функции fff(). Эти действия не могут изменять структуру, использованную в качестве фактического параметра.

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

    Если функция не изменяет структуру, то такую структуру можно передать по значению.

    Пример 4. Отображение полей структуры на экране.

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
      struct book {
        char title[40];
        char authors[30];
        char publishing_house[25];
        int year;
        int pages;
        };
    void show_book(book b) { 
      cout << "Название: "<< b.title<<"\n";
      cout << "Автор: "<< b.authors<<"\n";
      cout << "издательство: "<< b. publishing_house<<"\n";
      cout << "Год: "<< b.year<<"\n";
      cout << "Количество страниц: " << b.pages<<"\n";
    }
    
    int _tmain(int argc, _TCHAR* argv[]) {
      book a={"Программирование на языке Си", "Подбельский В.В.",
              "Финансы и статистика", 2004, 600};
      show_book(a);
      system("pause");
      return 0;
    }

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

    Пример 5. Параметр функции – указатель на структуру.

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
      struct book {
        char title[40];
        char authors[30];
        char publishing_house[15];
        int year;
        int pages;
       };
    void input_book(book *b){ //структура передается по указателю
      cout << "Название: ";
      cin >> b->title;
      cout << "Автор: ";
      cin >> b->authors;
      cout << "Издательство: ";
      cin >> b->publishing_house;
      cout << "Год: ";
      cin >> b->year;
      cout << "Количество страниц: ";
      cin >> b->pages;
    }
    
    int _tmain(int argc, _TCHAR* argv[]) {
      book a,*pa=a;
      input_book(pa);
      system("pause");
      return 0;
    }

    Пример 6. Параметр функции – ссылка на структуру.

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
      struct book {
        char title[40];
        char authors[30];
        char publishing_house[15];
        int year;
        int pages;
      };
    void input_book(book b) { //структура передается по ссылке
      cout << "Название: ";
      cin >> b.title;
      cout << "Автор: ";
      cin >> b.authors;
      cout << "Издательство: ";
      cin >> b.publishing_house;
      cout << "Год: ";
      cin >> b.year;
      cout << "Количество страниц: ";
      cin >> b.pages;
    }
    
    int _tmain(int argc, _TCHAR* argv[]) {
      book a;
      input_book(a);
      system("pause");
      return 0;
    }

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

    Пример 7. Функции g1, g2 и g3 возвращают структуру.

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    
    struct ss {
               int a; 
               float b; 
              };
    ss g1(ss v){ //параметр - значение
      v.a=7; 
      v.b=8; 
      return v; 
    }
    ss g2(ss v){ //параметр - ссылка
      v.a=v.b+7; 
      v.b=v.a+8; 
      return v; 
    }
    ss g3(const ss v){ //параметр - константная ссылка
      ss q;
      q.a=v.b+7; 
      q.b=v.a+8; 
      return q;
    }
    
    int _tmain(int argc, _TCHAR* argv[]) {
      ss x1,y1={1,2};
      ss x2,y2={3,4};
      ss x3,y3={5,6};
      x1=g1(y1);
      cout << "x1=" << x1.a << "; " << x1.b << "\n";
      cout << "y1=" << y1.a << "; " << y1.b << "\n";
      y1=g1(y1);
      cout << "x1=" << x1.a << "; " << x1.b << "\n";
      cout << "y1=" << y1.a << "; " << y1.b << "\n";
      x2=g2(y2);
      cout << "x2=" << x2.a << "; " << x2.b << "\n";
      cout << "y2=" << y2.a << "; " << y2.b << "\n";
      x3=g3(y3);
      cout << "x3=" << x3.a << "; " << x3.b << "\n";
      cout << "y3=" << y3.a << "; " << y3.b << "\n";
      y3=g3(y3);
      cout << "x3=" << x3.a << "; " << x3.b << "\n";
      cout << "y3=" << y3.a << "; " << y3.b << "\n";
      system("pause");
      return 0;
    }

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

    Значение указателя на структуру – адрес расположения элементов структуры.

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

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

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

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

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

  • В языке С++ определены указатели на структуры.
  • В качестве инициализирующего значения указателя на структуру применяется адрес определяемого структурного объекта.
  • При определении структуры запрещено указание в качестве элемента самого себя.
  • Элементом структуры может быть указатель на определяемую или другую структуру.
  • Указатель на структуру обеспечивает доступ к ее элементам двумя способами: прямым и косвенным.
  • Операции над указателями на структуры не отличаются от операций над другими указателями на данные. Исключение составляет операция "стрелка" ( -> ).
  • Структура может использоваться как параметр и значение функции.
  • Взаимодействие структуры и функции может быть организовано через указатель или ссылку.
  • Лабораторная работа 16. Структуры и указатели.

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

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

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

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

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

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

  • Разработайте структуру, содержащую сведения о результатах ЕГЭ по предмету: Фамилия, Имя, Отчество, Число баллов по первому предмету, Число баллов по второму предмету, Число баллов по третьему предмету. Разработайте функцию, определяющую результат поступления абитуриента по заданному проходному баллу. Введите сведения об N абитуриентах и выведите результаты зачисления по образцу (данные, введенные пользователем, выделены жирным шрифтом):
    Введите проходной балл на специальность: 255
    Введите количество абитуриентов: 5
    
    Сведения о 1 абитуриенте
    Фамилия: Петров
    Имя: Федор
    Отчество: Степанович
    Число баллов по первому предмету: 84
    Число баллов по второму предмету: 76
    Число баллов по третьему предмету: 95
    Результат: зачислен
    ...
  • Разработайте структуру, описывающую комплексное число. Разработайте функции, выполняющие с комплексными числами четыре арифметические операции (+, -, *, /). Введите два комплексных числа и знак операции. Выведите результат.
  • Разработайте структуры, определяющие положение точки в декартовой и полярной системе координат. Опишите функцию, преобразующую координаты точки на плоскости из полярных в декартовы. Введите точку в полярных координатах, преобразуйте координаты в декартовы.
  • Указания к выполнению работы.

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

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

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

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

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

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