Logo GenDocs.ru

Поиск по сайту:  


Загрузка...

Лекции по C/С++ - файл Л6.doc


Загрузка...
Лекции по C/С++
скачать (357.8 kb.)

Доступные файлы (8):

Л1.doc318kb.06.09.2009 15:02скачать
Л2.doc250kb.06.09.2009 14:56скачать
Л3.doc127kb.07.12.2009 15:34скачать
Л4.doc250kb.06.09.2009 14:57скачать
Л5.doc151kb.06.09.2009 14:58скачать
Л6.doc165kb.06.09.2009 14:58скачать
Л7.doc150kb.06.09.2009 14:58скачать
Л8.doc269kb.13.01.2006 20:00скачать

Л6.doc

Реклама MarketGid:
Загрузка...

Лекция №6

7.СЛОЖНЫЕ ТИПЫ ДАННЫХ

7.1. Массивы


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

Объявление массива имеет два формата:

СпецификаторТипа ИмяМассива [КонстантноеВыражение];

^ СпецификаторТипа ИмяМассива [ ];

СпецификаторТипа задает тип элементов объявляемого массива. Элементами массива не могут быть функции и элементы типа void.

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

• при объявлении массив инициализируется,

• массив объявлен как формальный параметр функции,

• массив объявлен как ссылка на массив, явно определенный в другом файле.

Пример:

double b[10]; /* вектор из 10 элементов имеющих тип double */

float f[4]={3.5,6.8,9.0,6};

float f1[]={2.3,5.6,6.7,4.2,3};

Пример: Найти максимальный элемент массива A[10]

#include<stdio.h>

main()

{

const N=10; /*размерность масcива А*/

static float A[N]; /*описание масcива А */

float MAX ;

int I ;

//ввод элементов массива

printf("Bведите через пробел %d чисел\n ",N);

for (I=1;I<=N;I++) scanf("%f",&A[I]);
// нахождение наибольшего элемента последовательности

MAX =A[1];

for (I=2;I<=N;I++)

if (A[I]>MAX) MAX =A[I];

printf("\nMАX=%.3f",MAX);

}



Самостоятельная проработка:


Пример: Дан массив А[10]. Выполнить сортировку первой половины массива в порядке убывания (метод обмена), а вторую – в порядке возрастания (метод выбора).

#include<stdio.h>

void main()

{

const N=10; /*размерность масcива А*/

static float A[N]; /*описание масcива А */

float k ;

int I,J,m ;

//ввод элементов массива

printf("Bведите через пробел %d чисел\n ",N);

for (I=0;I<N;I++) scanf("%f",&A[I]);

// Сортировка методом обмена

for(I=0;I<N/2-1;I++)

for (J=0;J<N/2-1;J++)

if (A[J]<A[J+1]) /*Сравнение пары соседних чисел A[J] и A[J+1]*/

{

k=A[J]; /*Перестановка A[J] и A[J+1] местами */

A[J]=A[J+1];

A[J+1]=k;

}

// Сортировка методом выбора

for(I=N-1;I>N/2+2;I--)

{

m=N/2+1; /* Индекс первого элемента */

for (J=N/2+1;J<I;J++)

if (A[J]>A[m]) m=J;

k=A[m]; /*Перестановка A[m] и A[I] местами */

A[m]=A[I];

A[I]=k;
}
//вывод отсортированного массива

printf("\nОтсортированный массив\n");

for (I=0;I<N;I++)

printf("%8.2f\n",A[I]);

}

Пример: Дан массив А[10]. Выполнить сортировку массива в порядке возрастания.

#include<stdio.h>

void main()

