Массив структур. Правило выравнивания структурных переменных в памяти

Если задан шаблон структуры:

struct student {char name[30];int kurs; char group[8];int stip;};

То можно записать массив:

struct student stud1kur[200];

Доступ к полю kur i-го элемента массива можно осуществить следующим способом:

1.stud1kur[i].kurs=2

2. (*(stud1kur+i)).kurs=2

3.(stud1kur+i)->kurs=2

Выравнивание задаётся опцией среды: Options-Code Generation-Alignment

1.Byte Alignment – выравнивание на границе байта

2.Word Alignment - выравнивание на границе слова

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

Правила выравнивания структурных переменных в памяти :

1) отдельная структурная переменная (элемент массива структур) начинается с четного адреса

2) любое поле ,тип которого не совпадает с типом char, будет начинатся с чётного адреса

3) при необходимости в конце структурной переменной добавляется ещё один байт так, чтобы число байт структурной переменной было чётным.

Переименование типов. Средство typedef.

Средства typedef позволяют давать новые имена или псевдонимы уже существующимии типами.Формат записи :

typedef имя_типа новое_имя_типа;

typedef int Lenght;

Lenght len, maxlen;

typedef char* String;

String p;

int strcmp(String,String);

Обычно средства typedef используют при создании сложных деклараций с использыванием структур.

typedef struct st1{char name[30];

Int kurs;

Char group[8];

Int stip; } STUDENT;

STUDENT stud1, stud2;

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

Преимущества:

Переименование типов. Средство typedef.

1)параметризация программы связаная с проблемой переносимости. Если с помощью средства typedef объявить типы данных, которые машинно зависимые, то при переносе программы на другую машину потребуется внести изменения только в определение typedef.

2)Кратность , наглядность и удобность.

Поля битов.

Язык С допускает использование в структурах полей особого типа – битовых полей (или полей битов). Их использование делает возможным доступ к отдельным битам более крупных объектов. Это позволяет экономнее использовать память. Например : если переменная принимает значения “0” или “1” (флаг), то для ее представления можно использовать 1 бит. Использование групп однобитовых флагов позволяет запаковать несколько объектов в одном машинном слове.

Поле битов – некоторое множество битов, лежащих рядом внутри одной, зависящей от реализации единицы памяти.

Описание поля битов : тип [имя] : ширина;

Тип может быть int, signed, unsigned.

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

Каждому битовому полю выделяеться ровно столько бит, сколько указано в поле “ширина”(от 0 до размера длины слова).

Ссылка на битовое поле выполняется по имени, указанном в поле “имя”. Поля могут не иметь имени. В этом случае организуеться пропуск заданного числа бит. Т.е. биты выделяются, но доступ к ним не возможен. Особая ширина безымянного поля, равная 0, используется когда надо выйти на границу следующего слова. Битовое поле может существовать только как элемент структуры и определяет из скольки бит состоит каждый её элемент.

struct имя_типа_структуры {

тип имя1:ширина1;

тип имя2:ширина2;

……….

тип имяN:ширинаN;};

Длина структуры всегда кратна 8;

struct flag{

unsigned one_bit:1;

unsigned two_bit:1;

unsigned three_bit:1;} obj;

Поэтому под переменную obj будет отведено 8 бит, но использоваться будут только первые 3.

В структуре могут быть смешаны обычные переменные и битовые поля. Ссылка к битовым полям obj. one_bit – доступ к полю.

Над битовыми полями возможны следующие операции:

obj.one_bit= obj.two_bit=1;

Объединения

Объединение – это переменная, которая может содержать в разные моменты времени объекты различных типов и размеров. Фактически объединение – это структура, у которой все её элементы имеют нулевое смещение относительно базового адреса. Размер структуры достаточно велик, чтобы вместить самый большой её элемент, а выравнивание удовлетворяет всем типам объединения. Объединения не могут содержать поля битов. Объявление объединения аналогично объявлению структуры, только вместо слова struct используется union.

union u {

int i;

char c;

long int l;};

union u a,b;

Можно объявить переменные в шаблоне. Переменной типа union выделяется место в памяти (в байтах) ровно столько, сколько нужно для самого большого элемента. Т.е. она будет достаточно большой, чтобы в ней разместились переменные других типов.

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

