Лекции по C++

Астраханский государственный технический университет



Кафедра   «Информационных
технологий и коммуникаций»



Конспект лекций по дисциплине

 «Основы алгоритмического языка С++»

для специальности 220200.



Астрахань 2000 г.


1. Переменные и операции языка С++  4

  ИЗУЧАЕМЫЕ ПОНЯТИЯ  5
  Буквы и цифры 6
   Пробельные символы  6
   Знаки пунктуации и специальные символы  6
   ESC- последовательности 8
   Операции   9
  Константы 11
   Целые константы  11
   Константы с плавающей точкой   13
   Константа-символ 14
   Строковые литералы  14
  Идентификаторы   15
  Ключевые слова   15
  Комментарии 16
  Лексемы 17
  ИСХОДНЫЕ ТЕКСТЫ ПРИМЕРОВ  17

2. Конструкции принятия решений и циклы 23

  ВОПРОСЫ  И ОТВЕТЫ  23

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

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

ОБЪЯВЛЕНИЯ  27

  Спецификаторы типов  28
  Деклараторы 30
   Деклараторы массивов, функций и указателей  30
   Составные деклараторы 31
   Об"явления переменной 33
   Объявление простой переменной  34
   Объявление перечисления 34
   Объявления структур 36
   Битовые поля 37
   Об"явление совмещений 38
   Об"явление массива  39
   Об"явление функций  42
   Классы памяти  45
   Об"явления переменной на внешнем уровне 45
   Об"явление переменной на внутреннем уровне  48
   Об"явление функции на внешнем и внутреннем уровнях 49
   Инициализация  50
   Базовые типы и типы указателей 50
   Составные типы 51
   Строковые инициализаторы  53
  Об"явления типов 54
   Типы структур, совмещений и перечислений  54
   Об"явления typedef  55
  Имена типов 56
  КОНТРОЛЬНЫЕ ВОПРОСЫ: 57

Функции  57

  Объявление и определение функций  58
  ТИПОВЫЕ ВОПРОСЫ С ОТВЕТАМИ  62
  ПРАКТИКУМ 62
   Контрольные вопросы 62

Массивы  65

  СОРТИРОВКА массива - ПРИМЕР в файле list6_4cpp. 67
  -  ПОИСК в массиве 67
   БИБЛИОТЕЧНЫЕ ФУНКЦИИ ПОИСКА и СОРТИРОВКИ в непрерывных массивах:  68

Строки и управление вводом/выводом  69

  Форматированный потоковый вывод 70
   Листинг 1. Исходный текст программы OUT1.CPP  70

Функция printf  71

  Функция printf   72
  Таблица 1. Еsс - последовательности  72
  Таблица 7.2. Значения флагов строки формата функции printf 72
  Таблица 3. Символы типов данных строки формата функции printf  73
   Листинг 3. Исходный текст программы OUT2.CPP в файле List7-3.CPP  74
   Таблица 4. Результат  действия  спецификаций  форматирования  в  функции
   printf из строки 13 75

Ввод строк  76

  Функция getline  76

Присвоение значений строкам  77

  Инициализация строки 77
  Функция strcpy   77
  Функция strdup   77
  Функция strncpy  78

Определение длины строки 78

  Функция strlen   78
  Функция strcat   78
  Функция strncat  79
  Сравнение строк  79
  Функция strcmp   79
   Пример  80
  Функция stricmp  80
   Пример  80
  Функция strncmp  80
   Пример  80
   Пример  81
  (см. List7_5.cpp - Исходный текст программы STRING2.CPP) 81

Преобразование строк   81

  Функция strlwr   81
   Пример  81
  Функция strupr   81
   Пример  81

Обращение строк 82

  Функция strrev   82

Поиск символов  82

  Функция strchr   82
  Функция strrchr  82
   Пример  83
  Функция Strspn   83
   Пример  83
  Функция strcspn  83
   Пример  83
  Функция strpbrk  83
   Пример  84

Поиск строк 84

  Функция strstr   84
   Пример  84
  Функция strtok   84
  Пример  84