{

const N=10; /*размерность масcива А*/

static float A[N]; /*описание масcива А */

float k ;

int I,J,m ;

//ввод элементов массива

printf("Bведите через пробел %d чисел\n ",N);

for (I=0;I<N;I++) scanf("%f",&A[I]);

// Сортировка

for(I=0;I<N-1;I++)

for (J=I+1;J<N;J++)

if (A[I]<A[J])

{

k=A[I];

A[I]=A[J];

A[J]=k;

}
//вывод отсортированного массива

printf("\nОтсортированный массив\n");

for (I=0;I<N;I++)

printf("%8.2f\n",A[I]);

}

Пример: Дан массив A[N]. Найти произведение положительных элементов первой половины массива и сумму отрицательных элементов второй половины массива. Использовать цикл while.
#include<stdio.h>

#include<conio.h>

void main()

{

const N=10;

int I,P,S;

static int A[N];

printf("Введите %d чисел\n",N);

I=0;

P=1;

while(I<N/2)

{ scanf("%d",&A[I]);

if (A[I]>0) P=P*A[I];

I++;}
I=N/2+1;

S=0;

while (I<N)

{ scanf("%d",&A[I]);

if (A[I]<0) S=S+A[I];

I++;}
printf("P= %d\n",P);

printf("S= %d",S);

getch();

}



В языке С++ определены только одномерные массивы, но поскольку элементом массива может быть массив, можно определить и многомерные массивы. Они формализуются списком КонстантныхВыражений следующих за идентификатором массива, причем каждое КонстантноеВыражение заключается в свои квадратные скобки.

^ Форма записи многомерного массива:

СпецификаторТипа ИмяМассива [КонстантноеВвыражение1] …[КонстантноеВыражениеN];

Каждое КонстантноеВыражение в квадратных скобках определяет число элементов по данному измерению массива, так что объявление двухмерного массива содержит два КонстантныхВыражения, трехмерного - три и т.д. Отметим, что в языке С++ первый элемент массива имеет индекс равный 0.

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

Примеры:

int w[3][3] = { { 2, 3, 4 },

{ 3, 4, 8 },

{ 1, 0, 9 } };

int a[2][3]; /* представлено в виде матрицы

a[0][0] a[0][1] a[0][2]

a[1][0] a[1][1] a[1][2] */

В последнем примере объявлен массив w[3][3]. Списки, выделенные в фигурные скобки, соответствуют строкам массива, в случае отсутствия скобок инициализация будет выполнена неправильно.



Самостоятельная проработка:



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

Примеры:

int s[2][3];

Если при обращении к некоторой функции написать s[0], то будет передаваться нулевая строка массива s.

int b[2][3][4];

При обращении к массиву b можно написать, например, b[1][2] и будет передаваться вектор из четырех элементов, а обращение b[1] даст двухмерный массив размером 3 на 4. Нельзя написать b[2][4], подразумевая, что передаваться будет вектор, потому что это не соответствует ограничению, наложенному на использование сечений массива.

Пример: Дан двумерный массив A[N][M]. Выполнить сортировку массива по возрастанию.

#include<stdio.h>

#include<conio.h>

main()

{

const N=2,M=3; /*размерность масcива А*/

static int A[N][M];

static int B[N*M]; /*описание масcивов А,В,С*/

int I,J,K;

//ввод элементов массива

K=1;

printf("Bведите элементы массива А[%d][%d]\n ",N,M);

for (I=0;I<N;I++)

for (J=0;J<M;J++)

{

scanf("%d",&A[I][J]);

B[K]=A[I][J];

K=K+1;

}

for (I=0;I<N*M-1;I++)

for (J=I+1;J<N*M;J++)

if (B[I]<B[J])

{ K=B[I];

B[I]=B[J];

B[J]=K;

}

K=1;

for (I=0;I<N;I++)

for (J=0;J<M;J++)

{

A[I][J]=B[K];

K=K+1;

}

printf("\nОтсортированный массив \n");

for (I=0;I<N;I++)

{

for (J=0;J<M;J++)

printf("%4d",A[I][J]);

printf("\n");

}

getch();

}

