Структурные типы данных в си. Обращение к полю структурной переменной. Структура и функции
Пока мы рассматривали одну сложную структуру (сложный тип) - массив; одним из основных свойств массива является однотипность его компонент. Многие информационно-логические задачи связаны с обработкой документов, содержащих в себе информация разного типа (числовую, символьную и т. д.) Примеры таких документов: платежные ведомости (фамилии и имена - символьная информация, денежные суммы - числовая), карточки больных в поликлинике, библиотечная информация. Для программирования алгоритмов обработки такой информации необходимо иметь сложный тип, объединяющий разнотипные компоненты. Таким типом является структура в Си (в Паскале запись).
Структурная переменная, или просто структура, состоит из нескольких переменных (называемых полями), возможно, разного типа.
Структура
тип "структура" (шаблон) |
переменная типа "структура " |
Описание шаблона : |
Описание структурной переменной |
typedef struct { Тип1 Список1ИменПолей; |
struct ИмяШаблона ИмяПеременной |
Тип2 Список2ИменПолей; | |
ТипN СписокNИменПолей; |
ключевое struct слово не нужно пpи |
} ИмяШаблона |
использовании typedef |
или struct ИмяШаблона | |
{ Тип1 Список1ИменПолей;¦ | |
Тип2 Список2ИменПолей; | |
ТипN СписокNИменПолей; | |
typedef struct {char author; char title;/*описание*/
int year; float price} BOOK; /*шаблона BOOK*/
/*или можно описать тот же самый шаблон так:
struct BOOK {char author; char title;
int year; float price} ;*/
struct BOOK b;/*описание структурной переменной b*/
Память, занимаемая структурой, равна сумме объемов памяти полей (если исключить из рассмотрения особенности, связанные с выравниванием). В любом случае для определения размера памяти структуры можно использовать операцию sizeof(). Шаблон ВООК, например, описывает структуру размером памяти 70.
Обращение к полю структурной переменной:
ИмяСтруктуры.ИмяПоля или АдресСтруктуры ->ИмяПоля
. (точка) и ->являются операциями, соответственно, прямого и косвенного выбора компоненты структурированной переменной.
Например,
struct BOOK a,*pnta=&a;...
a.author="Byron"; pnta->author="Byron"; /*эквивалентные операторы*/
Пример. Задача примера 2 п.3.1.4 в нижеприведенной программе выполнена с использованием структур (а не строк).
#include
#include
#include
{ /*структура сведений об игрушках*/
typedef struct {int nu;/*номер*/
char name;/*наименование*/
int minage,maxage;/*мин. и макс. возраст ребенка*/
double rub /*стоимость*/;}TOYS;
TOYS toy;/*переменная типа записьTOYS */
double max; /*максимальная стоимость*/
char namemax;/*название самого дорогого конструктора*/
int n /*число игрушек*/,i/*номер игрушки*/;
puts("Введите число наименований игpушек");
for (i=0;
i /*в
цикле ввод сведений об игрушках и
проверка условий*/ fflush(stdin); /*очистка буфера
устройства ввода послеscanf
*/ printf("
Введите сведения об игpушке с номеpом
%2d\n",toy.nu); puts("наименование"); puts("мин. и макс. возpаст и стоимость"); scanf("%d%d%lf",&toy.minage,&toy.maxage,&toy.rub); if
((strstr(toy.name,"констpуктоp")!=NULL || strstr(toy.name,"Констpуктоp")!=NULL) && (toy.maxage <= 7) && (toy.rub>max)) strcpy(namemax,toy.name); puts(" Констpуктоpов для детей до семи
лет нет"); {
printf("Cамый доpогой констpуктоp для
детей до семи лет\n"); printf(" %s стоит %8.0f pублей\n",namemax,max); В Си существует еще один сложный тип,
описание которого формально похоже на
структуру. Это тип (и переменная)
объединение
. Объединение - это переменная, содержащая
поля разного типа, помещаемые в одно и
то же место памяти. По существу объединение
дает способ различной интерпретация
содержимого памяти. Описание шаблона
(типа) объединения и переменной этого
типа выполняется также, как для структуры,
только вместо ключевого слова struct
используетсяunion
. Размер памяти,
занимаемой объединением, равен
максимальному из размеров полей. Структура в Си - тип данных, предназначенный для размещения значения разного типа в одном объекте. Полезен, когда необходимо объединить несколько переменных с разными типами под одним именем. Делают программу более компактной, ею удобней управлять. Структура имеет схожие особенности с массивами и классами. Прежде чем говорить о структуре в Си, нужно описать массив. Существуют массивы одномерные, двумерные, трехмерные. Одномерный - это такой, у которого есть только одна строка с заполненными значениями. Двумерный - одномерный массив, внутри которого находятся другие одномерные массивы. Обычный массив в Си записывается так: int a = {1, 2, 3, 4}. Видим, что a - имя, int - тип данных, внутри фигурных скобок { } находятся значения, между квадратными скобками указывается длина, то есть количество элементов. Количество элементов является статическим, равняется 4. Это означает, что если в этом примере пользователь добавит пятое значение, компилятор выдаст ошибку. Если изначально не известно количество, они могут быть добавлены позже, но в квадратных скобках не ставится значение. Двумерный объявляется похожим образом. Например, массив, который содержит 5 элементов-массивов, при этом каждый содержит по 3 элемента объявляется так: int a.По аналогии с одномерным добавлять ничего нельзя, чтобы не получить ошибку компилирования. Различают динамические и статические. Статический - это такой, который вмещает фиксированное количество данных, то есть имеет постоянную длину. Под динамическим понимается тот, размер которого не ограничивается, он может меняться во время выполнения программы. Инициализация динамического массива происходит без указания точного количества. Класс и структура похожи по между собой, но отличаются некоторыми нюансами. Что это такое? Это абстракция, описывающая методы еще не существующего объекта. После создания объект или, как он называется по-другому, экземпляр класса имеет конкретные свойства. Методы могут использоваться внутри, снаружи или при наследовании. Класс объявляется так: class /*class name*/ /* спецификатор доступа private обозначает, что управление методами возможно только внутри класса*/ /* делает свойства доступными для других частей кода */ /* наследуемые классы получают возможность использовать эти свойства */ Предназначена для хранения несколько типов данных. Например, чтобы создать каталог журналов, нужно иметь список с такими параметрами: Для решения этой задачи можно было бы применить массивы. Объявляем массив с датами int date, номерами int number, названиями char title, стоимостью int price. Обращаясь по индексу, мы получаем требуемую информацию. Вывод информации о произведении под номером 3 выглядит так: cout << “дата выпуска: ” date “, номер: ” number “, название: ” title “, стоимость: “ price). Структура упрощает запись, описывается следующим образом: Видим одно из главных преимуществ - присутствуют разные типы переменных. Программист не просто экономит время - он упрощает код, в дальнейшем ему будет намного проще работать. Структуры в Си играют очень важную роль - объединение данных различного типа. Для начала нужно указать имя структуры и свойства. Struct - ключевое слово, оно начинает объявление, name - имя, type - тип данных, member - имя элемента. Объявляется так: name name2, где name - заданное при создании структуры имя, а name2 - имя переменной. Объявить переменные можно на этапе создания. Первый и второй пример равносильны друг другу. Если есть необходимость объявить несколько переменных, они перечисляются через запятую. } name2, name3, name4. После объявления структуру в Си необходимо инициализировать. name2.member=”a”; Инициазация может происходить при создании. char member = “a”; У структуры такой же синтаксис, как у класса. У них практически одинаковое поведение, возможности. Все, что находится в теле класса, по умолчанию недоступно для использования другими объектами. У структуры все наоборот - все поля и методы являются публичными. Вручную можно задать модификатор доступа private и таким образом открыть доступ другим функциям или классам. Массивы - это множество компонентов одного типа. Они располагаются рядом с друг другом, обращение к каждому из них осуществляется по числовому индексу. Существуют одномерные массивы, двумерные, трехмерные. У одномерного только одна строка и n-e количество элементов. Объявление выглядит так: Массив структур в Си объявляется так: В этом примере мы создали MyStruct с элементом целочисленного типа под именем "а". Объявляем переменную obj1 - она является массивом, состоит из 10 элементов. При объявлении нескольких массивов одного типа используется MyStruct obj1, obj2, инициализация происходит во время объявления. Выглядит так: Создание массива структур с динамическим выделением памяти выглядит точно также, как создание простого динамического массива. Для этого применяется указатель на структуру Си. Указатель - это переменная, которая не содержит значения, а указывает на ту переменную, которая имеет какое-то значение. Соответственно, указатель содержит адрес этой переменной, на которую ссылается. Например, ptr = &var1 означает, что переменной со знаком амперсанда присвоен только адрес на переменную, но не само значение. Теперь все значения var1 доступны через переменную-указатель ptr. Операция * отсылает к содержимому ячейки, на которую указывает переменная после этого символа. Например, *ptr говорит о том, что здесь содержатся значения, взятые из ячейки с адресом к ptr. Чтобы выделить память для динамических переменных, используют операцию new. У нас есть Выделяем участок памяти, заносим туда некое значение MyStruct * point = new MyStruct; Для удаления динамических переменных используем операцию delete. Чтобы освободить место, вводим delete p; Все элементы по умолчанию являются публичными, поэтому другие классы их могут использовать. Чтобы задать или изменить некоторые значения, сначала нужно обратиться к элементу и только потом произвести соответствующие действия. Создаем myStruct с именем переменной b. struct myStruct { Обращаемся к fio: и задаем произвольное значение. Например, b.fio = “Ivanov”. Рассмотрим такой пример. struct myStruct { { "Иванов", 456756 }, { "Петров", 632345 } В данном примере у нас есть массив структур со строками и числами. Чтобы вывести на экран фамилию Иванов, используем следующее: cout << myStruct tel.fio; Когда захотим получить значение 456756, выполняем cout << myStruct tel.num. Может использоваться, как аргумент функция в структуре в Си. struct myStruct { Имеем переменную value, строку text на 100 символов. Создаем переменную menu типа myStruct: myStruct menu. В следующем примере функция принимает указатель на структуру как аргумент, а в теле безымянной функции происходит инициализация этих переменных. void item(myStruct menu) sprintf(menu.text,"One item"); Структура - это такой набор, наподобие массива, но при этом все элементы могут быть разного типа. Очень похожа на класс, но отличается тем, что свойства по умолчанию доступны для использования другими классами, то есть имеют спецификатор public. Создается с помощью ключевого слова struct, а внутри фигурных скобок { } указываются свойства. Объявление происходит на этапе создания или после. А теперь только представьте — вы сами можете создавать, своего рода, типы данных, которые вам необходимы и с которыми вам будет удобно работать! И это несложно! Структура — это, некое объединение различных переменных (даже с разными типами данных), которому можно присвоить имя.
Например можно объединить данные об объекте Дом: город (в котором дом находится), улица, количество квартир, интернет(проведен или нет) и т.д. в одной структуре. В общем, можно собрать в одну совокупность данные обо всем, что угодно, точнее обо всем, что необходимо конкретному программисту. Всем сразу стало понятно:) Если вы только приступаете к знакомству со структурами в С++, сначала, вам необходимо ознакомиться с синтаксисом структур в языке С++ . Рассмотрим простой пример, который поможет познакомиться со структурами и покажет, как с ними работать. В этой программе мы создадим структуру, создадим объект структуры, заполним значениями элементы структуры (данные об объекте) и выведем эти значения на экран. Ну что же, приступим!
#include В строках 4 — 10
мы создаем структуру. Чтобы ее объявить используем зарезервированное слово struct и даем ей любое, желательно логичное, имя. В нашем случае — building . С правилами именования переменных, вы можете ознакомиться в этой статье . Далее открываем фигурную скобку { , перечисляем 4 элемента структуры через точку с запятой; , закрываем фигурную скобку } и в завершении ставим точку с запятой; . Это будет нашим шаблоном (формой) структуры. В строке 16
объявляем объект структуры. Как и для обычных переменных, необходимо объявить тип данных. В этом качестве выступит имя нашей созданной структуры — building . Как же заполнить данными (инициализировать) элементы структуры? Синтаксис таков: Имя объекта далее оператор точка. и имя элемента структуры. Например: apartment1.owner . Таким образом, в строках 18-21
присваиваем данные элементам структуры. И так, данные мы внесли. Следующий вопрос: «Как к ним обратиться, как работать и использовать их в программе?» Ответ — «Очень просто — так же, как и при инициализации, используя точку. и имя элемента структуры». В строках 23 — 26
выводим заполненные элементы структуры на экран. И вот что мы увидим в результате, когда скомпилируем нашу программу:
Владелец квартиры: Денис
Квартира находится в городе: Симферополь
Количество комнат: 5
Стоимость: 150000 $ Что ещё важно знать:
но так делают крайне редко; Дополним предыдущий пример, чтобы увидеть дополнительные возможности работы со структурами. Пример:
#include Коментарии по коду программы:
Строка 17
— создание объекта built типа
date в определении структуры building
. Строки 42 — 43
: создаем указатель на структуру struct building *pApartment; и далее присваиваем ему адрес уже созданного и заполненного данными объекта pApartment = &apartment1; . Обращаясь к элементам структуры через указатель мы используем оператор -> (тире и знак >)
. Это видно в
строках 47 — 51.
В строке 62
показано, как можно инициализировать структуру. А именно, можно создать новый объект структуры и присвоить ему одним целым, уже созданный и заполненный данными, объект. В функцию show() передаем объект структуры, как параметр — строка 64.
Результат: Владелец квартиры: Денис Разобрав этот пример, мы увидели на практике следующее: В дополнение ко всему, следует отметить, что функции могут так же возвращать структуры в результате своей работы. Например: Building Set()
{
building object; // формирование объекта
//... код функции
return object;
}
Вот так, вкратце, мы познакомились со структурами в языке С++, попрактиковались на примерах и узнали основы. Это только начало! Тип переменной определяет: её размер в памяти, тип данных, которые она может хранить и операции, которые можно производить с этой переменной. Тип данных является категорией. В языке С++ программист может создать любой тип данных на основе базовых типов. Новые типы данных необходимо создавать для решения конкретных практических задач. Например: реализация работы деканата. Успех программы часто зависит от удачного выбора способа представления данных. С помощью структур возможно моделировать сложные объекты, возникающие при решении задач. Структуры представляют средство для доступа к записям, которые содержат поля одного или нескольких типов. Для использования структуры необходимо: Шаблон - это схема, описывающая содержание структуры. Установка структурного шаблона телефонный справочник: struct sprav { Данный шаблон описывает структуру с именем типа структуры sprav, состоящую из двух компонентов: строки fio и целой переменной num типа long. Имя типа структуры sprav необязательно и используется для ссылки на эту структуру. Компоненты структуры - данные любого типа, включая и другие структуры. Имя внутри структуры может быть таким же, как имя объекта вне структуры. Если шаблон описан внутри функции - он доступен только этой функции, если шаблон описан вне функции - он доступен любой функции программы. Установка шаблона не вызывает никаких действий в программе. Объявление структурных переменных приводит к выделению памяти для компонент структуры, куда можно записать данные или откуда можно прочитать их. Для объявления структурных переменных имеются несколько способов. 1. Установить структурный шаблон: struct sprav { Объявить простую переменную, массив структур, указатель на структуру: struct sprav tel1, tel2, *tel3;
2. Установить структурный шаблон с помощью макроопределения: #define SPRAV struct sprav Объявить переменные: SPRAV sp1, sp2, *sp3;
3. Объявить переменные одновременно с установкой шаблона (если на данную структуру вы больше не ссылаетесь): struct { 4. Ввести новый тип данных (TEL)-структура определенного вида: typedef struct { Объявить переменные нового типа: TEL tel1, tel2, *tel3; Если программа достаточно объемна, представляется более удобным четвертый способ. Инициализировать можно только внешние или статические структуры. static struct { Доступ к компонентам структуры продемонстрируем с помощью примеров. /* Обращение к элементам структуры через имя переменной */ puts("введите фио абонента-"); /* Динамическое выделение памяти для структуры */ void main(void) clrscr(); /* Массив структур. Обращение к элементам структуры через */ void main(void) SPRAV tel; /* массив структур - 5 элементов */ clrscr(); /* Массив структур. Память выделяется динамически. */ typedef struct{ void main(void) clrscr(); Непосредственный доступ к компонентам структуры - плохой стиль программирования. Все операции, которые разрешены применительно к структуре, должны быть при этом реализованы в виде отдельных функций. Не все компиляторы языка Си позволяют передавать структуры в функцию по значению, поэтому в примерах передача структуры идет через указатель. /* Передача структуры в функцию через указатель на структуру */ #include /* Вычисление суммы двух комплексных чисел */ /* Ввод значений для элементов структуры */ Структура, являющаяся компонентом другой структуры, называется вложенной. /* Даны четыре точки - центры четырех окружностей. Заполнить структуру окружность, если все окружности проходят через начало координат. */ #includeМассивы
Классы
Что такое структура в языке Си
Объявление
Инициализация
Доступ
Структура и функции
Заключение
struct building
{
char *owner
char *city;
int amountRooms;
float price;
}apartment1; //объявление объекта типа building
building apartment1 = {"Денис", "Симферополь", 5, 150000};
Квартира находится в городе: Симферополь
Количество комнат: 5
Стоимость: 150000 $
Дата постройки: январь 2013
Владелец квартиры: Игорь
Квартира находится в городе: Киев
Количество комнат: 4
Стоимость: 300000 $
Дата постройки: январь 2012
Для продолжения нажмите любую клавишу. . .
1. установить шаблон для структуры
2. объявить переменную, соответствующую этому шаблону
3. осуществить доступ к компонентам структуры.Шаблон структуры
char fio;
long num;
};Структурные переменные
char fio;
long num;
};
SPRAV {
char fio;
long num;
};
char fio;
long num;
} tel1, tel2, *tel3;
char fio;
long num;
} TEL;Инициализация структуры
char fio;
long num;
} tel={
"Иванов Ф.А.", 456756,
"Петров В.П.", 632345
};Доступ к компонентам структуры
#include
#include
void main(void)
{
struct{
char fio; /* фамилия */
long num; /* телефон */
} tel1, tel2;
gets(tel1.fio);
puts("введите его номер-");
scanf("%ld",&tel1.num);
tel2=tel1; /* нельзя так же сравнивать структуры */
puts("Введено:");
printf("Фамилия:%s номер: %ld\n",tel2.fio,tel2.num);
}
#include
#include
#include
struct sprav {
char fio;
long num;
};
{
struct sprav *tel1, *tel2;
/* Выделение памяти для структуры */
tel1=(struct sprav *)malloc(sizeof(struct sprav));
tel2=(struct sprav *)malloc(sizeof(struct sprav));
gets(tel1->fio);
puts("введите его номер-");
scanf("%ld",&tel1->num);
*tel2= *tel1;
puts("Введено:");
printf("Фамилия:%s номер: %ld\n",(*tel2).fio,(*tel2).num);
}Массив структур
/* имя элемента массива */
#include
#include
#include
#define SPRAV struct sprav
{
SPRAV{
char fio;
long num;
};
char fio_tek;
int i;
/* ввод данных в массив структур */
for(i=0; i<5; i++)
{
puts("введите фио абонента-");
gets(tel[i].fio);
puts("введите его номер-");
scanf("%ld",&tel[i].num);
getchar();
}
gets(fio_tek);
/* поиск структуры по фамилии абонента */
for(i=0; i<5; i++)
if(!strcmp(fio_tek,tel[i].fio)) break;
if(i!=5) /* цикл закончен по break */
tel[i].num);
else /* цикл выполнился полностью */
puts("Абонент не найден");
}
/* Обращение к элементам структуры через указатель */
#include
#include
#include
#include
char fio;
long num;
} TEL;
{
TEL *tel;
char fio_tek;
int i;
/* Выделение памяти для массива - 3 элемента */
tel=(TEL *)malloc(sizeof(TEL)*3);
for(i=0; i<3; i++)
{
puts("введите фио абонента-");
gets((tel+i)->fio);
puts("введите его номер-");
scanf("%ld",&(tel+i)->num);
getchar();
}
puts("Выбор телефона по фамилии");
gets(fio_tek);
for(i=0; i<5; i++,tel++)
if(!strcmp(fio_tek,tel->fio)) break;
if(i!=5)
printf("номер абонента %s равен %ld\n",fio_tek, \
tel->num);
else
puts("Абонент не найден");
}Передача структуры в функцию
/* Определение комплексного числа через структуру и действия */
/* над комплексными числами (ввод, вывод, вычисление суммы) */
typedef struct { float a; /* действительная часть */
float b; /* мнимая часть */
} COMPLEX;
void vvod(COMPLEX *,float,float);
void sum(COMPLEX *,COMPLEX *,COMPLEX *);
void out(COMPLEX *);
void main(void)
{
COMPLEX x,y,z;
vvod(&x,2.5,6.7);
vvod(&y,6.89,8.45);
puts("Введены числа:");
out(&x);
out(&y);
sum(&x,&y,&z);
puts("Сумма комплексных чисел равна:");
out(&z);
}
/* Вывод комплексного числа */
void out(COMPLEX *p)
{
printf("(%.2f,%.2f)\n", (*p).a,(*p).b);
return;
}
void sum(COMPLEX *p1,COMPLEX *p2,COMPLEX *p3)
{
(*p3).a=(*p1).a+(*p2).a;
(*p3).b=(*p1).b+(*p2).b;
return;
}
void vvod(COMPLEX *p,float a, float b)
{
p->a=a;
p->b=b;
return;
}Вложенные структуры
#include
#include
#include
struct POINT {
float x;
float y;
};
struct CIRCLE {
struct POINT point; /* вложенная структура */
double r;
} circle, *p;
void main (void)
{
int i,j;
float a,b,c,d;
clrscr();
gotoxy(17,1);
cputs("ВВЕДИТЕ КООРДИНАТЫ ТОЧЕК:\r\n");
for(i=0;i<2;i++)
{
cprintf ("\n\n ВВЕДИТЕ X: ");
cprintf ("X[%d]= ",i+1);
cscanf("%f",&circle[i].point.x);
cprintf ("\n ВВЕДИТЕ Y: ");
cprintf ("Y[%d]= ",i+1);
cscanf ("%f",&circle[i].point.y);
}
p=circle;
gotoxy(17,12);
cputs("РЕЗУЛЬТАТ:\r\n\n");
for(i=0;i<2;i++)
{
a=p->point.x;
b=p->point.y;
c=sqrt(a*a+b*b);
p->r=c;
cprintf("\nРАДИУС: %lf ЦЕНТР (%f,%f)\r\n",p->r,a,b);
p++;
}