Основы   объектно-ориентированного   программирования   СИНТАКСИС   ОСНОВНЫХ
КОНСТРУКЦИЙ 85

  Объявление базовых классов  85
  Конструкторы  88
  Деструкторы 90
  Объявление иерархии классов 91
  Виртуальные функции  92
  Дружественные функции  95
  Операции и дружественные операции 96
  Виртуальные функции  97
  Правило виртуальной функции 99
  Операции и дружественные операции 101
  ИСХОДНЫЕ ТЕКСТЫ ПРИМЕРОВ  103
  ВОПРОСЫ И ОТВЕТЫ 103
  Контрольные вопросы  104

ФАЙЛОВЫЕ ОПЕРАЦИИ ВВОДА/ВЫВОДА  105

  Stream-библиотека C++  105
  ОБЩИЕ ФУНКЦИИ ПОТОКОВОГО ВВОДА/ВЫВОДА  106
   Функция-компонент open  106
   Функция-компонент close 107
  ПОСЛЕДОВАТЕЛЬНЫЙ ТЕКСТОВЫЙ ПОТОК ВВОДА/ВЫВОДА 107
   Функция-элемент getline 108
  ПОСЛЕДОВАТЕЛЬНЫЙ ДВОИЧНЫЙ ФАЙЛОВЫЙ ВВОД/ВЫВОД 109
   Функция-элемент write 110
   Функция-элемент read  110
  Файловый ввод/вывод с прямым доступом  113
   Функция-элемент seekg 113
  Заключение  115
  Вопросы и ответы 115
  Практикум 116
   Контрольные вопросы 116
   Упражнение 116



   Переменные и операции языка С++


   Здесь представлены базовые компоненты программ на С++. В их число
входят типы данных, переменные, константы и выражения.


ИЗУЧАЕМЫЕ ПОНЯТИЯ


   - Предопределенные типы данных в С++ включают в себя типы int, char,
float, double и void. В языке С++ гибкость типов данных увеличивается
благодаря применению модификаторов типов. Эти модификаторы изменяют
точность представления и диапазон значений переменных. Модификаторами
типа являются signed, unsigned, short и long.
   - Идентификаторы в С++ могут иметь длину до 32 символов и
должны начинаться с буквы или подчеркивания. Последующие символы
идентификатора могут быть буквой, цифрой или подчеркиванием. Иден-
тификаторы С++ чувствительны к регистру. Ограничение на 32 символа
может быть, однако, изменено путем установки опций компилятора.
   - Директива #include является специальной командой компилятора. Она
предписывает компилятору включить в программу содержимое опреде-
ленного файла, как если бы вы сами ввели его в текущий исходный
файл.
   - Объявление констант предусматривает использование директивы #define
для объявления констант, определенных при помощи макросов, или ис-
пользование ключевого слова const для объявления формальных кон-
стант. Формальные константы требуют от вас определения их типа
(значением по умолчанию является int), имени и ассоциированного с
ними значения.
   - Объявление переменной требует, чтобы вы задали ее тип и имя, С++
дает вам возможность инициализировать переменную при ее объявлении.
Вы можете объявить несколько переменных в одном операторе объявле-
ния.
   - Арифметическими операциями являются +, -, *, / и % (деление по
модулю).
   - Арифметические выражения различаются по сложности. Самое простое
выражение содержит единственный элемент данных (литерал, константу
или переменную). Сложные выражения включают набор операций, функ-
ции, литералы, константы и переменные.
   - Операции инкремента и декремента используются в префиксной и пост-
фиксной формах. Язык С++ дает вам возможность применять эти опе-
рации к переменным, в которых хранятся символы, целые числа и даже
числа с плавающей точкой.
   - Арифметические операции присваивания дают вам возможность записы-
вать более короткие арифметические выражения, в которых первый опе-
ранд является также переменной, принимающей результат вычислений.
   - Оператор sizeof возвращает как для типов данных, так и для переменных
их размер в байтах.
   - Механизм приведения типа дает вам возможность форсировать преобра-
зование типа выражения.
   - Операции отношений и логические операции дают вам возможность стро-
ить логические выражения.
   - Булевы выражения объединяют операции отношений и логические опе-
рации для формулирования нетривиальных условий. Эти выражения позволяют
программе принимать сложные решения.
   - Условное выражение предлагает вам короткую форму для простого опе-