Пример: Дан двумерный массив NxM целых чисел, где N=2, а M=3. Сформировать массив В, состоящий из четных максимальных элементов каждой строки массива, и массив С, состоящий из максимальных нечетных элементов каждой строки массива.
#include<stdio.h>

#include<conio.h>

void main()

{

const N=2,M=3; /*размерность масcива А*/

static int A[N][M];

int B[N],C[N]; /*описание масcивов А,В,С*/

int MAX ;

int I,J;

//ввод элементов массива

printf("Bведите элементы массива А[%d][%d]\n ",N,M);

for (I=0;I<N;I++)

for (J=0;J<M;J++)

scanf("%d",&A[I][J]);

// нахождение наибольшего элемента последовательности

for (I=0;I<N;I++)

{

MAX=A[I][1];

for (J=0;J<M;J++)

if (A[I][J]>MAX) MAX=A[I][J];

if (MAX%2==0)

{

B[I] =MAX;

C[I]=0;

}

else

^ {C[I] =MAX;

B[I]=0;

}

}

printf("\nМассив B\n");

for (I=0;I<N;I++)

printf("%-4d",B[I]);

getch();

printf("\nМассив С\n");

for (I=0;I<N;I++)

printf("%-4d",C[I]);

getch();

}



Пример: Дан массив A[N][M]. Найти максимальный элемент каждой строки массива.
#include<stdio.h>

void main()

{

const N=2,M=3;

static int A[N][M];

int I,J,MAX;

printf("Введите массив А[%d][%d]\n",N,M);

for(I=0;I<N;I++)

for(J=0;J<M;J++)

scanf("%d",&A[I][J]);

printf("\nМаксимальные элементы каждой строки:\n");
for(I=0;I<N;I++)

{

MAX=A[I][1];

for(J=0;J<M;J++)

if (A[I][J]>MAX) MAX=A[I][J];

printf("%d\n",MAX);

}

}



Самостоятельная проработка:


Пример: Дан двумерный массив A[N][M]. Поменять местами 1 и 2 строку, а затем поменять местами 1 и 3 столбец.

#include <stdio.h>

void main()

{

const n=3,m=3;

static int a[n][m];

int i,j,k;

printf(" Введите массив %d X %d\n",n,m);

for(i=0;i<n;i++)

for (j=0;j<m;j++)

scanf("%d",&a[i][j]);

for(j=0;j<m;j++)

{

k=a[1][j];

a[1][j]=a[2][j];

a[2][j]=k;

}

printf(" 1 и 2 строки поменяли местами\n");

for(i=0;i<n;i++)

{

for (j=0;j<m;j++)

printf("%d",a[i][j]);

printf("\n");

}

for(i=0;i<n;i++)

{

k=a[i][1];

a[i][1]=a[i][3];

a[i][3]=k;

}

printf(" 1 и 3 столбцы поменяли местами\n");

for(i=0;i<n;i++)

{

for (j=0;j<m;j++)

printf("%d",a[i][j]);

printf("\n");

}

}



Пример объявления символьного массива.

char str[] = “объявление символьного массива“;

char str[] ={ “объявление символьного массива“};

Следует учитывать, что в символьном литерале находится на один элемент больше, так как последний из элементов является управляющей последовательностью '\0'.

Пример: Дано натуральное n, символы S1,..,Sn. Подсчитать наибольшее число букв А, идущих подряд в данной последовательности

символов.
#include<stdio.h>

#include<conio.h>

void main()

{

const N=10;

int I,K,K1;

char S[N];

K=0; K1=0;

printf("ВВЕДИТЕ СТРОКУ СИМВОЛОВ\n");

scanf("%s",S);

for (I=0;I<N;I++)

{

if (S[I]=='A') K=K+1; else K=0;

if ((K>1)&&(K>K1)) K1=K;

}

printf("КОЛИЧЕСТВО СТОЯЩИХ ПОДРЯД А = %d",K1);

getch();

}

7.2. Структуры


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

