Инициализация полей структуры может осуществляться двумя способами:
· присвоение значений элементам структуры в процессе объявления переменной, относящейся к типу структуры;
· присвоение начальных значений элементам структуры с использованием функций ввода-вывода (например, printf() и scanf()).
В первом способе инициализация осуществляется по следующей форме:
struct Имя Структуры Имя Переменной={ЗначениеЭлемента1, Значение Элемента_2,..., Значение Элементаn};
Пример
struct datebd={8,"июня", 1978};
Имя элемента структуры является составным. Для обращения к элементу структуры нужно указать имя структуры и имя самого элемента. Они разделяются точкой:
Имя Переменной. Имя Элемента Структуры
printf("%d %s %d",bd.day, bd.month, bd.year);
Второй способ инициализации объектов языка Си с использованием функций ввода-вывода.
Пример
#include <stdio.h>
#include <stdlib.h>
struct date
{
int day;
char *month;
int year;
};
struct persone
{
char firstname[20];
char lastname[20];
struct date bd;
};
int main()
{
system("chcp 1251");
system("cls");
struct persone p;
printf("Введитеимя: ");
scanf("%s",p.firstname);
printf("Введитефамилию: ");
scanf("%s",p.lastname);
printf("Введите дату рождения\nЧисло: ");
scanf("%d",&p.bd.day);
printf("Месяц: ");
scanf("%s",p.bd.month);
printf("Год: ");
scanf("%d",&p.bd.year);
printf("\nВы ввели: %s %s, дата рождения %d %s %d года",
p.firstname, p.lastname, p.bd.day, p.bd.month, p.bd.year);
getchar(); getchar();
return 0;
}
Результат работы
Имя структурной переменной может быть указано при объявлении структуры. В этом случае оно размещается после закрывающей фигурной скобки }. Область видимости такой структурной переменной будет определяться местом описания структуры.
struct complex_type // имя структуры
{
double real;
double imag;
} number; // имя структурной переменной
Поля приведенной структурной переменной: number.real, number.imag.
Объединения
Объединениями называют сложный тип данных, позволяющий размещать в одном и том же месте оперативной памяти данные различных типов.
Размер оперативной памяти, требуемый для хранения объединений, определяется размером памяти, необходимым для размещения данных того типа, который требует максимального количества байт.
Когда используется элемент меньшей длины, чем наиболее длинный элемент объединения, то этот элемент использует только часть отведенной памяти. Все элементы объединения хранятся в одной и той же области памяти, начиная с одного адреса.
Общая форма объявления объединения
union Имя Объединения
{
тип Имя Объекта 1;
тип Имя Объекта 2;
...
тип Имя Объектаn;
};
Объединения применяются для следующих целей:
· для инициализации объекта, если в каждый момент времени только один из многих объектов является активным;
· для интерпретации представления одного типа данных в виде другого типа.
Пример Поменять местами два младших байта во введенном числе
#include <stdio.h>
#include <stdlib.h>
int main()
{
char temp;
system("chcp 1251");
system("cls");
union
{
unsigned char p[2];
unsigned int t;
} type;
printf("Введите число: ");
scanf("%d", &type.t);
printf("%d = %x шестн.\n",type.t, type.t);
// Замена байтов
temp = type.p[0];
type.p[0] = type.p[1];
type.p[1] = temp;
printf("Поменяли местами байты, получили\n");
printf("%d = %x шестн.\n",type.t, type.t);
getchar(); getchar();
return 0;
}
Результат выполнения
Битовые поля
Используя структуры, можно упаковать целочисленные компоненты еще более плотно, чем это было сделано с использованием массива.
Набор разрядов целого числа можно разбить на битовые поля, каждое из которых выделяется для определенной переменной. При работе с битовыми полями количество битов, выделяемое для хранения каждого поля отделяется от имени двоеточием
Тип имя: Количество Бит
При работе с битовыми полями нужно внимательно следить за тем, чтобы значение переменной не потребовало памяти больше, чем под неё выделено.
Пример Разработать программу, осуществляющую упаковку даты в формат
#include <stdio.h>
#include <stdlib.h>
#define YEAR0 1980
struct date
{
unsigned short day:5;
unsigned short month:4;
unsigned short year:7;
};
int main()
{
struct date today;
system("chcp 1251");
system("cls");
today.day =16;
today.month = 12;
today.year = 2013 - YEAR0; //today.year = 33
printf("\n Сегодня %u.%u.%u \n", today.day, today.month, today.year+YEAR0);
printf("\n Размерструктуры today: %d байт", sizeof(today));
printf("\n Значениеэлемента today = %hu = %hx шестн.", today, today)
getchar();
return 0;
}
Результат выполнения
Массивы структур
Работа с массивами структур аналогична работе со статическими массивами других типов данных.
Пример Библиотека из 3 книг
#include <stdio.h>
#include <stdlib.h>
struct book
{
char title [15];
char author [15];
int value;
};
int main()
{
struct book libry[3];
int i;
system("chcp 1251");
system("cls");
for(i=0;i<3;i++)
{
printf("Введите название %d книги:",i+1);
gets(libry[i].title);
printf("Введитеавтора %d книги: ",i+1);
gets(libry[i].author);
printf("Введитецену %d книги: ",i+1);
scanf("%d",&libry[i].value);
getchar();
}
for(i=0;i<3;i++)
{
printf("\n %d. %s ", i+1,libry[i].author);
printf("%s %d",libry[i].title,libry[i].value);
}
getchar();
return 0;
}
Результат выполнения
Директивы препроцессора в Си
Препроцессор — это специальная программа, являющаяся частью компилятора языка Си. Она предназначена для предварительной обработки текста программы. Препроцессор позволяет включать в текст программы файлы и вводить макроопределения.
Работа препроцессора осуществляется с помощью специальных директив (указаний). Они отмечаются знаком решетка #. По окончании строк, обозначающих директивы в языке Си, точку с запятой можно не ставить.
Основные директивы препроцессора
#include — вставляет текст из указанного файла
#define — задаёт макроопределение (макрос) или символическую константу
#undef — отменяет предыдущее определение
#if — осуществляет условную компиляцию при истинности константного выражения
#ifdef — осуществляет условную компиляцию при определённости символической константы
#ifndef — осуществляет условную компиляцию при неопределённости символической константы
#else — ветка условной компиляции при ложности выражения
#elif — ветка условной компиляции, образуемая слиянием else и if
#endif — конец ветки условной компиляции
#line — препроцессор изменяет номер текущей строки и имя компилируемого файла
#error — выдача диагностического сообщения
#pragma — действие, зависящее от конкретной реализации компилятора.
Директива #include
Директива #include позволяет включать в текст программы указанный файл. Если файл является стандартной библиотекой и находится в папке компилятора, он заключается в угловые скобки. Если файл находится в текущем каталоге проекта, он указывается в кавычках. Для файла, находящегося в другом каталоге необходимо в кавычках указать полный путь.
#include <stdio.h>
#include "func.c"
Директива #define
Директива #define позволяет вводить в текст программы константы и макроопределения.
Общая форма записи