36000 секунд прошло сполуночи

*/

// Программа CONST2.CPP, иллюстрирующая формальные константы

#include <iostream.h>

const int SEC_IN_MIN = 60; // глобальная константа

int main()

{

const int MIN_IN_HOUR = 60; // локальная константа

long hours, minutes, seconds;

long totalSec;

cout << "Введите часы: ";

cin >> hours;

cout << "Введите минуты: ";

cin >> minutes;

cout << "Введите секунды: ";

cin >> seconds;

totalSec = ((hours * MIN_IN_HOUR + minutes) *

SEC_IN_MIN) + seconds;

cout << endl << endl << totalSec << " секунд прошло с полуночи" << endl;

return 0;

}

/* Тест и результаты:

Введите часы: 1

Введите минуты: 10

Введите секунды: 20

4220 секунд прошло с полуночи

*/

// Программа OPER1.CPP, иллюстрирующая простые математические операции

#include <iostream.h>

int main()

{

int int1, int2;

long long1, long2, long3, long4, long5;

float x, y, real1, real2, real3, real4;

cout << endl << "Введите первое целое число: ";

cin >> int1;

cout << "Введите второе целое число: ";

cin >> int2;

cout << endl;

long1 = int1 + int2;

long2 = int1 - int2;

long3 = int1 * int2;

long4 = int1 / int2;

long5 = int1 % int2;

cout << int1 << " + " << int2 << " = " << long1 << endl;

cout << int1 << " - " << int2 << " = " << long2 << endl;

cout << int1 << " * " << int2 << " = " << long3 << endl;

cout << int1 << " / " << int2 << " = " << long4 << endl;

cout << int1 << " % " << int2 << " = " << long5 << endl;

cout << endl << endl;

cout << "Веедите первое вещественное число: ";

cin >> x;

cout << "Введите второе вещественное число: ";

cin >> y;

cout << endl;

real1 = x + y;

real2 = x - y;

real3 = x * y;

real4 = x / y;

cout << x << " + " << y << " = " << real1 << endl;

cout << x << " - " << y << " = " << real2 << endl;

cout << x << " * " << y << " = " << real3 << endl;

cout << x << " / " << y << " = " << real4 << endl;

cout << endl << endl;

return 0;

}

/* Тест и результаты:

Введите первое целое число: 10

Введите второе целое число: 5

10 + 5 = 15

10 - 5 = 5

10 * 5 = 50

10 / 5 = 2

10 % 5 = 0

Введите первое вещественное число: 1.25

Введите второе вещественное число: 2.58

1.25 + 2.58 = 3.83

1.25 - 2.58 = -1.33

1.25 * 2.58 = 3.225

1.25 / 2.58 = 0.484496

*/

//Демонстрация операций инкремента и декремента см. в программе OPER2.CPP

// Программа SIZEOF.CPP, которая возвращает размеры данных, используя

// для этого операцию sizeof() с переменными и типами данных.

#include <iostream.h>

int main()

{

short int aShort;

int anInt;

long aLong;

char aChar;

float aReal;

cout << "Таблица 1. Размеры памяти для переменных" << endl

<< endl;

cout << " Тип данных Используемая " << endl;

cout << " память (в байтах)" << endl;

cout << "------------------ -----------" << endl;

cout << " short int " << sizeof(aShort) << endl;

cout << " integer " << sizeof(anInt) << endl;

cout << " long integer " << sizeof(aLong) << endl;

cout << " character " << sizeof(aChar) << endl;

cout << " float " << sizeof(aReal) << endl;

cout << endl << endl << endl;

cout << "Таблица 2. Размеры памяти для типов данных" << endl

<< endl;

cout << " Тип данных Используемая" << endl;

cout << " память (в байтах)" << endl;

cout << "------------------ -----------" << endl;

cout << " short int " << sizeof(short int) << endl;

cout << " integer " << sizeof(int) << endl;

cout << " long integer " << sizeof(long) << endl;

cout << " character " << sizeof(char) << endl;

cout << " float " << sizeof(float) << endl;

cout << endl << endl << endl;

return 0;

}

/* Результаты:

Таблица 1. Размеры памяти для переменных"

Тип данных Используемая

память (в байтах)

------------------ -----------

short int 2

integer 2

long integer 4

character 1

float 4

Таблица 2. Размеры памяти для типов данных

Тип данных Используемая

память (в байтах)

------------------ -----------

short int 2

integer 2

long integer 4

character 1

float 4

*/

// Простая программа TYPECAST.CPP, демонстрирующая приведение типа

#include <iostream.h>

int main()

