ГЛАВА 2. Базовые средства языка Си
Любая программа, написанная на языке высокого уровня, состоит из последовательности инструкций, оформленных в строгом соответствии с набором правил, составляющих синтаксис данного языка.
При создании программ разработчик может допустить следующие ошибки: синтаксические и логические.
Синтаксические ошибки – это результат нарушения формальных правил написания программы на конкретном языке программирования.
Логические ошибки разделяются, в свою очередь, на ошибки алгоритма и семантические ошибки.
Причиной ошибки алгоритма является несоответствие построенного алгоритма ходу получения конечного результата сформулированной задачи.
Причина семантической ошибки – неправильное понимание смысла (семантики) операторов выбранного языка программирования.
Алфавит языка Си
Алфавит любого языка составляет совокупность символов – тех неделимых знаков, при помощи которых записываются все тексты на данном языке.
Каждому из множества значений, определяемых одним байтом (от 0 до 255), в таблице знакогенератора ЭВМ ставится в соответствие символ. По кодировке фирмы IBM символы с кодами от 0 до 127, образующие первую половину таблицы знакогенератора, построены по стандарту ASCII и одинаковы для всех компьютеров, вторая половина символов (коды 128 – 255) может отличаться и обычно используется для размещения символов национального алфавита. Коды 176 – 223 отводятся под символы псевдографики, а коды 240 – 255 – под специальные знаки (прил. 1).
Алфавит языка Си включает:
– прописные и строчные буквы латинского алфавита и знак подчеркивания (код 95);
– арабские цифры от 0 до 9;
– специальные символы, смысл и правила использования которых будем рассматривать по тексту;
– пробельные (разделительные) символы: пробел, символы табуляции, перевода строки, возврата каретки, новой страницы и новой строки.
Лексемы
Из символов алфавита формируются лексемы (или элементарные конструкции) языка – минимальные значимые единицы текста в программе:
– идентификаторы;
– ключевые (зарезервированные) слова;
– знаки операций;
– константы;
– разделители (скобки, точка, запятая, пробельные символы).
Границы лексем определяются другими лексемами, такими как разделители или знаки операций, а также комментариями.
Идентификаторы и ключевые слова
Идентификатор (ID) – это имя программного объекта* (константы, переменной, метки, типа, функции и т.д.). В идентификаторе могут использоваться латинские буквы, цифры и знак подчеркивания; первый символ ID – не цифра; пробелы внутри ID не допускаются.
Длина идентификатора определяется выбранной версией среды программирования. Например, в среде Borland C++ 6.0 идентификаторы могут включать любое число символов, из которых воспринимаются и используются только первые 32 символа. Современная тенденция – снятие ограничений длины идентификатора.
При именовании объектов следует придерживаться общепринятых соглашений:
– ID переменных и функций обычно пишутся строчными (малыми) буквами – index, max();
– ID типов пишутся с большой буквы, например, Spis, Stack;
– ID констант (макросов) – большими буквами – INDEX, MAX_INT;
– идентификатор должен нести смысл, поясняющий назначение объекта в программе, например, birth_date – день рождения, sum – сумма;
– если ID состоит из нескольких слов, как, например, birth_date, то принято либо разделять слова символом подчеркивания, либо писать каждое следующее слово с большой буквы – birthDate.
В Си прописные и строчные буквы – различные символы. Идентификаторы Name, NAME, name – различные объекты.
Ключевые (зарезервированные) слова не могут быть использованы в качестве идентификаторов.
Список ключевых слов, определенных в стандарте ANSI Cи:
auto | do | goto | signed | unsigned |
break | double | if | sizeof | void |
case | else | int | static | volatile |
char | enum | long | struct | while |
const | extern | register | switch | |
continue | float | return | typedef | |
default | for | short | union |
Комментарии
Еще один базовый элемент языка программирования – комментарий – не является лексемой. Внутри комментария можно использовать любые допустимые на данном компьютере символы, поскольку компилятор их игнорирует.
В Си комментарии ограничиваются парами символов /* и */, а в С++ был введен вариант комментария, который начинается символами // и заканчивается символом перехода на новую строку.
Простейшая программа
Программа, написанная на языке Си, состоит из одной или нескольких функций, одна из которых имеет идентификатор main* – главная (основная). Она является первой выполняемой функцией (с нее начинается выполнение программы) и ее назначение – управлять работой всей программы (проекта).
Общая структура программы на языке Си имеет вид:
<директивы препроцессора>
<определение типов пользователя – typedef>
<описание прототипов функций>
<определение глобальных переменных>
<функции>
В свою очередь, каждая функция имеет следующую структуру:
<класс памяти> <тип> < ID функции> (<объявление параметров>)
{ – начало функции
код функции
} – конец функции
Код функции является блоком и поэтому заключается в фигурные скобки.
Функции не могут быть вложенными друг в друга.
Рассмотрим кратко основные части общей структуры программ.
Перед компиляцией программа обрабатывается препроцессором (прил. 3), который работает под управлением директив.
Препроцессорные директивы начинаются символом #, за которым следует наименование директивы, указывающее ее действие.
Препроцессор решает ряд задач по предварительной обработке программы, основной из которых является подключение (include) к программе так называемых заголовочных файлов (обычных текстов) с декларацией стандартных библиотечных функций, использующихся в программе. Общий формат ее использования
#include < ID_файла.h>
где h – расширение заголовочных файлов.
Если идентификатор файла заключен в угловые скобки (< >), то поиск данного файла производится в стандартном каталоге, если – в двойные кавычки (” ”), то поиск файла производится в текущем каталоге.
К наиболее часто используемым библиотекам относятся:
stdio.h – содержит стандартные функции файлового ввода-вывода;
math.h – математические функции;
conio.h – функции для работы с консолью (клавиатура, дисплей).
Второе основное назначение препроцессора – обработка макроопределений. Макроподстановка определить (define) имеет общий вид
#define ID строка
Например: #define PI 3.1415927
– в ходе препроцессорной обработки программы идентификатор PI везде будет заменяться значением 3.1415927.
Рассмотрим пример, позволяющий понять простейшие приемы программирования на языке Си:
#include <stdio.h>
void main(void)
{ // Начало функции main
printf(“ Высшая оценка знаний – 10 !”);
} // Окончание функции main
Отличительным признаком функции служат скобки ( ) после ее идентификатора, в которые заключается список параметров. Перед ID функции указывается тип возвращаемого ею результата. Если функция не возвращает результата и не имеет параметров, указывают атрибуты void – отсутствие значений.
Для начала будем использовать функцию main без параметров и не возвращающую значения.
Код функции представляет собой набор инструкций, каждая из которых оканчивается символом «;». В нашем примере одна инструкция – функция printf, выполняющая вывод данных на экран, в данном случае – указанную фразу.
__________________________________________________________________
Приемы отладки в среде программирования Visual C++ 6.0 рассматриваются в прил. 5.
__________________________________________________________________
Основные типы данных
Данные в языке Си разделяются на две категории: простые (скалярные), будем их называть базовыми, и сложные (составные) типы данных.
Тип данных определяет:
– внутреннее представление данных в оперативной памяти;
– совокупность значений (диапазон), которые могут принимать данные этого типа;
– набор операций, которые допустимы над такими данными.
Основные типы базовых данных: целый – int (integer), вещественный с одинарной точностью – floatи символьный – char (character).
В свою очередь, данные целого типа могут быть короткими – short, длинными – long и беззнаковыми – unsigned, а вещественные – с удвоенной точностью – double.
Сложные типы данных – массивы, структуры – struct, объединения – union, перечисления – enum.
Данные целого и вещественного типов находятся в определенных диапазонах, т.к. занимают разный объем оперативной памяти (табл. 2.1).
Таблица 2.1
Тип данных | Объем памяти (байт) | Диапазон значений |
сhar | –128 … 127 | |
int | 2 (4)* | –32768 … 32767 |
short | 1 (2)* | –32768 … 32767(–128 … 127) |
long | –2147483648 … 2147483647 | |
unsigned int | 0 … 65535 | |
unsigned long | 0 … 4294967295 | |
float | 3,14×10–38 … 3,14×1038 | |
double | 1,7×10–308 … 1,7×10308 | |
long double | 3,4×10–4932 … 3,4×104932 |
* Размер памяти зависит от разрядности процессора, для 16-разрядных объем памяти определяется первой цифрой, для 32-разрядных – второй.
Декларация объектов
Все объекты, с которыми работает программа, необходимо декларировать, т.е. объявлять компилятору об их присутствии. При этом возможны две формы декларации:
– описание, не приводящее к выделению памяти;
– определение, при котором под объект выделяется объем памяти в соответствии с его типом; в этом случае объект можно инициализировать, т.е. задать его начальное значение.
Кроме констант, заданных в исходном тексте, все объекты программы должны быть явно декларированы по следующему формату:
<атрибуты> <список ID объектов>;
элементы списка ID объектов разделяются запятыми, а атрибуты – разделителями, например: int i, j, k; float a, b;
Объекты программы могут иметь следующие атрибуты:
класс памяти – характеристика способа размещения объектов в памяти (статическая, динамическая); определяет область видимости и время жизни переменной (по умолчанию – auto), данные атрибуты будут рассмотрены в гл. 12;
тип – тип будущих значений декларируемых объектов (по умолчанию устанавливается тип int).
Класс памяти и тип – атрибуты необязательные и при отсутствии одного из них (но не обоих одновременно) устанавливаются атрибуты по умолчанию.
Примеры декларации простых объектов:
int i, j, k; char r; double gfd;
Рассмотрим основные базовые типы данных более подробно.