Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Обращение к полям структуры и оператор «точка»

Поиск

Тема 12. СТРУКТУРЫ

Зачем нужны структуры?

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

Предположим, что перед нами стоит задача реализовать базу данных, предназначенную для работы с информацией о сотрудниках некоторой фирмы. С каждым сотрудником связан набор разнотипных данных, таких как имя (name), возраст (age), зарплата (salary) и др. Чтобы решить эту задачу, можно описать несколько массивов, каждый из которых будет отвечать за свою характеристику сотрудника:

 

char name[][20];

float salary[];

int age[];

 

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

 

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

 

Создание структуры

 

Рассмотрим, как описать структуру для представления сотрудника:

 

struct Worker {

stirng name;

float salary;

int age;

};

 

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

 

Worker director;

 

При описании также можно задать значения полей структуры, перечислив эти значения в том порядке, который указан при описании структуры:

 

Worker director = {"Андрей", 34, 1000.6};

 

Заметим, что при описании структуры Worker память под нее не выделяется; это происходит только при описании переменной director типа Worker, которая занимает столько места, сколько ее поля все вместе. Проверим это с помощью оператора sizeof:

 

cout << "Тип\tРазмер\n");

cout << "----------------------\n";

cout << 20*sizeof(char) << endl;

cout << sizeof(int) << endl;

cout << sizeof(float) << endl;

cout << "----------------------\n");

cout << sizeof(Worker) << endl;

 

Строка длины 20 занимает 20 байт; целое и вещественное числа занимают по 4 байта; итого получается 28 байт:

 

 

Обратите внимание на то, что во избежание путаницы имена структур следует начинать с заглавной буквы, а имена переменных – со строчной. Такое соглашение позволяет к тому же объявлять переменные и структуры с «почти» одинаковыми именами, поскольку язык Си различает регистр букв:

 

Worker worker;

 

Обращение к полям структуры и оператор «точка»

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

 

Worker manager;

 

manager.name = "Сергей";

manager.salary = 1000.55;

manager.age = 33;

 

Обратите внимание на то, что поля manager.salary и manager.age являются обычными переменными, и работать с ними нужно, как с переменными. Поле manager.name является строкой.

 

Вложенные структуры

Пусть для каждого сотрудника требуется хранить его адрес, который состоит из нескольких полей: улица (street), номер дома (house) и номер квартиры (flat). В таком случае адрес разумно также представить в виде структуры

 

struct Address {

char street[50];

int house;

int flat;

};

 

и одним из полей структуры Worker сделать структуру Address

 

struct Worker {

char name[20];

int age;

float salary;

Address address;

};

 

Обращение к полям вложенной структуры Address происходит через поля структуры Worker; например, задать адрес сотрудника и вывести его на экран можно так:

 

strcpy(manager.address.street, "Ленина");

manager.address.house = 10;

manager.address.flat = 7;

 

printf("Улица: %s\n", manager.address.street);

printf("Дом: %d\n", manager.addrress.house);

printf("Квартира: %d\n",manager.address.flat);

 

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

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

 

#define SIZE 5

Worker workers[SIZE];

 

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

 

Worker workers[SIZE] = {

{"Андрей", 30, 5000},

{"Светлана", 51, 2000},

{"Дмитрий", 45, 3000},

{"Анна", 28, 4000},

{"Василий", 37, 1000}

};

 

а можно и после объявления:

 

strcpy(workers[0].name, "Игорь");

workers[0].age = 53;

workers[0].salary = 2500;

 

strcpy(workers[1].name, "Демьян");

workers[1].age = 57;

workers[1].salary = 1500;

 

Причем грамотная группировка элементов выглядит именно так, как показано выше, а не так:

 

//Неправильная группировка!

strcpy(workers[0].name, "Игорь");

strcpy(workers[1].name, "Демьян");

 

workers[0].age = 53;

workers[1].age = 57;

 

workers[0].salary = 2500;

workers[1].salary = 1500;

 

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

 

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

Алгоритмы сортировки применимы к любым объектам, в том числе и к структурам. Рассмотрим особенности, которые нужно учитывать при сортировке массива структур.

Во-первых, структуры сортируются по какому-то полю, поэтому сравнение нужно указывать это поле:

 

if (workers[j] .age < workers[j+1] .age) {

}

 

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

 

Worker temp = workers[j];

workers[j] = workers[j+1];

workers[j+1] = temp;

 

Алгоритм пузырьковой сортировки массива структур выглядит следующим образом:

 