ратора if-else с двумя альтернативами.
   - Операции манипулирования битами выполняют поразрядные операции
AND, OR, XOR и NOT. Кроме того, в С++ поддерживаются поразрядные
операции сдвига << и >>.
   - Операции манипулирования битами с присваиванием предлагают корот-
кие формы для простых операций манипулирования битами.

   Буквы и цифры

   Множество символов Си включает  большие  и  малые  буквы  из  английского
алфавита и 10 десятичных арабских цифр:
     -большие английские буквы:
A B C D E F G H I J K L M N O P Q R T U V W X Y Z
     -малые английские буквы:
a b c d e f g h i j k l m n o p q r t u v w x y z
     -десятичные цифры:
     0 1 2 3 4 5 6 7 8 9
   Буквы и цифры используются при формировании констант, иден-
тификаторов и ключевых слов. Все эти конструкции  описаны  ниже.  Компилятор
Си рассматривает одну и ту же  малую  и  большую
буквы как отличные символы. Если в данной записи использованы  малые  буквы,
то замена малой буквы "a" на  большую  букву  "A"  сделает  отличной  данную
запись от предшествующей.

       Пробельные символы


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


       Знаки пунктуации и специальные символы


       Знаки  пунктуации и специальные  символы  из  множества  символов  Си
используются для различных целей,  от   организации   текста  программы   до
определения   заданий,   которые   будут    выполнены    компилятором    или
откомпилированной программой. В таблице 2.1  перечислены эти символы.
-----------------------------------------------------------
   Символ   Наименование       Символ Наименование
-----------------------------------------------------------
     ,   Запятая  ! Восклицатель-
              ный знак
     .   Точка  | Вертикальная
              черта
     ;   Точка с за-   / Наклонная чер-
         пятой    та вправо
     :   Двоеточие  \  Наклонная чер-
              та влево
     ?   Знак вопроса  ~ Тильда
     '   Одиночная ка  _ Подчеркивание
         вычка
     (   Левая круглая # Знак номера
         скобка
     )   Правая круглая  % Знак процента
         скобка
     {   Левая фигурная  & Амперсанд
         скобка
     }   Правая фигурная ^ Caret
         скобка
     <   Левая угловая - Знак минус
         скобка
     >   Правая угловая  = Знак равно
         скобка
     [   Левая  квадратная + Знак плюс
              скобка
     ]        Правая квадратная
            скобка ---------------------------------------------------------
--
         Табл.  2.1. Знаки пунктуации и специальные символы

        Эти   символы  имеют  специальный  смысл  для  компилятора  Си.   Их
использование в языке Си описывается в дальнейшем  содержании   руководства.
Знаки   пунктуации  из   множества   представимых   символов,   которые   не
представлены в данном списке, могут быть  использованы  только  в  строковых
литералах, константах-символах и комментариях.

       ESC- последовательности

       ESC-   последовательности-  это  специальные  символьные  комбинации,
которые  представляют  пробельные   символы   и   неграфические  символы   в
строках и символьных константах.
       Их    типичное  использование   связано    со    спецификацией  таких
действий,  как  возврат  каретки  и   табуляция  ,   а  также  для   задания
литеральных  представлений  символов,   таких   как символ двойная  кавычка.
ESC-последовательность  состоит  из  наклонной   черты   влево,  за  которой
следует буква, знаки пунктуации ' " \ или комбинация цифр.  В  таблице  2.2.
приведен список ESC- последовательностей языка Си.
-------------------------------------------------
   ESC- последовательность Наименование
-------------------------------------------------
            \n  Новая строка
            \t  Горизонтальная табу-
                ляция
            \v  Вертикальная табуля-
                ция
            \b  Пробел
            \r  Возврат каретки
            \f  Новая страница
            \a  Звонок(сигнал)
            \'  Одиночная кавычка
            \"  Двойная кавычка
            \\  Наклонная черта влево
            \ddd  ASCII символ в восьми-
                ричном представлении
            \xdd  ASCII символ в шестнад-
              цатиричном представлении

         Табл.  2.2. ESC- последовательности

       Если наклонная черта влево предшествует символу,  не  включенному   в
  этот  список,  то   наклонная   черта   влево   игнорируется,   а   символ