struct [Тег] { ТипДанных Описатель1;

………

ТипДанных ОписательN; }[СписокИдентификаторов]

В структуре обязательно должен быть указан хотя бы один компонент. ТипДанных указывает тип структуры для объектов, находящихся в описателях. В простейшей форме описатели представляют собой идентификаторы или массивы. Наличие тега необязательно, тег является идентификатором структуры.

Пример объявления структур:

struct koord{ double x,y; } s1, s2, sm[9];

struct { int year;

char moth, day; } date1, date2;

Переменные s1, s2 определяются как структуры, каждая из которых состоит из двух компонент х и у. Переменная sm определяется как массив из девяти структур. Каждая из двух переменных date1, date2 состоит из трех компонентов year, moth, day. >p>

Наличие СпискаИдентификаторов в записи типа структуры также необязательно. Объявление СпискаИдентификаторов, как структур, допускается с использованием тега структуры, описанной ранее, в форме:

struct Тег СписокИдентификаторов;

Пример объявления структур:

struct studeut st1,st2;

Использование тегов структуры необходимо для описания рекурсивных структур. Ниже рассматривается использование рекурсивных тегов структуры.

struct node { int data;

struct node * next; } st1_node;

Тег структуры node действительно является рекурсивным, так как он используется в своем собственном описании, т.е. в формализации указателя next. Структуры не могут быть прямо рекурсивными, т.е. структура node не может содержать компоненту, являющуюся структурой node, но любая структура может иметь компоненту, являющуюся указателем на свой тип, как и сделано в приведенном примере.

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

Пример:

struct ft{ int a;

char s[12];

float g;} f={6,”Hello”,5.72};

Доступ к компонентам структуры осуществляется с помощью указания имени структуры и следующего через точку имени выделенного компонента, например:

st1.name=”Иванов”;

st2.id=st1.id;

st1_node.data=st1.age;
Пример: Дан массив из 5 записей. Каждая запись содержит три поля: первое поле – название продукции; второе поле – количество продукции; третье – год выпуска.

Вывести на экран список и количество продукции, год выпуска которой не меньше 1997 и не больше 1999г.
#include<stdio.h>

#include<conio.h>

void main()

{

const N=3; //описание размера массива структур

struct tovar{char nazv[10]; // описание типа структуры

int kol;

int god;

};

static tovar tv[N]; // описание массива структур tv из N элементов

int M;

int I,J; //параметры циклов

//ввод элементов cтруктуры

for (I=0;I<N;I++)

{printf("Bведите [%d] элементы структуры\n",I);

scanf("%s %d %d",&tv[I].nazv,&tv[I].kol,

&tv[I].god);}

printf("Наименование Кол-во Год выпуска:\n");

for (I=0;I<N;I++)

if ((tv[I].god>=1997)&&(tv[I].god<=1999))

{printf("%-10s %6d %6d",tv[I].nazv,

tv[I].kol,tv[I].god);

printf("\n");}

getch();

}

Пример: Дан массив из 5 записей. Каждая запись содержит три поля: первое поле – название продукции; второе поле – количество продукции; третье – год выпуска.

Вывести на экран название и количество продукции, которой в наличии больше всего и год выпуска которой не превышает 1997г.
#include<stdio.h>

#include<conio.h>

void main()

{

const N=3; //описание размера массива структур

struct tovar{char nazv[10]; // описание типа структуры

int kol;

int god;

};

static tovar tv[N]; // описание массива структур tv из N элементов

int MAX=0,M;

int I,J; //параметры циклов

//ввод элементов cтруктуры

for (I=0;I<N;I++)

{printf("Bведите [%d] элементы структуры\n",I);

scanf("%s %d %d",&tv[I].nazv,&tv[I].kol,

&tv[I].god);}

// нахождение начального значения МАХ

for (I=0;I<N;I++)

if (tv[I].god>=1997)

{ MAX=tv[I].kol;

M=I;

break;

}

//нахождение максимального количества

for (I=M+1;I<N;I++)

if (tv[I].god>=1997)

if (tv[I].kol>MAX)

MAX=tv[I].kol;

//Вывод результатов

printf("В наличии больше всего:\n");

printf("Наименование Кол-во Год выпуска:\n");

for (I=0;I<N;I++)

if (tv[I].god>=1997)

if (tv[I].kol==MAX)

{printf("%-10s %6d %6d",tv[I].nazv,tv[I].kol,tv[I].god);

printf("\n");}

getch();

}