for (int i=1; i<SIZE; i++) {

for (int j=SIZE-2; j>=0; j--) {

if (workers[j].age < workers[j+1].age) {

worker temp = workers[j];

workers[j]=workers[j+1];

workers[j+1]=temp;

}

}

}

 

Результат сортировки по возрасту:

 

 

Примеры решения задач

Задача 1. Объявите структуру Vector (Вектор) с вещественными полями x, y и z, которые задают координаты этого вектора в трёхмерном пространстве. Создайте функцию, которая принимает два аргумента типа Vector и возвращает их скалярное произведение.

 

#include <iostream>

using namespace std;

struct Vector { float x; float y; float z; };

float getScalarProduct(Vector v1, Vector v2) {

return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;

}

int main() {

Vector vect1 = {12.3, 45.3, 2.3};

Vector vect2 = {11.2, 35.2, 17.8};

cout << getScalarProduct(vect1, vect2) << endl;

return 0;

}

 

Задача 2. Объявите структуру Point (Точка) с вещественными полями x и y, которые задают её координаты на плоскости. Объявить также структуру Circle (Окружность) с полем center типа Point, которое задает координаты центра этой окружности, и вещественным полем radius, определяющим её радиус. Создайте функцию, которая принимает в качестве аргументов окружность и точку, а возвращает true, если точка находится внутри окружности, и false – иначе.

 

#include <iostream>

using namespace std;

struct Point { float x; float y; };

struct Circle { Point center; float radius; };

float getDistance(Point p1, Point p2) {

return sqrt((p1.x-p2.x)*(p1.x-p2.x) +

(p1.y-p2.y)*(p1.y-p2.y));

}

bool isInside(Point p, Circle c) {

float dist = getDistance(p, c.center);

return dist < c.radius;

}

int main() {

Circle circle;

circle.center.x = 12.3;

circle.center.y = 10.1;

circle.radius = 7.8;

Point point;

point.x = 15;

point.y = 11;

IsInside(point, circle)?

cout << "Внутри\n": cout << "Снаружи\n";

return 0;

}

Задача 3. Объявите структуру «Книга», имеющую 5 полей: название, автор, тираж, количество страниц и цена. Задайте в коде программы массив из структур и выведите их в виде таблицы.

 

#include <iostream>

using namespace std;

struct Book {

char name[100];

char author[100];

int nCopies;

int nPages;

float price;

};

Book books[] = {

{"Пиковая дама", "Пушкин", 10000, 70, 300},

{"Идиот", "Достоевский", 20000, 490, 600},

{"Мастер и Маргарита", "Булгаков", 40000,340,500},

{"Совершенный код", "Макконнел", 4000,800, 900},

{"Криптография", "Смарт", 3000, 400, 550}

};

int main() {

setlocale(LC_ALL, "Russian");

printf("%-20s %-12s %-7s %-5s %-5s\n",

"Название", "Автор", "Тираж", "Стр.", "Цена");

printf("------------------------------------\n");

for (int i=0; i<5; i++) {

printf("%-20s %-12s %-7d %-5d %-5.2f\n",

books[i].name, books[i].author,

books[i].nCopies, books[i].nPages,

books[i].price);

}

printf("------------------------------------\n");

return 0;

}

 

Задача 4. На основе предыдущей программы реализовать меню из следующих пунктов: 1 – Вывод массива в виде таблицы, 2 – Сортировка массива по второму полю, 3 – Сортировка массива по третьему полю, 4 – Запись содержимого массива в файл, 0 – Выход. Каждый пункт меню реализовать в виде отдельной функции.

 

#include <iostream>

using namespace std;

struct Book {

char name[100];

char author[100];

int nCopies;

int nPages;

float price;

};

const int n=5;

Book books[n] = {

{"Пиковая дама", "Пушкин", 10000, 70, 300},

{"Идиот", "Достоевский", 20000, 490, 600},

{"Мастер и Маргарита", "Булгаков", 40000, 340, 500},

{"Совершенный код", "Макконнел", 4000, 800, 900},

{"Криптография", "Смарт", 3000, 400, 550}

};

void printBooks() {

printf("%-25s %-15s %-7s %-10s %-10s\n", "Название",

"Автор", "Тираж", "Страниц", "Цена");

for (int i=0; i<5; i++) {

printf("%-25s %-15s %-7d %-10d %-10.2f\n",

books[i].name, books[i].author,

books[i].nCopies, books[i].nPages,

books[i].price);

}

}

#define NAME 1

#define AUTHOR 2

#define N_COPIES 3

#define N_PAGES 4

#define PRICE 5