представляется как  литеральный. Например, изображение  \c
представляет символ "c" в литеральной строке или константе-символе.
   Последовательности  \ddd и \xdd позволяют задать  любой  символ  в  ASCII
(Американский   стандартный    код     информационного    интерфейса)    как
последовательность трех восьмеричных цифр или двух  шестнадцатеричных  цифр.
Например, символ пробела может  быть  задан как \010  или  \x08.  Код  ASCII
"нуль"  может  быть  задан   как  \0   или  \x0  .  В   восьмеричной    ESC-
последовательности могут быть использованы от  одной  до  трех  восьмеричных
цифр.
   Например, символ пробела может быть задан  как \10  .   Точно  так  же  в
шестнадцатеричной ESC- последовательности могут быть использованы  от  одной
до двух шестнадцатеричных цифр.  Так,  шестнадцатеричная  последовательность
для символа  пробела может быть задана  как \x08 или \x8 .
   Замечание:
       Когда     используется     восьмеричная     или     шестнадцатеричная
ESCпоследовательность  в  строках,  то  нужно полностью задавать  все  цифры
ESC- последовательности (три  цифры  для  восьмеричной   и   две  цифры  для
шестнадцатеричной   ESC-   последовательностей).   Иначе,    если     символ
непосредственно следующий за  ESC-  последовательностью,  случайно  окажется
восьмеричной или  шестнадцатеричной   цифрой,   то  он   проинтерпретируется
как  часть последовательности. Например, строка   \x7Bell   при   выводе  на
печать будет выглядеть как {ell , поскольку  \x7B   проинтерпретируется  как
символ  левой   фигурной  скобки({)  .  Строка   \x07Bell  будет  правильным
представлением сим-
вола "звонок" с последующим словом Bell.
   ESC-  последовательности  позволяют  посылать  неграфические  управляющие
символы к внешним устройствам. Например, ESC-  последовательность\033  часто
используется как первый символ команд управления  терминалом  и   принтером.
Неграфические     символы      всегда     должны     представляться     ESC-
последовательностями,   поскольку,    непосредственное    использование    в
программах  на  Си  неграфических  символов  будет   иметь   непредсказуемый
результат.
   Наклонная черта  влево  (\)  помимо  определения  ESC-последовательностей
используется   также,   как  символ  продолжения  строки  в  препроцессорных
определениях.
   Если символ "новая строка" следует за наклонной чертой  влево,  то  новая
строка  игнорируется  и  следующая  строка    рассматривается,   как   часть
предыдущей строки.

   Операции

   Операции- это специальные комбинации символов, специфицирующие   действия
по пробразованию различных  величин.  Компилятор  интерпретирует  каждую  из
этих комбинаций как самостоятельную единицу, называемую лексемой (token).
    В  Табл.   2.3   представлен   список    операций.    Операции    должны
использоваться точно так, как они представлены  в  таблице:  без  пробельных
символов между символами в тех операциях, которые  представлены  несколькими
символами.
   Операция sizeof не включена в эту таблицу. Она скорее представляет  собой
ключевое слово, чем символ.
-------------------------------------------------
Операция                     Наименование ----------------------------------
---------------
       !                         Логическое НЕ
~                         Побитовое дополнение
       +                         Сложение

-  Вычитание, арифмети-
   ческое отрицание
*  Умножение
/  Деление
%  Остаток
<< Сдвиг влево
>> Сдвиг вправо
<  Меньше
<= Меньше или равно
>  Больше
>= Больше или равно
== Равно
!= Не равно
&  Побитовое И, адрес от
|  Побитовое  включающее ИЛИ
^  Побитовое исключающее ИЛИ
&& Логическое И
|| Логическое ИЛИ
'  Последовательное выполне-
   ние (запятая)
?: Операция условного вы-
   ражения
++ Инкремент
-- Декремент
=  Простое присваивание
+= Сложение с присваиванием
-= Вычитание с присваиванием
*= Умножение с присваиванием
/= Деление с присваиванием
%= Остаток с присваиванием
>>=  Сдвиг вправо с присваива-
   иванием
<<=  Сдвиг влево с присваива-
   нием
&= Побитовое И с присваива-
   нием
|= Побитовое включающее ИЛИ
   с присваиванием
^= Побитовое исключающее ИЛИ
   с присваиванием
       -------------------------------------------------------
            Табл. 2.3. Операции
     Замечание:
     Операция  условного выражения ?: -это тернарная,  а  не  двухсимвольная
операция.       Формат        условного         выражения         следующий:
<expression>?<expression>:<expression>

     Константы

      Константа-  это  число,  символ   или   строка   символов.   Константы
используются  в  программе  как неизменяемые величины. В языке Си  различают
четыре  типа  констант:  целые  константы,  константы  с  плавающей  точкой,
константы-символы и строчные литералы.

     Целые константы

     Целая константа- это десятичное,  восьмеричное  или   шестнадцатеричное
число, которое  представляет  целую  величину.  Десятичная  константа  имеет
следующий формат представления:
     <digits>,
     где  <digits>  - это одна или более десятичных цифр от 0 до 9.
     Восьмеричная константа имеет следующий  формат  представления:
     0<odigits>,
     где  <odigits>  - это одна или более  восьмеричных  цифр  от  0  до  7.
Запись ведущего нуля необходима.
      Шестнадцатеричная  константа  имеет  один   из   следующих    форматов
представления:
     0x<hdigits>
     0X<hdigits>,
где <hdigits>  одна  или  более  шестнадцатеричных  цифр.  Шестнадцатеричная
цифра  может  быть  цифрой от 0 до 9 или
буквой  (большой  или  малой)  от  A  до  F.  В   представлении    константы
допускается   "смесь"  больших  и  малых  букв.  Запись  ведущего   нуля   и
следующего за ним символа x или X необходима.
     Пробельные символы не допускаются  между  цифрами  целой  константы.  В
Табл. 2.4 иллюстрируются примеры целых констант.



-----------------------------------------------------------
   Десятичные         Восьмеричные         Шестнадцатеричные
   константы          константы            константы
-----------------------------------------------------------
   10               012                  0xa или 0xA
   132              0204                 0x84
   32179          076663               0x7dB3 или 0x7DB3
-----------------------------------------------------------
         Табл. 2.4 Примеры констант

     Целые константы всегда  специфицируют  положительные   величины.   Если
требуется отрицательные величины,  то  необходимо  сформировать  константное
выражение из знака минус и  следующей  за  ним
константы.  Знак  минус рассматривается как арифметическая операция.
      Каждая  целая  константа  специфицируется  типом,    определяющим   ее
представление в памяти и область значений. Десятичные константы  могут  быть
типа int или long.
     Восьмеричные и шестнадцатеричные константы  в  зависимости  от  размера
могут  быть   типа   int,   unsigned  int,  long  или  unsigned  long.  Если
константа может быть  представлена  как  int,  она   специфицируется   типом
int. Если ее  величина  больше,  чем  максимальная  положительная  величина,
которая  может   быть   представлена   типом  int,   но   меньше   величины,
которая представляется в том же самом числе бит  как  и  int,  она  задается
типом  unsigned  int.  Наконец, константа,  величина   которой   больше  чем
максимальная  величина,  представляемая   типом   unsigned   int,    задется
типом  long   или unsigned long, если это необходимо. В Табл.  2.5  показаны
диапазо-
ны   величин  восьмеричных  и   шестнадцатеричных   констант,   представимых
соответствующими типами на машине, где тип int имеет длину 16 бит.
-----------------------------------------------------------
   Шестнадцатеричные            Восьмеричные   Тип
   диапазоны                диапазоны
-----------------------------------------------------------
0x0-0x7FFF             0-077777     int
0x8000-0xFFFF          0100000-0177777     unsigned int
0x10000-0x7FFFFFFF         0200000-017777777777  long
0x80000000-0xFFFFFFFF   020000000000-030000000000   unsigned long
-----------------------------------------------------------
       Табл.    2.5 Диапазоны   величин восьмеричных   и
         шестнадцатеричных констант

     Важность рассмотренных выше правил состоит в том,  что  восьмеричные  и
шестнадцатеричные  константы  не   содержат   "знаковых"  расширений,  когда
они преобразуются к более  длинным  типам  (преобразование  типов  смотри  в
разделе 5 "Выражения и присваивания").
Программист  может определить для любой целой константы тип
long, приписав букву "l" или "L" в конец константы. В  Табл.   2.6  показаны
примеры целых констант.



------------------------------------------------------------
   Десятичные        Восьмеричные Шестнадцатеричные
   константы           константы    константы
------------------------------------------------------------
   10L                   012L       0xaL или 0xAL
   79l                   0115l      0x4fl или 0x4Fl
------------------------------------------------------------
       Табл. 2.6 Примеры целых констант типа long

     Константы с плавающей точкой

      Константа  с   плавающей   точкой-   это   действительное   десятичное
положительное   число.  Величина  действительного  числа   включает   целую,
дробную  части  и  зкспоненту.   Константы   с   плавающей    точкой   имеют
следующий формат представления:
     [<digits>][.<digits>][E[-]<digits>],
     где  <digits> - одна или более десятичных цифр (от 0 до 9),
а E или e -символ экспоненты. Целая  или  дробная   части   константы  могут
быть опушены, но не обе сразу. Десятичная точка может  быть  опущена  только
тогда, когда задана экспонента.
    Экспонента  состоит  из   символа   экспоненты,   за   которым   следует
целочисленная величина экспоненты, возможно отрицательная.
Пробельные символы не могут  разделять  цифры  или  символы
константы.
    Константы   с   плавающей  точкой  всегда  специфицируют   положительные
величины. Если требуются отрицательные величины, то необходимо  сформировать
константное выражение из знака минус и  следующей  за  ним  константы.  Знак
минус рассматривается  как  арифметическая операция.
   Примеры  констант  с плавающей точкой и константных выраже-
ний:
   15.75
   1.575E1
   1575e-2
   -0.0025
   -2.5e-3
   25e-4
   Целая часть константы с плавающей точкой может быть  опущена, например:
   .75
   .0075e2
   -.125
   -.175E-2
Все константы с плавающей точкой имеют тип double.

   Константа-символ

   Константа-символ-  это  буква,  цифра,  знак пунктуации или ESC-  символ,
заключенные  в  одиночные  кавычки.    Величина    константы-символа   равна
значению представляющего ее кода символа.
Константа-символ имеет следующую форму представления:
   '<char>',
    где   <char>  может  быть  любым  символом  иэ  множества   представимых
символов,  включая  любой  ESC-  символ,  исключая  одиночную  кавычку  ('),
наклонную черту влево (\) и символ новой строки.
   Чтобы использовать одиночную кавычку   или   наклонную   черту  влево   в
качестве   константы-символа,   необходимо  вставить  перед  этими   знаками
наклонную черту влево. Чтобы представить  символ  новой  строки,  необходимо
использовать запись '\n'.
----------------------------------------------
Константа                   Название величины
----------------------------------------------
'a'         Малая буква а
'?'         Знак вопроса
'\b'        Знак пробела
'0x1B'        ASCII ESC- символ
'\''        Одиночная кавычка
'\\'        Наклонная черта влево
-------------------------------------------------
     Табл. 2.7 Примеры констант-символов.


   Константы-символы имеют тип int.

   Строковые литералы

    Строковый  литерал-  это  последовательность  букв,  цифр  и   символов,
заключенная  в  двойные  кавычки.  Строковый  литерал   рассматривается  как
массив символов, каждый элемент которого  представляет   отдельный   символ.
Строковый  литерал  имеет следующую форму представления:
   "<characters>" ,
   где <characters> - это нуль или более символов из множества  представимых
символов, исключая двойную  кавычку  ("),   наклонную  черту  влево  (\)   и
символ новой строки. Чтобы использовать  символ  новой  строки  в  строковом
литерале, необходимо напечатать   наклонную  черту  влево,  а  затем  символ
новой строки.
    Наклонная   черта  влево  вместе   с   символом   новой   строки   будут
проигнорированы  компилятором  ,  что   позволяет   формировать    строковые
литералы,  располагаемые более  чем  в  одной  строке.  Например,  строковый
литерал:
   "Long strings can be bro\
   cken into two pieces."
   идентичен строке:
   "Long strings can be brocken into two pieces."
   Чтобы использовать двойные  кавычки  или  наклонную  черту  влево  внутри
строкового литерала, нужно представить их с предшествующей наклонной  чертой
влево, как показано в следующем примере:
   "This is a string literal"
   "First \\ Second"
   "\"Yes, I do,\" she said."
   "The following line shows a null string:"
   ""
   Заметим, что ESC- символы  (такие  как  \\  и  \")  могут   появляться  в
строковых литералах. Каждый ESC- символ считается одним отдельным символом.
   Символы строки запоминаются в отдельных байтах памяти. Символ  null  (\0)
является   отметкой    конца    строки.    Каждая    строка   в    программе
рассматривается как отдельный об"ект.  Если  в   программе  содержатся   две
идентичные строки, то каждая  из  них будет   храниться  в  отдельном  месте
памяти.
   Строчные литералы  имеют  тип  char[].  Под  этим  подразумевается,   что
строка-  это  массив, элементы которого имеют тип char.  Число  элементов  в
массиве равно числу  символов  в  строчном  литерале  плюс  один,  поскольку
символ null (отметка конца  строки)  тоже считается элементом массива.

   Идентификаторы

   Идентификаторы-  это имена переменных, функций и  меток,  используемых  в
программе. Идентификатор создается об"явлением соот-
ветствующей ему переменной или функции.После этого его  можно   использовать
в последующих операторах программы.  Идентификатор-  это  последовательность
из  одной  или  более  букв, цифр или  подчерков(_),  которая  начинается  с
буквы или подчерка. Допускается   любое  число  символов  в  идентификаторе,
однако  только  первые  31  символ  распознаются  компилятором.  (Программы,
использующие результат
работы компилятора, такие как,  линкер,  могут  распознавать  меньшее  число
символов).
   При использовании  подчерков  в  идентификаторе  нужно  быть  осторожным,
поскольку идентификаторы, начинающиеся с подчерка могут совпадать  (войти  в
конфликт) с именами "скрытых" системных программ.
   Примеры идентификаторов:
   temp1
   toofpage
   skip12
   Компилятор Си  рассматривает  буквы  верхнего  и  нижнего  регистров  как
различные   символы.   Поэтому   можно   создать    отдельные    независимые
идентификаторы, которые совпадают орфографически, но различаются большими  и
малыми буквами.  Например,  каждый  из  следующих  идентификаторов  является
уникальным:
   add
   ADD
   Add
   aDD
   Компилятор Си не допускает идентификаторов,  которые  имеют ту  же  самую
орфографию, что  и  ключевые  слова.  Ключевые  слова  описаны  в  следующем
раздела
   Замечание:
    По  сравнению  с  компилятором,  сборщик   может   в   большей   степени
ограничивать количество и тип символов для глобальных идентификаторов,  и  в
отличие от  компилятора  не   делать   различия   между  большими  и  малыми
буквами. (Подробнее смотри руководство по пакету MSC).

   Ключевые слова

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

   Список ключевых слов:
   auto  double int struct
   break else long  switch
   case  enum register typedef
   char  extern return union
   const float  short  unsigned
   continue for signed void
   default  goto  sizeof while
   do  if   static  volatile
   Ключевые слова  не могут быть переопределены. Тем  не  менее,  они  могут
быть названы другим текстом, но тогда  перед  компиляцией  они  должны  быть
заменены посредством препроцессора на  соответствующие ключевые слова.
    Ключевые   слова  const  и  volatile   зарезервированы   для    будущего
использования.
   Следующие идентификаторы могут быть  ключевыми   словами   для  некоторых
приложений:
   cdecl
   far
   fortran
   huge
   near
   pascal

   Комментарии

   Комментарий-  это  последовательность  символов,  которая  воспринимается
компилятором  как  отдельный  пробельный  символ   или,   другими   словами,
игнорируется.
Комментарий имеет следующую форму представления:
   /*<characters>*/,
   где  <characters>  может быть любой  комбинацией  символов  из  множества
представимых символов, включая символы новой строки, но исключая  комбинацию
*/. Это означает, что комментарии могут занимать более одной строки,  но  не
могут быть вложенными.
   Комментарии допускаются   везде,   где   разрешены   пробельные  символы.
Компилятор игнорирует  символы  комментария,  в  частности,  в  комментариях
допускается запись ключевых слов  и  зто  не  приведет  к  ошибке.  Так  как
компилятор рассматривает комментарий как символ пробела, то  комментарии  не
могут появляться внутри лексем.
Следующие примеры иллюстрируют некоторые комментарии:
   /* Comments can separate and document
   lines of a program. */
   /* Comments can contain keywords such as for
   and while */
/*******************************************
          Comments         can         occupy         several         lines.
*******************************************/
   Так как  комментарии  не  могут  содержать  вложенных   комментариев,  то
следующий пример будет ошибочным:
   /* You cannot/* nest */ comments */
   Компилятор распознает первую комбинацию */ после слова  nest  как   конец
комментария. Затем, компилятор попытается обрабатывать  оставшийся  текст  и
выработает сообщение об ошибке.  Чтобы  обойти
компиляцию  комментариев больших размеров, нужно использовать директиву  #if
препроцессора.

   Лексемы

   Когда  компилятор  обрабатывает  программу,  он  разбивает  программу  на
группы  символов,  называемых  лексемами.  Лексема-   это   единица   текста
программы, которая имеет определенный смысл для  компилятора  и  которая  не
может быть разбита  в  дальнейшем.  Операции,  константы,  идентификаторы  и
ключевые слова, описанные в этом разделе,являются  примерами  лексем.  Знаки
пунктуации,  такие  как  квадратные  скобки  ([]),  фигурные  скобки   ({}),
угловые  скобки  (<>), круглые  скобки и запятые, также являются  лексемами.
Границы лексем  определяются  пробельными  символами  и  другими  лексемами,
такими как операции и  знаки  пунктуации.  Чтобы  предупредить  неправильную
работу  компилятора,  запрещаются   пробельные   символы   между   символами
идентификаторов, операциями, состоящими из нескольких символов  и  символами
ключевых слов.
    Когда   компилятор  выделяет  отдельную  лексему,   он   последовательно
об"единяет столько  символов,  сколько  возможно,  прежде   чем  перейти   к
обработке следующей лексемы. Поэтому  лексемы,  не  разделенные  пробельными
символами,  могут  быть  проинтерпретированы неверно.
   Например, рассмотрим следующее выражение:
     i+++j
   В  этом  примере  компилятор вначале создает из трех  знаков  плюс  самую
длинную из возможных операций (++), а затем обработает  оставшийся  знак  +,
как операцию сложения (+). Выражение проинтерпретируется  как  (i++)+(j),  а
не как (i)+(++j).  В  таких  случаях  необходимо   использовать   пробельные
символы или круглые скобки, чтобы однозначно определить ситуацию.


ИСХОДНЫЕ ТЕКСТЫ ПРИМЕРОВ


// Программа VAR.CPP, иллюстрирующая простые переменные

#include <iostream.h>

int main()
{
   int i, j = 2;
   double x, y = 355.0 / 113;

   i = 3 * j;
   cout << "i = " << i << endl
        << "j = " << j << endl;

   x = 2 * y;
   x = x * x;
   cout << "y = " << y << endl
        << "x = " << x << endl;
   return 0;
}
/*
    Результаты:
    i = 6
    j = 2
    y = 3.141593
    x = 39.4784
*/
// Программа CONST1.CPP, иллюстрирующая константы

#include <iostream.h>

#define SEC_IN_MIN 60
#define MIN_IN_HOUR 60

int main()
{
   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 << totalSec << " секунд прошло с полуночи" << endl;
   return 0;
}
/*  Тест и результаты:
    Введите часы: 10
    Введите минуты: 0
    Введите секунды: 0

    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).


   Конструкции принятия решений и циклы



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


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

   Нет. Отступ определяется только Вами. Типовые размеры отступа  составляют
два или четыре пробела. Использование отступов делает  ваш  листинг  намного
более удобочитаемым.
   Вот пример оператора 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>-   это  одно
     или  более  об"явлений переменных или битовых полей. Каждая

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