{

short shortInt1, shortInt2;

unsigned short aByte;

int anInt;

long aLong;

char aChar;

float aReal;

// присваиваются значения

shortInt1 = 10;

shortInt2 = 6;

// действия выполняются без приведения типа

aByte = shortInt1 + shortInt2;

anInt = shortInt1 - shortInt2;

aLong = shortInt1 * shortInt2;

aChar = aLong + 5; // автоматическое преобразование

// в символьный тип

aReal = shortInt1 * shortInt2 + 0.5;

cout << "shortInt1 = " << shortInt1 << endl

<< "shortInt2 = " << shortInt2 << endl

<< "aByte = " << aByte << endl

<< "anInt = " << anInt << endl

<< "aLong = " << aLong << endl

<< "aChar is " << aChar << endl

<< "aReal = " << aReal << endl << endl << endl;

// дейтсвия выполняются с приведением типа

aByte = (unsigned short) (shortInt1 + shortInt2);

anInt = (int) (shortInt1 - shortInt2);

aLong = (long) (shortInt1 * shortInt2);

aChar = (unsigned char) (aLong + 5);

aReal = (float) (shortInt1 * shortInt2 + 0.5);

cout << "shortInt1 = " << shortInt1 << endl

<< "shortInt2 = " << shortInt2 << endl

<< "aByte = " << aByte << endl

<< "anInt = " << anInt << endl

<< "aLong = " << aLong << endl

<< "aChar is " << aChar << endl

<< "aReal = " << aReal << endl << endl << endl;

return 0;

}

/* Результаты:

shortInt1 = 10

shortInt2 = 6

aByte = 16

anInt = 4

aLong = 60

aChar is A

aReal = 60.5

shortInt1 = 10

shortInt2 = 6

aByte = 16

anInt = 4

aLong = 60

aChar is A

aReal = 60.5

*/