bool isGreater(Book b1, Book b2, int field) {

switch(field) {

case NAME: return strcmp(b1.name, b2.name) > 0;

case AUTHOR: return strcmp(b1.author, b2.author) > 0;

case N_COPIES: return b1.nCopies > b2.nCopies;

case N_PAGES: return b1.nPages > b2.nPages;

case PRICE: return b1.price > b2.price;

default: return true;

}

}

void sortBooks(int field) {

for (int i=0; i<n-1; i++) {

int max = i;

for (int j=i+1; j<n; j++) {

if (isGreater(books[max], books[j], field)) {

max = j;

}

}

Book temp = books[max];

books[max] = books[i];

books[i] = temp;

}

}

void intoFile() {

FILE* dataFile = fopen("books.txt", "w");

for (int i=0; i<5; i++) {

fprintf(dataFile, "%s\n%s\n%d\n%d\n%f\n",

books[i].name, books[i].author, books[i].nCopies,

books[i].nPages, books[i].price);

}

fclose(dataFile);

}

int main() {

setlocale(LC_ALL, "Russian");

while (true) {

system("cls");

printf("1 - Вывод всех книг\n");

printf("2 - Сортировка по названию\n");

printf("3 - Сортировка по автору\n");

printf("4 - Сортировка по тиражу\n");

printf("5 - Сортировка по числу страниц\n");

printf("6 - Сортировка по цене\n");

printf("7 - Запись в файл\n");

printf("0 - Выход\n");

int choice;

cin >> choice;

switch (choice) {

case 1: printBooks();break;

case 2: sortBooks(NAME);break;

case 3: sortBooks(AUTHOR);break;

case 4: sortBooks(N_COPIES);break;

case 5: sortBooks(N_PAGES);break;

case 6: sortBooks(PRICE);break;

case 7: intoFile();break;

case 0: exit(EXIT_SUCCESS);break;

default: printf("Ошибка\n");

}

system("pause");

}

return 0;

}

 

КОНТРОЛЬНЫЕ ВОПРОСЫ

  1. Зачем нужны структуры?
  2. Как определить новую структуру и объявить переменные-структуры?
  3. Как инициализировать структуру?
  4. Как объявить массив структур?
  5. Что такое поле структуры и как к ним обращаться?
  6. Что такое вложенные структуры?
  7. Как вывести содержимое массива структур в виде таблицы?
  8. Можно ли передавать структуры в качестве аргументов функций и возвращать структуры в качестве значений функций?

 

Тема 12. СТРУКТУРЫ

Зачем нужны структуры?

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

Предположим, что перед нами стоит задача реализовать базу данных, предназначенную для работы с информацией о сотрудниках некоторой фирмы. С каждым сотрудником связан набор разнотипных данных, таких как имя (name), возраст (age), зарплата (salary) и др. Чтобы решить эту задачу, можно описать несколько массивов, каждый из которых будет отвечать за свою характеристику сотрудника:

 

char name[][20];

float salary[];

int age[];

 

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

 

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

 

Создание структуры

 

Рассмотрим, как описать структуру для представления сотрудника:

 

struct Worker {

stirng name;

float salary;

int age;

};

 

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

 

Worker director;

 

При описании также можно задать значения полей структуры, перечислив эти значения в том порядке, который указан при описании структуры:

 

Worker director = {"Андрей", 34, 1000.6};

 

Заметим, что при описании структуры Worker память под нее не выделяется; это происходит только при описании переменной director типа Worker, которая занимает столько места, сколько ее поля все вместе. Проверим это с помощью оператора sizeof:

 

cout << "Тип\tРазмер\n");

cout << "----------------------\n";

cout << 20*sizeof(char) << endl;

cout << sizeof(int) << endl;

cout << sizeof(float) << endl;

cout << "----------------------\n");

cout << sizeof(Worker) << endl;

 

Строка длины 20 занимает 20 байт; целое и вещественное числа занимают по 4 байта; итого получается 28 байт:

 

 

Обратите внимание на то, что во избежание путаницы имена структур следует начинать с заглавной буквы, а имена переменных – со строчной. Такое соглашение позволяет к тому же объявлять переменные и структуры с «почти» одинаковыми именами, поскольку язык Си различает регистр букв:

 

Worker worker;

 

Обращение к полям структуры и оператор «точка»

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

 

Worker manager;

 

manager.name = "Сергей";

manager.salary = 1000.55;

manager.age = 33;

 

Обратите внимание на то, что поля manager.salary и manager.age являются обычными переменными, и работать с ними нужно, как с переменными. Поле manager.name является строкой.

 



Поделиться:


Последнее изменение этой страницы: 2016-04-23; просмотров: 1754; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 52.14.7.53 (0.011 с.)