Помнить о том, какой элемент хранится в объединении, должен программист.

Объединения могут входить в структуры и массивы и наоборот.

struct {

char *name;

int iv;

union {

int i;

float f;

char *s} u;

} sym [nsym];

sym[k].u.i – доступ к полю i объединения u k-того элемента массива структур sym

*sym[k].u.s равносильно sym[k].u.s[o]

Объединения

Инициализировать объединение можно только значением, имеющим тип его первого элемента.

union u {

int i;

char c;

long int l;

} a,b;

a.i=100;

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

Ввод, вывод потока.

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

Так как потоки не зависят от физических устройств, одна и та же функция может выводить информацию на екран и на диск одновременно. Существует 2 типа потока:

1)текстовый поток – последовательность строк, каждая строка имеет 0 или n литер и заканчивается \0 , но операционная среда может потребовать коррекцию текстового потока. Например, пара символов: возврат каретки и перевод строки трактуются как один символ перевода строки при вводе.

2)бинарный поток – последовательность непреобразуемых байтов, которые взаимнооднозначно соответствуют тому, что находится на внешнем устройстве.

Чтобы связать поток с файлом или устройством, его необходимо открыть. Эта связь разрывается посредством закрытия потока.Открытие файла возвращает указатель на обьект типа FILE.

С началом работы автоматически открываются 5 потоков:

stdin – стандартный ввод;

stdout – стандартный вывод;

stderr – стандартный вывод сообщения об ошибках;

stdaux – стандартный дополнительный поток;

stdprn – стандартная печать.

По умолчанию 1-3 относятся к консоли и открываются в текстовом режиме, 4-5 открываются в двоичном режиме.Режим доступа к файлу устанавливается во время его открытия как параметр функции открытия или с помощью спец. переменной _fmode, которая находится в <fctl.h> или <stdlib.h>. fmode может принимать 2 значения: O_BINARY – открывается в двоичном режиме, O_TEXT – в текстовом режиме. По умолчанию устанавливается текстовый режим.

Связующим звеном между файлом и потоком является указатель на файл. Указатель на файл – это указатель на структуру типа FILE, ее шаблон определен в stdio.h. Этот указатель используется для последующей ссылки на поток.

Доступ к файлам через поток ввода/вывода.Открытие потока.Закрытие потока.

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

Указатель на файл - это указатель на структуру типа FILE, шаблон которой содержится в < stdio.h>. Этот указатель используется для последующих ссылок на потоки

FILE* fp-объявление.

Открытие потока.

Функция fopen открывает поток и связывает с ним файл с заданым именем , она возвращает указатель связанный с этим файлом или NULL если попытка открытия неудачна.

Прототип этой функции FILE*fopen(char *filename,char *mode);

char *filename-указатель на строку-имя файла.

char *mode-задает режим открытия файла.

char *mode может принимать следующие значения :

«r»-открыть только для чтения

«w»-создать для записи .

«a»-открыть файл для добавления в конец файла.

«r+»-открыть для исправления (для чтения и записи)

«w+»-создать для исправления (старое содержимое теряется)

«a+»-открыть файл для исправления уже существующей информации и добавления ее в конец.

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

ПР: открытие файла “good”

FILE *fp;

If ((fp = fopen(“good”,”r”))==NULL)

printf(“Can not open file\n”); exit(1);}

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

Функция freopen переназначает указатель потока на другой поток. Прототип этой функции: FILE *freopen (char *filename, char *mode, FILE *stream);

Функция открывает файл в режиме mode и свзывает его с потоком stream. Обычно используют для замены файлов, связанных с <stdin>, <stout>…

Закрытие потока.

Функция fclose закрывает отдельный поток, а fcloseall закрывает все открытые потоки, за исключением стандартных.

int fclose (FILE*fp),

возвращает NULL, в случае успешного закрытия файла и EOF в случае ошибки, при этом все данные из буфера считываются в файл. Если поток не закрыт, то он закрывается автоматически по окончании программы. Одновременно можно иметь до 20 открытых потоков.

Функция remove уничтожает заданный файл int remove (char *filename)

возвращает NULL при успешной операции.

Наши рекомендации