Самостоятельная проработка:


^

Поля битов


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

struct {Тип Идентификатор 1 : ДдлинаПоля 1;

Тип Идентификатор 2 : ДлинаПоля 2; }

Тип – это char, unsigned char, int, unsigned int. ДлинаПоля задается целым выражением или константой. Эта константа определяет число битов, отведенное соответствующему полю. Целочисленные компоненты типа signed или unsigned можно объявлять битовыми полями шириной от 1 до 16 бит. Поле нулевой длины обозначает выравнивание на границу следующего слова.

Пример:

struct { unsigned a1 : 1;

unsigned a2 : 2;

unsigned a3 : 5;

unsigned a4 : 2; } prim;
Допустимы неименованные поля (они не доступны программе, т.е. не используются); они не влияют на смысл именованных полей, но неким машинно-зависимым образом могут улучшить размещение:
struct sreg {

unsigned e : 1;

unsigned p : 3;

unsigned : 1; // неиспользуемое

unsigned m : 2;

unsigned : 4: // неиспользуемое

int a : 1;

int k : 1;

unsigned n : 2;}

создает следующее распределение памяти



где х – не используемые биты.
Этот пример также иллюстрирует другое основное применение полей: именовать части внешне предписанного размещения.

Поле должно быть целого типа и используется как другие целые, за исключением того, что невозможно взять адрес поля. Целочисленные поля хранятся в виде дополнения до двух, причем крайний левый бит помещается в MSB(наиболее значащий). Для битового поля типа Int (например, signed) MSB интерпретируется как знаковый бит. Битовое поле шириной 2, содержащее 11, будет следовательно интерпретироваться для unsigned как 3, а для int как –1. В предыдущем примере допустимое выражение sreg.n=6 поместит в sreg.n двоичное 10=-2, не выдавая каких-либо предупреждений. Поле k типа int шириной 1 может содержать только значения 0 и –1, т.к. битовый шаблон 1 будет считаться знаковым и интерпретироваться в –1.

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

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

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

Пример:

#include <stdio.h>

union

{

long int IntVal;

float FloatVal;

struct

{

int bit0 : 1;

int bit1 : 1;

int bit2 : 1;

int bit3 : 1;

int bit4 : 1;

int bit5 : 1;

int bit6 : 1;

int bit7 : 1;

int bit8 : 1;

int bit9 : 1;

int bit10 : 1;

int bit11 : 1;

int bit12 : 1;

int bit13 : 1;

int bit14 : 1;

int bit15 : 1;

int bit16 : 1;

int bit17 : 1;

int bit18 : 1;

int bit19 : 1;

int bit20 : 1;

int bit21 : 1;

int bit22 : 1;

int bit23 : 1;

int bit24 : 1;

int bit25 : 1;

int bit26 : 1;

int bit27 : 1;

int bit28 : 1;

int bit29 : 1;

int bit30 : 1;

int bit31 : 1;

} BitField;

} MyUnion;

void main ()

