Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛекцииЛаб(Часть_1_Книги).doc
Скачиваний:
7
Добавлен:
03.05.2019
Размер:
1.04 Mб
Скачать

Symbol Code16 Code10 Code2

a 61 97 01100001

A 41 65 01000001

2 32 50 00110010

00 0 00000000

; 3b 59 00111011

Две строки получили, если при вводе нажали на клавишу “F1”

; 3b 59 00111011

Получили при вводе символа ‘;’

00 0 00000000

H 48 72 01001000

Две строки получили, если при вводе нажали на клавишу “стрелка вверх”

00 0 00000000

R 52 82 01010010

Две строки получили, если при вводе нажали на клавишу “ Insert

R 52 82 01010010

Получили при вводе символа ‘R’.

Здесь один байт обозначается следующим образом:

|---------------------------------- N.ch --------------------|

|---- N.num16.n2---------|-- ---N.num16.n1-----------|

Кроме этого, “левый крайний” бит обозначается N.MyB.b8, следующий бит — N.MyB.b7 и т.д. Доступ к младшему “правому” биту осуществляется с помощью N.MyB.b1.Так как поля битов n1 и n2 объединены в структуру, которая входит в объединение, то эти поля занимают разные биты в указанном выше порядке.

Пример 2.б. Изменим объявление объединения. Включим в него поля битов n1 и n2 напрямую, то есть объявим объединение так:

union TUI

{ TMyByte MyB;

unsigned n1:4; unsigned n2:4;

char ch;

} N;

Тогда поля n1 и n2 будут занимать одни и те же “крайние правые” четыре бита. Так как структуры num16 в этом варианте нет, то доступ к таким полям осуществляется так:

cout<<" "<< hex<<N.n2<<N.n1;

printf(" %d ", N.n2*16+N.n1);

Но эти операторы выведут неправильный результат. Например, для символа A вместо 41 и 65 будет выведено 11 и 17, так как доступ к шестнадцатеричной цифре 4 мы потеряли, а цифра 1 будет храниться и в поле n1, и в поле n2. Двоичное представление кода будет по- прежнему выводиться правильно.

Битовые поля имеют ряд ограничений и особенностей.

Нельзя получить адрес битового поля. Это объясняется тем, что адрес — это номер байта, а не бита, и битовые поля размещаются не с самого начала байта. Поэтому для них не определена операция “взятие адреса” (&). По этой же причине нет указателей и ссылок на битовые поля. Нельзя возвратить их из функции. Поля битов не могут объединяться в массивы.

Можно объявить поле битов без указания его идентификатора. Например,

{ struct {

unsigned a:5;

unsigned :3;

unsigned y:1;

} S2;

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

Заметим в заключение, что любой код, использующий поля битов, зависит от компьютера.

§7. Перечисления

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

enum тип { список_идентификаторов};.

Здесь enum — ключевое слово, полученное от сокращения слова enumarate (перечислять). В скобках записываются через запятую идентификаторы, которые ещё называют именованными целочисленными константами. Как и структуры и объединения, переменные перечисляемого типа можно объявить как вместе с типом, так и раздельно. Допускается также анонимное объявление переменных, то есть без указания типа.

Например, следующее раздельное объявление

enum TColors {clBlack, clBlue, clGreen, clRed, clYellow, clWhite};

TColors C1, C2;

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

C1= clBlue;.

Допускается использование такой переменной в операторах if, while, for и других, например:

if (C1==clRed) …

Каждому идентификатору, записанному в фигурных скобках при определении типа, ставится в соответствие целочисленное значение. По умолчанию первый из них ( в примере clBlack) имеет значение нуль, второй (clBlue) — единица и т.д.. При изменении порядка идентификаторов (названий цветов) им могут соответствовать другие целые величины. Поэтому оператор

printf(" %d %d ",C1, clYellow);

выведет 1, так как в переменной С1 находится значение clBlue, которое в списке на втором месте, а нумерация с нуля. Второе выведенное значение — число 4, так как clYellow на пятом месте.

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

float a[4] ={11, 2.2,-3.3,4.4};

оператор

cout<<a[C1]<<" "<<a[clWhite]<<" ";

выведет значение a[1], то есть 2.2, и a[5], то есть 0.

Цикл

for(C2=clBlue; C2<=clYellow; C2+=1) cout<< a[C2]<<" ";

выведет 2.2, -3.3, 4.4, 0. Из этого примера видно, что для перечислений можно использовать обычные арифметические операции. Например,

C2=clWhite; unsigned test; test=C1+C2; cout<<"C1+C2 "<<test;

выведет C1+C2 6, несмотря на то, что цвета с таким номером нет.

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

enum TColors {clBlack, clBlue, clGreen=5, clRed, clYellow, clWhite} С3;

Тогда именованные константы, следующие после той, для которой записано значение (clRed, clYellow и т.д.), будут нумероваться, начиная с этого указанного значения (6, 7, 8). Номера первых идентификаторов останутся без изменения (0, 1). Понятно, что аналогичный цикл for после такой инициализации работает, но неправильно. Будет выведено восемь значений (в качестве упражнения подумайте, каких).

Вводить переменные перечисляемого типа нельзя. Оператор cin>>C1; работать правильно не будет. “Компилятор нас не ругает”, программа продолжает работать и в случае, если ввести номер (например, 3), и если ввести идентификатор (например, clRed). Но дальнейший вывод введённого значения показывает, что переменную правильно мы так и не определили, так как дальше выводится значение, определённое раньше при присваивании, а не то, которое ввели.

При выводе такой переменной выводятся соответсвующие целые значения, а не имена констант. А как вывести идентификаторы? Один из способов — использование оператора switch одним из следующих способов:

switch (C1)

{ case clBlack: cout<<" clBlack "; break;

case clBlue : cout<<" clBlue "; break;

case clGreen : cout<<" clGreen "; break;

case clRed : cout<<" clRed "; break;

case clYellow: cout<<" clYellow "; break;

case clWhite: cout<<" clWhite "; break;

default: cout<<”Error!”; };

или

switch (C1)

{ case 0: cout<<" clBlack "; break;

case 1 : cout<<" clBlue "; break;

case 2 : cout<<" clGreen "; break;

case 3 : cout<<" clRed "; break;

case 4: cout<<" clYellow "; break;

case 5: cout<<" clWhite "; break;

default: cout<<"Error!"; };

При этом не важно, как мы определили C1, с помощью номера, например, C1=3, или с помощью идентификатора (C1=clRed).

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

Упражнения, тесты.

1. Выберите верные утверждения:

          1. В структуре могут быть только переменные с атрибутами public.

          2. В структуре должны быць обязательно переменные и при необходимости функции.

          3. Поля структуры имеют атрибут по умолчанию public.

          4. Поля структуры могут иметь атрибут private, который записывается явно.

          5. Функции в структуре могут иметь атрибут как public, так и private.

          6. Все элементы структуры имеют один и тот же начальный адрес.

          7. Поля битов можно использовать без структуры и без объединения.

          8. В структуре нельзя использовать поля битов.

          9. Доступ к полям структуры, если объявлен указатель на структуру, осуществляется с помощью операции “.” (точка).

          10. Доступ к полям объединения, если объявлен указатель на объединение, осуществляется с помощью операции “—>” (стрелка).

          11. Доступ к полям объединения, если объявлен указатель на объединение, осуществляется с помощью операции “.” (точка).

  1. Дан код:

struct tst { int l; float * coord; float per; } s1;

tst s1=s1; //1

tst *s2= new tst; //2

tst *s3=&s1; //3

tst &s4=s1; //4

tst &s5=*s1; //5

В каких вариантах (//1 — //5) правильно объявлен и проинициализирован указатель на структуру?

  1. Дан код:

int t=5; struct St2 {int *p; } S2;

S2 p=&t; //1

St2.p=&t; //2

S2.p=t; //3

S2.p=new int; S2.(*p)=t; //4

S2.p=new int; *(S2. p)=t; //5

S2 p=new int; *(S2 p)=t; //6

В каких строках( //1 — //6) нет ошибок?

  1. Дан код:

struct St11 {char *C; } S1;

Что нужно записать дополнительно, чтобы оператор S1.C[0]=x; компилировался и выполнялся? Выберите все правильные варианты (14).

1) int n=11; S1.C=new char[n]; char x=’*’;

2) const n=11; S1.C=new char[n]; int x=50;

3) S1.C=new char; char x=50;