/* *** ВОПРОСЫ И ОТВЕТЫ ***

Существуют ли особые соглашения о присвоении имен идентификаторам?

Существует несколько стилей, которые стали популярными в последние

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

имя переменной с символа, набранного в нижнем регистре. Если идентифи-

катор состоит из нескольких слов, как, например, numberOfElements,

набирайте первый символ каждого последующего слова в верхнем реги-

стре.

Как реагирует компилятор, если вы объявляете переменную, но никогда не

присваиваете ей значения?

Компилятор выдает предупреждение, что на переменную нет ссылок.

Каково булево выражение для проверки того, что значение переменной i

находится в заданном диапазоне значений (например, определяемом пере-

менными lowVal и hiVal)?

Выражением, которое определяет, находится ли значение переменной i

в некотором диапазоне, является (i >= lowVal && i <= hiVal).

2.    Конструкции принятия решений и циклы ВОПРОСЫ И ОТВЕТЫ

Предъявляет ли С++ какие-либо требования на отступ операторов в предложениях оператора?

Нет. Отступ определяется только Вами. Типовые размеры отступа составляют два или четыре пробела. Использование отступов делает ваш листинг намного более удобочитаемым.

Вот пример оператора if с записью предложений без отступа:

if ( i > 0 )

j = i * 1;

else

j = 10 - i;

Сравните этот листинг и его вариант с отступами

if ( i > 0 )

j = i * i;

else

j = 10 - i;

Последний вариант читается много легче; легко указать, где операторы if и else. Более того, если вы будете работать с вложенными циклами, отступы еще более значимы в отношении удобочитаемости кода.

Каковы правила написания условий в операторе if-else?

 Здесь существуют два подхода. Первый рекомендует писать условия так, что true будет чаще, чем false. Второй подход рекомендует избегать отрицательных выражений (тех, которые используют операции сравнения != и булевы операции !).

Программисты из последнего лагеря преобразуют такой оператор if:

if ( i != 0 )

j = 100/i;

else

j = 1;

в следующую эквивалентную форму:

if ( i == 0 )

j = 1;

else

j = 100/i;

хотя вероятность равенства нулю переменной i достаточно низка.

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

if ( i != 0 && 1/i > 1 )

j = i * i;

С++ не всегда оценивает проверяемые условия полностью. Эта частичная оценка происходит, когда член булева выражения превращает все выражение в false или true, независимо от значения других членов. В этом случае, если переменная i равна 0, исполняющая система не будет оценивать 1/i > 1, потому что член i != 0 есть false и обращает в false все выражение, независимо от значения второго члена. Это называется укороченной оценкой булевых выражений.

Действительно ли необходимо включать предложения else или default в многоальтернативные операторы if-else и switch?

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

Как смоделировать цикл while циклом for?

Рассмотрим простой пример.

int i; int i = 1;

for (i=1; i<=10; i+=2) { while ( i <= 10) {

cout << i << endl; cout << i << endl;

} i += 2;

}

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

Как смоделировать цикл while циклом do-while?

Рассмотрим простой пример.

i = 1; i = 1;

do { while (i <= 10) {

cout << i << endl;  cout << i << endl;

i += 2; i += 2;

} while (i <= 10); }

Оба цикла имеют одинаковые условия в предложениях while.

Заметим, однако, что если цикл спроектирован таким образом, что начальное значение i может быть неизвестным заранее, то это может привести к различным эффектам. Например, если i исходно равно 11, то цикл слева выполнится один раз, тогда как цикл справа не сделает ни одной итерации.

Как открытый цикл for может эмулировать циклы while и do-while?

Открытый цикл for эмулирует другие циклы С++ установкой оператора if выхода из цикла в начале или конце цикла. Рассмотрим пример эмуляции цикла while открытым циклом for:

i = 1; i = 1;

while (i <= 10) { for (;;) {

if (i > 10) break;

cout << i << endl; cout << i << endl;

i += 2; i += 2;

} }

Заметим, что открытый цикл for использует оператор if выхода из цикла как первый оператор внутри цикла. Условие, проверяемое оператором if, есть логическое обращение условия цикла while.

Рассмотрим простой пример, иллюстрирующий эмуляцию цикла do-while:

i = 1; i = 1;

do { for (;;) {

cout << i << endl; cout << i << endl;

if (i > 10) break;

i += 2; i += 2;

} while (i <= 10) }

Открытый цикл for использует оператор if выхода из цикла перед концом цикла. Оператор if проверяет обратное логическое условие, так же как в цикле do-while. Однако имейте, пожалуйста, в виду, что приведенные примеры довольно грубы и неэлегантны. Никто никогда не будет использовать открытый оператор for подобным образом. Конечно, можно было бы пропустить одно из трех предложений внутри скобок цикла for (например, предложение инициализации, если управляющая переменная уже инициализирована). Открытые циклы for чаще всего используются в случаях, когда выход из цикла бывает редким событием, например, если при обработке данных, вводимых пользователем с клавиатуры, нажатие клавиши Esc должно приводить к выходу из программы.

Можно ли во вложенном цикле for использовать переменную управления внешним циклом в качестве границы диапазона значений для внутренних циклов?

Да. С++ не только не запрещает такое использование, на самом деле

оно в порядке вещей. Рассмотрим простой пример.

for ( int i = 1; i <= 100; i += 5)

for ( int j = i; i <= 100; j++)

cout < i * j << endl;

Ограничивает ли С++ вложение циклов разных типов?

Нет. В программе на С++ вы можете вкладывать любые комбинации

циклов.

СТРУКТУРА ПРОГРАММЫ

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

Исходная программа

Исходная программа- это совокупность следующих об"ектов: директив, указаний компилятору, об"явлений и определений. Дирек­тивы задают действия препроцессора по преобразованию текста прог­раммы перед компиляцией. Указания компилятору- это команды, вы­полняемые компилятором во время процесса компиляции. Об"явления задают имена и атрибуты переменных, функций и типов, используемых в программе. Определения- это об"явления, определяющие переменные и функции.

Определение переменной в дополнении к ее имени и типу зада­ет начальное значение об"явленной переменной. Кроме того, опреде­ление предполагает распределение памяти для переменной.

Определение функции специфицирует ее структуру, которая

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

Исходная программа может содержать любое число директив,

указаний компилятору, об"явлений и определений. Любой из об"ектов программы имеет определенный синтаксис, описанный в этом руковод­стве,и каждая составляющая может появляться в любом порядке, хотя влияние порядка, в котором следуют переменные и функции может быть использовано в программе (см. раздел 3.5 "Время жизни и ви­димость").

Нетривиальная программа всегда содержит более одного опре­деления функции. Функция определяет действия, выполняемые прог­раммой.

В следующем примере иллюстрируется простая исходная прог­рамма на языке Си.

int x = 1;/* Variable definitions */

int y = 2;

extern int printf(char *,...);/* Function declaration */

main () /* Function definition for main function */

{

int z; /* Variable declarations */

int w;

z = y + x; /* Executable statements */

w = y - x;

printf("z = %d \nw = %d \n", z, x);

}

Эта исходная программа определяет функцию с именем main и об"являет функцию printf. Переменные x и y задаются своими опре­делениями. Переменные z и w только об"являются.

ОБЪЯВЛЕНИЯ

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