{

MyUnion.BitField.bit31 = 0;

MyUnion.BitField.bit30 = 1;

MyUnion.BitField.bit29 = 0;

MyUnion.BitField.bit28 = 0;

MyUnion.BitField.bit27 = 0;

MyUnion.BitField.bit26 = 0;

MyUnion.BitField.bit25 = 1;

MyUnion.BitField.bit24 = 1;

MyUnion.BitField.bit23 = 0;

MyUnion.BitField.bit22 = 0;

MyUnion.BitField.bit21 = 1;

MyUnion.BitField.bit20 = 1;

MyUnion.BitField.bit19 = 0;

MyUnion.BitField.bit18 = 0;

MyUnion.BitField.bit17 = 1;

MyUnion.BitField.bit16 = 0;

MyUnion.BitField.bit15 = 0;

MyUnion.BitField.bit14 = 0;

MyUnion.BitField.bit13 = 1;

MyUnion.BitField.bit12 = 0;

MyUnion.BitField.bit11 = 0;

MyUnion.BitField.bit10 = 0;

MyUnion.BitField.bit9 = 0;

MyUnion.BitField.bit8 = 0;

MyUnion.BitField.bit7 = 0;

MyUnion.BitField.bit6 = 0;

MyUnion.BitField.bit5 = 0;

MyUnion.BitField.bit4 = 0;

MyUnion.BitField.bit3 = 0;

MyUnion.BitField.bit2 = 0;

MyUnion.BitField.bit1 = 0;

MyUnion.BitField.bit0 = 0;

long int k;

k= MyUnion.IntVal>>4;

printf("%f\n", MyUnion.FloatVal);

printf("%lx\n", MyUnion.IntVal);

printf("%lx\n", k);

}
^

Переменные с изменяемой структурой


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

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

struct figure {

double area,perimetr; /* общие компоненты */

int type; /* признак компонента */

union /* перечисление компонент */

{ double radius; /* окружность */

double a[2]; /* прямоугольник */

double b[3]; /* треугольник */

} geom_fig;

} fig1, fig2 ;

В общем случае каждый объект типа figure будет состоять из трех компонентов: area, perimetr, type. Компонент type называется меткой активного компонента, так как он используется для указания, какой из компонентов объединения geom_fig является активным в данный момент. Такая структура называется переменной структурой, потому что ее компоненты меняются в зависимости от значения метки активного компонента (значение type).

Отметим, что вместо компоненты type типа int, целесообразно было бы использовать перечисляемый тип. Например, такой

enum figure_chess { CIRCLE,

BOX,

^ TRIANGLE } ;

Константы CIRCLE, BOX, TRIANGLE получат значения соответственно равные 0, 1, 2. Переменная type может быть объявлена как имеющая перечислимый тип :

enum figure_chess type;

В этом случае компилятор С++ предупредит программиста о потенциально ошибочных присвоениях, таких, например, как

figure.type = 40;

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

struct { общие компоненты;

метка активного компонента;

union { описание компоненты 1 ;

описание компоненты 2 ;

:::

описание компоненты n ;

} идентификатор-объединения ;

} идентификатор-структуры ;

Пример определения переменной структуры с именем helth_record

struct { /* общая информация */

char name [25]; /* имя */

int age; /* возраст */

char sex; /* пол */

/* метка активного компонента */

/* (семейное положение) */

enum merital_status ins;

/* переменная часть */

union { /* холост */

/* нет компонент */

struct { /* состоит в браке */

char marripge_date[8];

char spouse_name[25];

int no_children;

} marriage_info;

/* разведен */

char date_divorced[8];

} marital_info;

} health_record;

enum marital_status { SINGLE, /* холост */

MARRIGO, /* женат */

DIVOREED /* разведен */

} ;

Обращаться к компонентам структуры можно при помощи ссылок:

helth_record.neme,

helth_record.ins,

helth_record.marriage_info.marriage_date .



^

12.3. Данные перечислимого типа


Переменная (или константа), которая может принимать значение из некоторого списка значений, называется переменной(или константой) перечислимого типа или перечислением.

Объявление перечисления начинается с ключевого слова enum.

^ Форма представления:

enum [Тег] { ТипДанных Идентификатор1 [= константное выражение1];

… … …

ТипДанных ИдентификаторN [= константное выражениеN];

} [СписокИдентификаторов];

