Указатели на структуры
Указатели на структуры определяются точно так же, как и указатели на другие типы данных.
struct COMPLEX *pC;
complex *pcmpl;
Можно вводить указатели и в качестве обозначений структур, т.е.
struct birth {
char Where[40];
struct date When;
} *pB1, *pB2;
- это для одновременного описания структуры и ее определения (создаются указатели pB1 и pB2.
Возможно также:
typedef struct COMPLEX
{
double real;
double imag;
} complex, *ptr_comp;
и тогда для определения переменной типа указатель на структуру:
ptr_comp px [12];
complex * px [12];
- одинаково определяют массивы из 12-ти указателей на структуру complex.
Доступ к элементам структуры, определенной через указатель
осуществляется одним из двух способов
(*<указатель на структуру>).<имя элемента>
<указатель на структуру>-><имя элемента>
Первый способ традиционный, он основан на равенстве
если pAdr == &adr, то *pAdr == adr
В программах обычно применяют второй способ, связанный с использованием специальной операции «->». Эта операция, наряду со скобками и операцией «.» имеет наивысший приоритет. Операция «стрелка» обеспечивает доступ к элементу структуры через адресующий ее указатель того же структурного типа. Операция «стрелка» иногда называется операцией косвенного выбора элемента структурного объекта, адресуемого указателем.
Если struct pBall *pB1 = &B1; то будут справедливы равенства:
pB1 -> color = (*pB1). color
pB1 -> coord = (*pB1). coord
Тип результата операции «стрелка» совпадает с типом операнда, на который она нацелена.
if (pdelta->real > 0) …
psigma->real +=2;
n = ptr_c->imag * ptr_c->imag;
Структуры и функции
Взаимодействие структур и функций может проявляться двумя способами: структура может быть возвращаемым значением и структура может использоваться в качестве аргумента функции. Кроме того, в обоих случаях могут использоваться указатели на объекты структурных типов.
struct COMPLEX f1(int n);
struct complex * f2(int n);
void f3(struct complex cmpl);
void f4(struct complex *Pcmpl);
Как и для других типах данных, структура передается в функцию по значению – т.е. никакие изменения фактических параметров в функции не меняют значения объектов вне ее (под формальный параметр при вызове строится вспомогательный объект). Для изменения содержимого – структуру следует передавать через указатель на нее.
Объединения
Еще одним агрегирующим типом данных в языке С являются объединения, которые вводятся при помощи служебного слова union.
Объединение – это переменная, которая может содержать (в разное время) объекты различных типов и размеров.
Объединение можно рассматривать как структуру, все элементы которой имеют нулевое смещение от начала. При таком размещении разные элементы занимают в памяти один и тот же участок. Тем самым объединения обеспечивают возможность доступа к одному и тому же участку памяти с помощью переменных разного типа.
Цель введения в программу объединения – иметь переменную, которая хранила бы в себе значения нескольких типов.
Для обращения к элементу объединения используются те же конструкции, что и для обращения к элементу структуры:
<имя объединения>.<имя элемента>
(*<указатель на объединение>).<имя элемента >
< указатель на объединение > -> < имя элемента >
Как и данные других типов, объединение – это конкретный объект, которому выделено место в памяти. В качестве элементов объединения могут выступать не только отдельные переменные, но и массивы или структуры. Размеры участка памяти, выделяемого под объединение, определяются по размеру самого большого элемента объединения.
Определение объединений осуществляется точно так же, как и структур
typedef union REG {
unsigned char Byte[2];
unsigned short Word;
} REGISTR;
REG – имя объединяющего типа;
REGISTR – обозначение объединяющего типа;
Использование объединений позволяет создавать машинно-независимый код. Поскольку компилятор отслеживает настоящие размеры переменных, образующих объединение, уменьшается зависимость от компьютера. Не нужно беспокоиться о размере целых или вещественных чисел, символов или чего-либо еще.
Объединения часто используются при необходимости преобразования типов, поскольку можно обращаться к данным, хранящимся в объединении, совершенно различными способами.
Если для хранения типа текущего значения u использовать переменную utype, то
if (utype == INT)
printf(“%d\n”, u.ival);
else if(utype == FLOAT)
printf(“%f\n”, u.fval);
else if(utype == STRING)
printf(“%s\n”, u.sval);
else
printf(“неверный тип %d в utype\n”, utype);
Инициализировать объединение можно только значением, имеющим тип его первого члена. Упомянутую выше переменную u можно инициализировать только значением типа int.
Битовые поля
При дефиците памяти может возникнуть необходимость запаковать несколько объектов в одно слово машины. Одна из обычных ситуаций – это объединение групп однобитовых флажков. Битовое поле может быть только элементом структуры или объединения и вне этих объектов не встречается. Назначение битовых полей – обеспечить удобный доступ к отдельным битам данных. С помощью битовых полей можно формировать объекты с длиной внутреннего представления не кратной байту. Битовые поля не имеют адресов и не могут объединяться в массивы.
Битовые поля полезны по следующим причинам:
1. Если ограничено место для хранения информации, можно сохранить несколько логических переменных в одном байте.
2. Некоторые интерфейсы передают информацию, закодировав биты в один байт.
3. Некоторым процедурам кодирования необходимо получить доступ к отдельным битам в байте.
Описание структуры с битовыми полями имеет следующий формат:
struct {
<тип 1> <имя поля 1>:<ширина поля 1>;
<тип 2> <имя поля 2>:<ширина поля 2>;
. . .
} <имя структуры>;
где <тип i> - тип поля, который может быть только int (signed или unsigned);
<ширина поля i> - целое неотрицательное десятичное число, не превышающее разрядности слова конкретной ЭВМ.
Разрешается не указывать имени поля, что означает пропуск (неиспользование) соответствующего указанной ширине количества бит. Нулевая длина вводится, когда необходимо, чтобы следующее поле разместилось с начала очередного слова конкретной ЭВМ.
Вместо struct может употребляться union.
Для обращения к полям используются те же конструкции, что и для обращения к обычным элементам структур:
<имя структуры>.<имя поля i>
(*<указатель на структуру>).<имя поля i>
<указатель на структуру> -> <имя поля i>
Нельзя получить адрес переменной битового поля. Переменные битового поля не могут помещаться в массив. Переходя с компьютера на компьютер нельзя быть уверенным в порядке изменения битов (слева на право или справо налево). Любая программа использует битовые поля и зависит от компьютера. Можно смешивать различные структурные переменные в битовых полях.
Попытка присвоить нецелое значение, либо значение, слишком большое для указанного поля, приведет к возникновению ошибки. Обычно оказывается полезным определить массив символических констант для всевозможных значений битового поля и использовать введенные символические имена.
Дата добавления: 2016-04-14; просмотров: 1164;