[<sc-specifier>][<type-specifier>]<declarator>[=<initializer>] [,<declarator>[=<initializer>...],

где:

<sc-specifier>- спецификатор класса памяти; <type-specifier>- имя определяемого типа;

<declarator>- идентификатор, который может быть модифициро­ван при об"явлении указателя, массива или функции;

<initializer>- задает значение или последовательность зна­чений, присваиваемых переменной при об"явлении.

Все переменные Си должны быть явно об"явлены перед их ис­пользованием. Функции Си могут быть об"явлены явно или неявно в случае их вызова перед определением.

Язык Си определяет стандартное множество типов данных. К этому множеству можно добавлять новые типы данных посредством их

об"явлений на типах данных уже определенных.

Об"явление Си требует одного или более деклараторов. Декла­ратор- это идентификатор, который может быть определен с квадрат­ными скобками ([]), эвездочкой (*) или круглыми скобками () для об"явления массива, указателя или функции. Когда об'является простая переменная (такая как символ, целое или плавающее), структура или совмещение простых переменных, то декларатор- это идентификатор.

В Си определено четыре спецификатора класса памяти, а имен­но: auto, extern, register и static.

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

Об"явления функций описаны в разделе 4.4.

Спецификаторы типов

Язык Си поддерживает определения для множества базовых ти­пов данных, называемых "основными" типами. Названия этих типов перечислены в Табл. 4.1.

------------------------------------------------------------

Типы целых Типы плавающих Другие типы

------------------------------------------------------------

signed char float void

signed int double

signed short intsigned long int

unsigned char

unsigned int

unsignet short int unsigned long int

-----------------------------------------------------------

Табл. 4.1. Основные типы.

Перечислимые типы также рассматриваются как основные типы. Спецификаторы перечислимых типов рассмотрены в разделе 4.7.1. Ти­пы signed char, signed int, signed short int и signed long int

вместе с соответствующими двойниками unsigned называются типами целых.

Спецификаторы типов float и double относятся к типу "плава­ющих". В об"явлениях переменых и функций можно использовать любые спецификаторы "целый" и "плавающий".

Тип void может быть использован только для об"явления функ­ций, которые не возвращают значения. Типы функций рассмотрены в разделе 4.4.

Можно задать дополнительные спецификаторы типа путем об"яв­ления typedef, описанного в разделе 4.7.2.

При записи спецификаторов типов допустимы сокращения как показано в табл. 4.2. В целых типах ключевое слово signed может быть опущено. Так, если ключевое слово unsigned опускается в за­писи спецификатора типа, то тип целого будет знаковым, даже если опущено ключевое слово signed.

В некоторых реализациях могут быть использованы опции ком­пилятора, позволяющие изменить умолчание для типа char со знако­вого на беззнаковый. Когда задана такая опция, сокращение char имеет то же самое значение, что и unsigned char, и следовательно ключевое слово sidned должно быть записано при об"явлении сим­вольной величины со знаком.

-----------------------------------------------------------

Спецификатор типа Сокращение

-----------------------------------------------------------

signed char char

signed int signed, int

signed short int short, signed short

signed long int long, signed long

unsigned char -

unsigned int unsigned

unsigned short int unsignet short

unsignet long int unsignet long

float -

long float double

------------------------------------------------------------

Табл. 4.2. Спецификаторы и сокращения

Замечание: в этом руководстве в основном используются сок­ращенные формы, перечисленные в Табл. 4.2, при этом предполагает­ся, что char по умолчанию знаковый.

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

-----------------------------------------------------------

Тип Представление Область значений

в памяти величины

-----------------------------------------------------------

char 1 байт -128 до 127

int зависит от

реализации

short 2 байта -32768 до 32767

long 4 байта -2.147.483.648 до 2.147.483.647

unsigned char 1 байт 0 до 255

unsigned зависит от

реализации

unsigned short 2 байта 0 до 65535

unsigned long 4 байта 0 до 4.294.967.295

float 4 байта IEEE стандартное

соглашение

double 8 байт IEEE стандартное

соглашение ------------------------------------------------------------

Табл 4.3 Размер памяти и область значений типов

Тип char используется для запоминания буквы, цифры или сим­вола из множества представимых символов. Значением об"екта типа char является ASCII код, соответствующий данному символу. Так как тип char интерпретируется как однобайтовая целая величина с об­ластью значений от -128 до 127, то только величины от 0 до 127

имеют символьные эквиваленты. Аналогично, тип unsigned char может запоминать величины с областью значений от 0 до 255.

Заметим, что представление в памяти и область значений для типов int и unsigned int не определены в языке Си. По умолчанию размер int (со знаком и без знака) соответствует реальному разме­ру целого на данной машине. Например, на 16-ти разрядной машине тип int всегда 16 разрядов или 2 байта. На 32-ух разрядной машине тип int всегда 32 разряда или 4 байта. Таким образом, тип int эк­вивалентен типам short int или long int в зависимости от реализа­ции.

Аналогично, тип unsigned int эквивалентен типам unsigned short или unsigned long. Спецификаторы типов int и unsigned int широко используются в программах на Си, поскольку они позволяют наиболее эффективно манипулировать целыми величинами на данной машине.

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

Деклараторы

Синтаксис:

<identifier>

<declarator>[]

<declarator>[constant-expression>]

*<declarator>

<declarator>()

<declarator>(<arg-type-list>)

(<declarator>)

Си позволяет об"являть: массивы величин, указатели на вели­чины, величины возвратов функций. Чтобы об"явить эти об"екты, нужно использовать декларатор, возможно модифицированный квадрат­ными скобками ([]), круглыми скобками () и звездочкой (*), что соответствует типам массива, функции или указателя. Деклараторы появляются в об"явлениях указателей, массивов и функций.

Деклараторы массивов, функций и указателей

Когда декларатор состоит из немодифицируемого идентификато­ра, то об'ект, который об"является, имеет немодифицированный тип. Звездочка, которая может появиться слева от идентификатора, моди­фицирует его в тип указателя. Если за идентификатором следуют квадратные скобки ([]), то тип модифицируется на тип массива. Ес­ли за идентификатором следуют круглые скобки, то тип модифициру­ется на тип функции. Сам по себе декларатор не образует полного об"явления. Для этого в об"явление должен быть включен специфика­тор типа. Спецификатор типа задает тип элементов массива или тип адресуемых об"ектов и возвратов функции.

Следующие примеры иллюстрируют простейшие формы декларато­ров:

1. int list[20]

2. char *cp

3. double func(void),

где:

1. Массив list целых величин

2. Указатель cp на величину типа char

3. Функция func без аргументов, возвращающая величину double

Составные деклараторы

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

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

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

char *(*(*var) ()) [10];

^ ^ ^ ^ ^ ^ ^

7 6 4 2 1 3 5

1. Идентификатор var об'явлен как

2. Указатель на

3. Функцию, возвращающую

4. Указатель на

5. Массив из 10 элементов, который состоит 6. Из указателей на

7. Величины типа char.

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

1. int *var[5]; - массив указателей на величины типа int.

2. int (*var)[5]; - указатель на массив величин типа int.

3. long *var(long,long); - функция, возвращающая указатель на величину типа long.

4. long (*var) (long,long); - указатель на функцию, возвра­щающую величину типа long.

5. struct both {

int a;

char b;

} ( *var[5] ) ( struct both, struct both); массив указателей на функции, возвращающих структуры.

6. double ( *var( double (*) [3] ) ) [3];

функция, возвращающая указатель на массив из трех величин типа double.

7. union sign {

int x;

unsigned y;

} **var[5] [5];

массив массивов указателей на указатели совмещений.

8. union sign *(*var[5]) [5];

массив указателей на массив указателей на совмещения.

Описание примеров:

В первом примере, модификатор массива имеет высший приори­тет, чем модификатор указателя, так что var об"является массивом. Модификатор указателя определяет тип элементов массива; элемента­ми являются указатели на величины типа int.

Во втором примере скобки меняют значение об"явления первого примера. Теперь модификатор указателя имеет более высокий приори­тет, чем модификатор массива, и переменная var об"является как указатель на массив из пяти величин типа int.

В третьем примере модификатор функции имеет более высокий приоритет, чем модификатор указателя, так что переменная var об"является функцией, возвращающей указатель на величину типа long. Функция об"явлена с двумя аргументами типа long.

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

Элементы массива не могут быть функциями. Взамен этому в пятом примере показано, как об"явить массив указателей на функ­ции. В этом примере переменная var об"явлена как массив из пяти указателей на функции, возвращающие структуры с двумя элементами. Оба аргумента функции об"явлены как структуры типа both. Заметим, что круглые скобки, в которые заключено выражение *var[5], обяза­тельны. Без них об"явление будет неверным, поскольку будет об"яв­лен массив функций:

/* ILLEGAL */

struct both *var[5] ( struct both, struct both );

В шестом примере показано, как об"являть функцию, возвраща­ющую указатель на массив. Здесь var об"явлена функцией, возвраща­ющей указатель на массив из трех величин типа double. Тип аргу­мента функции задан составным абстрактным декларатором. Круглые скобки, заключающие звездочку, требуются, так как в противном случае типом аргумента был бы массив из трех указателей на вели­чины типа double.

В седьмом примере показано, что указатель может указывать на другой указатель и массив может состоять из массивов. Здесь var- это массив из пяти элементов. Каждый элемент, в свою оче­редь, так же массив из пяти элементов, каждый из которых является указателем на указатель совмещения, состоящего из двух элементов.

В восьмом примере показано, как круглые скобки изменили

смысл об"явления. В этом примере var- это массив из пяти указате­лей на массив из пяти указателей на совмещения.

Об"явления переменной

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

Тип переменной Описание

Простая переменная Переменная целого или плаваю-

щего типа.

Переменная перечис- Простая переменная целого типа

ления. которая принимает значения из

предопределенного набора зна-

чений поименованных констант. Структура Переменная, которой соответс-

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

Совмещение Переменная, которой соответс-

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

Массив Переменная, представляющая на-

бор элементов одного типа.

Указатель Переменная, которая указывает

на другую переменную (содержит местоположение другой перемен­ной в форме адреса).

Общий синтаксис об"явлений переменных следующий:

[<sc-spesifier>] <type-spesifier> <declarator> [,<declarator>...],

где <type- spesifier> - задает тип данных, представляемых переменной, а <declarator> - это имя переменной, возможно модифи­цированное для об"явления массива или указателя. В об"явлении мо жет быть задана более чем одна переменная путем задания множест­венного об"явления, в котором деклараторы разделены запятыми. <sc- spesifier> задает класс памяти переменной. В некоторых слу­чаях переменные могут быть инициализированы при их определении. Классы памяти и инициализация описаны в разделах 4.6 и 4.7 соот­ветственно.

Объявление простой переменной

Синтаксис:

<type-specifier><identifier>[,<identifier>...];

Об"явление простой переменной определяет имя переменной и ее тип; оно может также определять класс памяти переменной, как это описано в разделе 4.6. Имя переменной- это идентификатор, за­данный в об"явлении. Спецификатор типа <type-specifier> задает имя определяемого типа данных.

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

Примеры

int x; /* Example 1 */

unsigned long reply, flag /* Example 2 */ double order; /* Example 3 */

В первом примере об"является простая переменная x. Эта пе-

ременная может принимать любое значение из множества значений, определяемых для типа int.

Во втором примере об"явлены две переменные: reply и flag. Обе переменные имеют тип unsigned long.

В третьем примере об"явлена переменная order, которая имеет тип double. Этой переменной могут быть присвоены величины с пла­вающей запятой.

Объявление перечисления

Синтаксис: enum[<tag>]{<enum-list>}<identifier>[,<identifier>...]; enum<tag><identifier>[,<identifier>...];

Об"явление перечисления задает имя переменной перечисления и определяет список именованных констант, называемый списком пе­речисления. Значением каждого имени списка является целое число. Переменная перечисления принимает значение одной из именованных констант списка. Именованные константы списка имеют тип int. Та-

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

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

имеет две формы представления. В первой форме представления имена перечисления задаются в списке перечисления <enum-list>.

Опция <tag>- это идентификатор, который именует тип пере­числения, определенного в <enum-list>.

Переменную перечисления именует <identifier>. В об"явлении может быть описана более чем одна переменная перечисления.

Во второй форме используется тег перечисления, который ссы-

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

<enum-list> имеет следующий синтаксис:

<identifier>[=<constant-expression>][,<identifier>

[=<constant-expression]]...

.

.

.

Каждый идентификатор именует элементы перечисления. По умолчанию первому идентификатору соответствует значение 0, следу­ющий идентификатор ассоциируется со значением 1 и т. д. Имя конс­танты перечисления эквивалентно ее значению.

Запись =<constant-expression> переопределяет последователь­ность значений, заданных по умолчанию. Идентификатор, следующий перед записью =<constant-expression> принимает значение, задавае­мое этим константным выражением. Константное выражение имеет тип int и может быть отрицательным. Следующий идентификатор в списке ассоциируется с величиной, равной <constant-expression>+1, если он явно не задается другой величиной.

Перечисление может содержать повторяющиеся значения иденти­фикаторов, но каждый идентификатор должен быть уникальным. Кроме того, он должен быть отличным от всех других идентификаторов пе­речислений с той же видимостью. Например, двум различным иденти­фикаторам null и zero может быть задано значение 0 в одном и том же перечислении. Идентификаторы должны быть отличны от других идентификаторов с той же самой видимостью, включая имена обычных переменных и идентификаторы других перечислений. Теги перечисле­ний должны быть отличны от тегов перечислений, тегов структур и совмещений с той же самой видимостью.

Примеры:

/**************** Example 1 ***************/

enum day {

saturday,

sunday = 0,

monday,

tuesday,

wednesday,

thursday,

friday

} workday;

/***************** Example 2 ***************/

enum day today = wednesday;

В первом примере определяется тип перечисления, поименован­ный day и об"является переменная workday этого типа перечисления. С saturday по умолчанию ассоциируется значение 0. Идентификатор sunday явно устанавливается в 0. Оставшиеся идентификаторы по умолчанию принимают значение от 1 до 5.

Во втором примере переменной today типа enum day присваива­ется значение из перечисления. Заметим, что для присваивания ис­пользуется имя константы из перечисления. Так как тип перечисле­ния day был предварительно об"явлен, то достаточно сослаться только на тег перечисления.

Объявления структур

Синтаксис: struct[<tag>]{<member-declaration-list>}<declarator>[,<declarator>...]; struct<tag><declarator>[,<declarator>...];

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

Об"явление структуры начинается с ключевого слова struct и имеет две формы представления, как показано выше. В первой форме представления типы и имена элементов структуры специфицируются в списке об"явлений элементов <member-declaration-list>. <tag>- это идентификатор, который именует тип структуры, определенный в списке об"явлений элементов.

Каждый <declarator> задает имя переменной типа структуры. Тип переменной в деклараторе может быть модифицирован на указа­тель к структуре, на массив структур или на функцию, возвращающую структуру.

Вторая синтаксическая форма использует тег- <tag> структуры для ссылки на тип структуры. В этой форме об"явления отсутствует список об"явлений элементов, поскольку тип структуры определен в другом месте. Определение типа структуры должно быть видимым для тега, который используется в об"явлении и определение должно предшествовать об"явлению через тег, если тег не используется для об"явления указателя или структурного типа typedef. В последних случаях об"явления могут использовать тег структуры без предвари­тельного определения типа структуры, но все же определение должно находиться в пределах видимости об"явления.

Список об"явлений элементов <member-declaration-list>- это одно или более об"явлений переменных или битовых полей. Каждая

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

Элемент не может иметь тип структуры, в которой он появля­ется. Однако, элемент может быть об"явлен, как указатель на тип структуры, в которую он входит, позволяя создавать списочные структуры.

Битовые поля

Об"явления битовых полей имеют следующий синтаксис:

<type-specifier>[<identifier>]:<constant-expression>; Битовое поле состоит из некоторого числа бит, специфициро-

ванных константным выражением- <constant- expression>. Для бито-

вого поля спецификатор типа <type- specifier> должен специфициро-

вать беззнаковый целый тип, а константное выражение должно быть неотрицательной целой величиной. Массивы битовых полей, указатели на битовые поля и функции, возвращающие битовые поля не допуска­ются. Идентификатор- <identifier> именует битовое поле. Неимено­ванное битовое поле, чей размер специфицируется как нулевой, име­ет специальное назначение: оно гарантирует, что память для следу­ющей переменной об"явления будет начинаться на границе int.

Идентификаторы элементов внутри об"являемой структуры должны быть уникальными. Идентификаторы элементов внутри разных структур могут совпадать. В пределах той же самой видимости теги структур должны отличаться от других тегов (тегов других струк­тур, совмещений и перечислений).

Переменные (элементы) структуры запоминаются последователь­но в том же самом порядке, в котором они об"являются: первой пе­ременной соответствует самый младший адрес памяти, а последней­самый старший. Память каждой переменной начинается на границе свойственной ее типу. Поэтому могут появляться неименованные участки между соседними элементами.

Битовые поля не располагаются на пересечении границ, обяв­ленных для них типов. Например, битовое поле, об"явленое с типом unsigned int, упаковывается или в пространстве, оставшимся от предидущего unsigned int или начиная с нового unsigned int.

Примеры

/**************** Example 1 ****************/

struct {

float x,y;

} complex;

/**************** Example 2 *****************/

struct employee {

char name[20];

int id;

long class;

} temp;

/**************** Example 3 ******************/

struct employee student, faculty, staff;

/**************** Example 4 ******************/ struct sample {

char c;

float *pf;

struct sample *next;

} x;

/***************** Example 5 ******************/

struct {

unsigned icon : 8;

unsigned color : 4; unsigned underline : 1; unsigned blink : 1;

} screen[25][80];

В первом примере об"является переменная с именем complex типа структура. Эта структура состоит из двух элементов x и y ти­па float. Тип структуры не поименован.

Во втором примере об"является переменная с именем temp типа структура. Структура состоит из трех элементов с именами name, id и class. Элемент с именем name- это массив иэ 20- ти элементов типа char. элементы с именами id и class- это простые переменные типа int и long соответственно. Идентификатор employee является тегом структуры.

В третьем примере об"явлены три переменных типа структура с именами: student, faculty и staff. Каждая из структур состоит из трех элементов одной и той же конструкции. Элементы определены при об"явлении типа структуры с тегом employee в предыдущем примере.

В четвертом примере об"является переменная с именем x типа структура. Первые два элемента структуры представлены переменной c типа char и указателем pf на величину типа float. Третий эле­мент с именем next об"являются как указатель на описываемую структуру sample.

В пятом примере об"является двумерный массив поименованный screen, элементы которого имеют структурный тип. Массив состоит из 2000 элементов и каждый элементэто отдельная структура, состо­ящая из четырех элементов типа bit-fild с именами icon, color, underline и blink.

Об"явление совмещений

Синтаксис: union[<tag>]{<member-declaration-list>}<declarator>[,<declarator>...]; union<tag><declarator>[,<declarator>...];

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

Об"явление совмещения имеет тот же самый синтаксис, как и об"явление структуры, за исключением того, что она начинается с ключевого слова union вместо ключевого слова struct. Для об"явле­ния совмещения и структуры действуют одни и те же правила, за ис­ключением того, что в совмещении не допускаются элементы типа би­товых полей.

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

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

Примеры:

/************** Example 1 ********************/

union sign {

int svar;

unsigned uvar;

} number;

/************** Example 2 ********************/

union {

char *a, b;

float f[20];

} jack;

/*************** Example 2 *******************/

union {

struct {

char icon;

unsigned color : 4;

} window1, window2, window3, window4;

} screen[25][80];

В первом примере об"является переменная типа совмещения, поименованная number. Список элементов совмещения состоит из двух

об"явлений переменных: svar типа int и uvar типа unsigned. Это об"явление позволяет запоминать текущее значение number в знако­вом или беззнаковом виде. Тип совмещения поименован идентификато­ром sign.

Во втором примере об"является переменная типа совмещения с именем jack. Список элементов об"явления состоит из трех об"явле­ний: указателя a на величину типа char, переменной b типа char и массива f из 20 элементов типа float. Тип совмещения не поимено­ван.

Память, распределенная для переменной jack, равна памяти, распределенной под массив f, поскольку f самый большой элемент совмещения.

В третьем примере об"является двумерный массив совмещений с именем screen. Массив состоит из 2000 об"ектов. Каждый об"ект­это отдельное совмещение из четырех элементов: window1, window2, window3, window4, где каждый элемент- это структура. В любое за­данное время каждый об"ект совмещения поддерживается одним из че­тырех возможных элементов типа структура. Таким образом, перемен­ная screen- это композиция четырех возможных "windows".

Об"явление массива

Синтаксис: <type-specifier><declarator>[<constant-expression>]; <type-specifier><declarator>[];

Здесь квадратные скобки- это терминальные символы. Об"явле­ние массива определяет тип массива и тип каждого элемента. Оно может определять также число элементов в массиве. Переменная типа массив рассматривается как указатель на элементы массива. Об"яв­ление массива может представляться в двух синтаксических формах, указанных выше. Декларатор<declarator> задает имя переменной. Квадратные скобки, следующие за декларатором, модифицируют декла­ратор на тип массива. Константное выражение

<constant-expression>, заключенное в квадратные скобки, определя­ет число элементов в массиве. Каждый элемент имеет тип, задавае­мый спецификатором типа <type-specifier>, который может специфи­цировать любой тип, исключая void и тип функции.

Во второй синтаксической форме опущено константное выраже­ние в квадратных скобках. Эта форма может быть использована толь­ко тогда, когда массив инициализируется или об"явлен как формаль­ный параметр или об"явлен как ссылка на массив, явно определенный где-то в программе.

Массив массивов или многомерный массив определяется путем задания списка константных выражений в квадратных скобках, следу­щего за декларатором:

<type-specifier><declarator>[<constant-expression>]

[<constant-expression>]...

Каждое константное выражение- <constant-expression> в квад­ратных скобках определяет число элементов в даннном иэмерении

массива, так что об"явление двумерного массива содержит два конс­тантных выражения, трехмерного- три и т.д. Если многомерный мас­сив об"является внутри функции или если он инициализируется либо об"является как формальный параметр или об"является как ссылка на

массив, явно определенный где- то в программе, то первое констан­тное выражение может быть опущено.

Массив указателей на величины,заданного типа, может быть определен посредством составного декларатора, как было описано в разделе 4.3.2.

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

char A[2][3]

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

Примеры:

/*************** Example 1 ******************/

int scores[10], game;

/*************** Example 2 ******************/

float matrix[10][15];

/*************** Example 3 ******************/

struct {

float x,y;

} complex[100];

/*************** Example 4 *******************/

char *name[20];

В первом примере об"является переменная типа массив с име­нем scores из 10 элементов типа int. Переменная с именем game об"явлена как простая переменная целого типа.

Во втором примере об"является двумерный массив с именем matrix. Массив состоит из 150-ти элементов типа float.

В третьем примере об"является массив структур. Массив сос­тоит из 100 об"ектов. Каждый об"ект массива представляет собой структуру, состоящую из двух элементов.

В четвертом примере об"явлен массив указателей. Массив сос­тоит из 20-ти элементов, каждый из которых является указателем на величину типа char.


Информация о работе «Лекции по C++»
Раздел: Информатика, программирование
Количество знаков с пробелами: 229074
Количество таблиц: 6
Количество изображений: 0

Похожие работы

Скачать
20747
1
0

... (изложение), аналитический (что мы узнали? Как это можно применить в своих знаниях, в практике, в дальнейшей жизни?…), дискуссионный методы («Порассуждаем?»). Дидактические требования к лекции, методика её подготовки и чтения. Безусловно, помимо таких составляющих, как личность учителя, знание им предмета, эрудиция, на результат, итоговый выход проведения лекции, будет оказывать её основная ...

Скачать
33311
7
3

... вес, объем, урожайность. Абсолютная шкала является безразмерной шкалой отношений. Тема 2. Вариационные ряды. Пример 1. Приведем оценки 45 студентов по курсу статистика в порядке сдачи экзамена: 5 3 3 4 2 4 4 3 5 4 4 5 5 4 4 3 3 3 2 5 5 4 4 4 3 4 3 4 5 4 4 4 4 3 3 4 3 4 3 2 3 2 3 3 3 При таком представлении информации трудно делать какие-либо выводы об успеваемости. Произведем группировку данным ...

Скачать
18566
0
0

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

Скачать
41331
2
0

... – 5); ·           принцип приоритета общечеловеческих ценностей перед профессиональными (4). Очевидно, что данное деление условно, но оно удобно для классификации. Заключение Лекции присущи три основные педагогические функции, которые определяют ее возможности в учебном процессе: познавательная, развивающая и организующая. Познавательная функция выражается в возможности средствами лекции ...

0 комментариев


Наверх