enum Тег СписокИдентификаторов;

Объявление перечисления задает тип переменной перечисления и определяет список именованных констант, называемый списком перечисления. Значением каждого имени списка является некоторое целое число.

Переменная типа перечисления может принимать значения одной из именованных констант списка. Именованные константы списка имеют тип int. Таким образом, память, соответствующая переменной перечисления, это память необходимая для размещения значения типа int.

Переменная типа enum могут использоваться в индексных выражениях и как операнды в арифметических операциях и в операциях отношения.

Пример:

Определить, какой месяц (из трех введенных) к какому сезону относится. Номер месяца вводить самостоятельно.

#include<stdio.h>

#include<conio.h>

void main()

{enum mes{JV,F,MT,AP,M,JU,JL,AV,ST,OKT,NV,DS};

enum sezon{ZIMA,VESNA,LETO,OSEN} s;

mes m;

int i;

for(i=MT;i<=M;i++)

{

clrscr();

printf("Введите номер месяца:\n");

printf("0-Январь,1-Февраль,...,11-Декабрь\n");

scanf("%d",&m);

switch (m) {

case DS,JV,F: {printf("ZIMA");s=ZIMA; break;}

case MT,AP,M: {printf("VESNA");s=VESNA; break;}

case JU,JL,AV: {printf("LETO");s=LETO; break;}

case ST,OKT,NV:{printf("OSEN");s=OSEN; break;}

}

printf("\nПорядковый номер сезона %d",s);

getch();

}

}
Пример: Корабль шел по курсу К1, а затем был дан приказ PR изменить направление курса. Определить новый курс К2.
#include<stdio.h>

#include<conio.h>

void main()

{enum kurs{sever,vostok,iug,zapad};

enum prikaz{vpered,vpravo,nazad,vlevo};

kurs k1,k2;

prikaz pr;

//ввод элементов cтруктуры

printf(" Задайте курс:\n");

printf("0-север; 1-восток;");

printf("2-юг; 3-запад;\n");

scanf("%d",&k1); /*ввод значения начального курса */

printf(" Измените курс:\n");

printf("0-вперед; 1-вправо;");

printf("2-назад; 3-влево;\n");

scanf("%d",&pr); /* задание приказа */

printf("Начальный курс\n");

switch (k1){ /* вывод значения начального курса на экран */

case 0:printf("север"); break;

case 1:printf("восток");break;

case 2:printf("юг");break;

case 3:printf("запад");break;

}

printf("\n Конечный курс\n");

k2=(k1+pr)%4; /*определение конечного курса */

switch (k2){ /* вывод значения конечного курса на экран */

case 0:printf(“север”); break;

case 1:printf(“восток”);break;

case 2:printf(“юг”);break;

case 3:printf(“запад”);break;

}

getch(); /*задержка*/

}

Необязательное имя тега перечисления, это идентификатор, который именует тег перечисления, определенный списком перечисления. Каждый идентификатор именует элемент перечисления. Все идентификаторы в списке enum должны быть уникальными. В случае отсутствия константного выражения первому идентификатору соответствует значение 0, следующему идентификатору - значение 1 и т.д. Имя константы перечисления эквивалентно ее значению.

Идентификатор, связанный с константным выражением, принимает значение, задаваемое этим константным выражением. Константное выражение должно иметь тип int и может быть как положительным, так и отрицательным. Следующему идентификатору в списке присваивается значение, равное константному выражению плюс 1, если этот идентификатор не имеет своего константного выражения.

Использование элементов перечисления должно подчиняться следующим правилам:

1. Переменная может содержать повторяющиеся значения.

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

3. Имена типов перечислений должны быть отличны от других имен типов перечислений, структур и смесей в этой же области видимости.

4. Значение может следовать за последним элементом списка перечисления.

Пример:

enum week { SUB = 0, /* 0 */

VOS = 0, /* 0 */

POND, /* 1 */

VTOR, /* 2 */

SRED, /* 3 */

HETV, /* 4 */

PJAT /* 5 */

} rab_ned ;