4) const n=11; C=new char[n]; int x; cin > > x;

  1. Дан код:

const n=3, k=5, m=10;

struct St10 {char name[m]; char C; float f[k];} *S10, S10A;

S10=&S10A; //1

for(int i=0; i < k; i++) S10A.f[i]=i; //2

St10=new S10; S10 C=’3’; //3

S10=new St10; S10 name[k]=’4’; //4

S10=new St10[m]; S10[k] name=”Borland”; //5

В каких строках (//1 – //5) есть ошибки?

  1. Дан код:

struct St2

{ private: int a, b;

public: void set (int x, int y) {a=x; b=y;}); void show( ) {cout < < a <<” ”< < b;}

}

Правильно ли определена структура? Варианты ответа:

  1. Да.

  2. Да, если удалить обе функции, а поля оставить с атрибутом private.

  3. Да, если поля объявить с атрибутами public, а функции оставить с тем же атрибутом.

  4. Да, если удалить обе функции, а поля объявить с атрибутом public.

  1. Дан код:

const k=5, n=3;

struct St14 {float a[k]; } Sar[n];

Что нужно записать дополнительно, чтобы оператор

S2 a[k-1]=Sar[n-1].a[0];

компилировался и выполнялся? Выберите все правильные варианты .

Варианты ответа: 1) float S2; 2)St14 &S2; 3)St14 *S2; St14=new S2; 4) St14 *S2; S2=new St14; 5)Такой оператор всегда ошибочен.

  1. Дан код:

const k=5, n=3; struct St17 {float a[k]; } Sar[n];

Что нужно записать дополнительно, чтобы оператор

Sar[0].a=x;

компилировался и выполнялся? Выберите все правильные варианты.

Варианты ответа: 1)St17 x; 2)St17 *x; x=new St17;

3)float *x; x=new float[n]; 4) float x[n]; 5)Всегда ошибка.

  1. Дан код:

const k=5; struct St12 {float *a; } Sar[k];

Sar=new St12[k]; //1

Sar=new float[k]; //2

Sar[0].a=new float[k]; //3

Sar[k-1] a=new float[k+1]; //4

Sar[k-1].a=new float[k+1]; //5

Какие операторы (//1//5) правильные?

  1. Дан код:

struct MyPoint {float x, y;};

struct TFig {MyPoint *u; } *Pol3, P18;

Pol1=new TFig; Pol1.u=new MyPoint; //1

Pol2=new TFig[5]; Pol2[4].u=new MyPoint; //2

Pol3=new TFig; Pol3 u=new MyPoint; //3

Pol4=new TFig; Pol4.u=new MyPoint[5]; //4

P18 u=new TFig; P18 u x=1.1; //5

P18 u=new MyPoint; P18.u x=2.2; //6

P18.u=new MyPoint; P18 u.x=3.3; //7

P18.u=new MyPoint[3]; P18.u[0].x=4.4; //8

P18.u=new MyPoint; P18.u x=5.5; //9