В данном примере объявлен перечислимый тег week, с соответствующим множеством значений, и объявлена переменная rab_ned имеющая тип week.

Как и для структур, имя тега перечисления используется для ссылки на тип перечисления, определяемый где-то в другом месте. Имя тега перечисления должно относится к уже определенному тегу перечисления в пределах текущей области видимости. Так как тег перечисления объявлен где-то в другом месте, список перечисления не представлен в объявлении.

Пример:

enum week rab1;

В объявлении указателя на тип данных перечисления и объявляемых typedef для типов перечисления можно использовать имя тега перечисления до того, как данный тег перечисления определен. Однако определение перечисления должно предшествовать любому действию используемого указателя на тип объявления typedef. Объявление без последующего списка описателей описывает тег, или, если так можно сказать, шаблон перечисления.
^

12.4. Объединения (смеси)


Объединение подобно структуре, однако в каждый момент времени может использоваться (или другими словами быть ответным) только один из элементов объединения. Тип объединения может задаваться в следующем виде:

union[Тег] {ТипДанных Описатель 1;

...

ТипДанных Описатель N; }[СписокИдентификаторов];

Как и для структур наличие Тега и СпискаИдентификаторов необязательно.

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

Доступ к элементам объединения осуществляется тем же способом, что и к структурам. Тег объединения может быть формализован точно так же, как и тег структуры.

Объединение применяется для следующих целей:

• инициализации используемого объекта памяти, если в каждый момент времени только один объект из многих является активным;

• интерпретации основного представления объекта одного типа, как если бы этому объекту был присвоен другой тип.

Общий синтаксис объявления объединений во многом напоминает синтаксис объявления структур. Различия в следующем:

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

2. В отличие от структур, объединения в С++ не могут использовать спецификаторы класса доступа public, private, protected. Все поля имеют доступ private.

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

union ret{ int I; float n} a={12};

4. Объединение не может участвовать в иерархии класса. Оно не может являться производным от какого-либо класса или быть базовым классом. Объединение может иметь конструктор.

5. Анонимные объединения не могут иметь компоненты-функции.

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

Пример:

union Spravka{ char fio[30];

char adres[80];

int vozrast;

int telefon; } inform;

union { int ax;

char al[2]; } ua;

При использовании объекта inform типа union можно обрабатывать только тот элемент который получил значение, т.е. после присвоения значения элементу inform.fio, не имеет смысла обращаться к другим элементам. Объединение ua позволяет получить отдельный доступ к младшему ua.al[0] и к старшему ua.al[1] байтам двухбайтного числа ua.ax .
^

12.5. Тип void


Void это специальный спецификатор типа, указывающий на отсутствие каких-либо значений. Тип данных void (пустой) определяет пустое множество значений. Значение (несуществующее) объекта void нельзя использовать никаким образом, не могут применяться ни явное, ни неявное преобразования. Поскольку пустое выражение обозначает несуществующее значение, такое выражение может использоваться только как оператор “выражение” или как левый операнд в выражении в операции последовательного вычисления. Выражение может явно преобразовываться к типу void.

Тип void задается в следующих ситуациях:

- Пустой список параметров в объявлении функции:

int func(void); // функция не принимает аргументов

С++ обрабатывает 0 специальным образом

- Когда объявленная функция не возвращает значений:

void func(int n); // возвращаемое значение отсутствует

- В качестве родового указателя. Указатель на void является родовым указателем на все что угодно:

void *ptr; // далее ptr может быть установлен на любой объект

- Выражения с проверкой типа:

extern int errfunc(); // возвращает код ошибки

(void) errfunc(); // значение возврата теряется






Скачать файл (357.8 kb.)

Поиск по сайту:  

© gendocs.ru
При копировании укажите ссылку.
обратиться к администрации
Рейтинг@Mail.ru