Главная страница
Навигация по странице:

1 Структура и этапы создания программы на языке С



Скачать 235.25 Kb.
Название 1 Структура и этапы создания программы на языке С
Анкор C++.docx
Дата 30.04.2017
Размер 235.25 Kb.
Формат файла docx
Имя файла C++.docx
Тип Программа
#5051
страница 1 из 8
  1   2   3   4   5   6   7   8


1.1. Структура и этапы создания программы на языке С++

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

Листинг 1.1. Пример простой программы.

/* Пример простой программы*/
#include
int main()
{
printf(“Hello World!”);
return 0;
}

и обычно имеет расширение cpp, например, «ex1.cpp».

Следующий шаг – это компиляция исходного кода. Под компиляцией понимают процесс, при котором содержимое текстового файла преобразуется в исполняемый машинный код, понимаемый процессором компьютера. Однако компилятор создает не готовую к исполнению программу, а только объектный код (файл с расширением *.obj). Этот код является промежуточным этапом при создании готовой программы. Дело в том, что создаваемая программа может содержать функции стандартных библиотек языка С++, реализации которых описаны в объектных файлах библиотек. Например, в приведенной программе используется функция printf() стандартной библиотеки «stdio.h». Это означает, что объектный файл ex1.obj будет содержать лишь инструкции по вызову данной функции, но код самой функции в нем будет отсутствовать.

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

Рассмотрим более подробно пример программы листинга 1.1. Первая строка задает комментарии, т.е. замечания, помогающие лучше понять программу. Они предназначены только для чтения и игнорируются компилятором. Во второй строке записана директива #include, которая дает команду препроцессору языка С++ вставить содержимое файла ‘stdio.h’ на место этой строки при компиляции. В третьей строке определена функция с именем main, которая возвращает целое число (тип int) и не принимает никаких аргументов (тип void). Функция main() является обязательной функцией для всех программ на языке С++ и без ее наличия уже на этапе компиляции появляется сообщение об ошибке, указывающее на отсутствие данной функции. Обязательность данной функции обусловливается тем, что она является точкой входа в программу. В данном случае под точкой входа понимается функция, с которой начинается и которой заканчивается работа программы. Например, при запуске exe-файла происходит активизация функции main(), выполнение всех операторов, входящих в нее и завершение программы. Таким образом, логика всей программы заключена в этой функции. В приведенном примере при вызове функции main() происходит вызов функции printf(), которая выводит на экран монитора сообщение “Hello World!”, а затем выполняется оператор return, который возвращает нулевое значение. Это число возвращается самой функцией main() операционной системе и означает успешное завершение программы. Фигурные скобки {} служат для определения начала и конца тела функции, т.е. в них содержатся все возможные операторы, которые описывают работу данной функции. Следует отметить, что после каждого оператора в языке С++ ставится символ ‘;’. Таким образом, приведенный пример показывает общую структуру программ на языке С++.

1.2. Стандарты языка С++

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

По мере того, как язык С постепенно развивался сообщество пользователей этого языка осознало, что нуждается в современном и строгом стандарте. В ответ на эти потребности Американский институт национальных стандартов (American National Standards Institute (ANSI)) в 1983 г. организовал комитет (X3J11) для разработки нового стандарта, который был принят в 1989 г. Этот стандарт (ANSI C) содержит определение как языка, так и стандартной библиотеки С. Затем международная организация по стандартизации (ISO) в 1990 г. приняла свой стандарт (ISO C), который по сути не отличается от стандарта ANSI C.

В 1994 г. возобновилась деятельность по разработке нового стандарта, в результате чего появился стандарт C99, который соответствует языку С++. Объединенный комитет ANSI/ISO развил исходные принципы предыдущего стандарта, являющийся основным на сегодняшний день.

1.3. Представление данных в языке С++

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

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

<�тип переменной> <�имя_переменной>;

например, строка

int arg;

объявлет целочисленную переменную с именем arg.

Основные базовые типы данных:

int - целочисленный тип 16 либо 32 бит

long int - целочисленный тип 32 бит

short - целочисленный тип 8 либо 16 бит

char - символьный тип 8 бит

float - вещественный тип 32 бит

double - вещественный тип 64 бит

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

В приведенных примерах переменные arg и Arg считаются разными, т.к. язык С++ при объявлении переменных различает большой и малый регистры.

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

1.4. Оператор присваивания

Для того чтобы задать то или иное значение переменной используется оператор присваивания, который записывается как знак ‘=’. Работу этого оператора представим на следующем примере:

int length = 5;

Здесь переменной с именем length присваивается значение 5, т.е. элемент слева от знака равенства является именем переменной, а элемент справа – это значение, присвоенное этой переменной. Сам символ ‘=’ называется оператором присваивания.

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

int i=2;
i=i+1;

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

Так как оператор присваивания задает значение переменной, то оператор типа

20 = i;

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

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

short agr_short = -10;
long arg_long;

и выполняется оператор присваивания

arg_long = arg_short;

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

float agr_f = 8.7;
int arg_long;
arg_long = arg_f;

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

<�имя_переменной_1> = (тип_данных)<�имя_переменной_2>;

Например,

arg_long = (long )arg_f;

1.5. Системы счисления

Любое число можно представлять в разной системе счисления. Во всех предыдущих примерах использовалось десятичная форма записи числа. Это значит, что число может быть разложено по степеням 10, например,

http://www.sernam.ru/c_img/151.gif
Однако компьютер оперирует двоичными числами, т.е. представляет число по степеням двойки, например:

http://www.sernam.ru/c_img/152.gif
которое часто записывают в виде 1000000.

Учитывая, что в одном байте 8 бит, максимальное число, которое он может содержать равно

http://www.sernam.ru/c_img/153.gif
Таким образом, один байт информации может представлять десятичные числа в диапазоне от 0 до 255, т.е. 256 возможных значений.

Кроме десятичной и двоичной систем счисления при программировании часто используют шестнадцатиричную систему, т.е. числа с основанием 16. Для записи таких чисел недостаточно использовать цифры, поэтому для обозначения основания больше 9 добавляют буквы A – 10, B – 11, C – 12, D – 13, E – 14, F – 15 (или малого регистра a,b,c,d,e,f). Например, десятичное число 0 соответствует шестнадцатиричному 0, а десятичное 15, шестнадцатиричному F. Для представления числа 16 используется шестнадцатиричное http://www.sernam.ru/c_img/154.gif, а число 255 соответствует числу http://www.sernam.ru/c_img/155.gif.

Следует отметить, что каждая цифра шестнадцатиричного числа представляется четырьмя битами двоичного числа. Действительно http://www.sernam.ru/c_img/156.gifдает диапазон чисел от 0 до 15 или в шестандцатиричной записи от 0 до F. Это свойство удобно для представления байтовых чисел, где каждая половинка байта представляется одним шестнадцатиричным числом. Например,
FF = 11111111; 0F = 00001111; 11 = 00010001 и т.д.

Для представления шестнадцатиричных чисел в языке С++ используется следующий синтаксис:

int var = 0xff; //число 255
int arg = 0xac; //число 172

1.6. Арифметические операции

В языке С++ довольно просто реализуются элементарные математические операции: сложения, вычитания, умножения и деления. Допустим, что в программе заданы две переменные

int a, b;

с начальными значениями

a=4;
b=8;

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

int c;
c = a+b; //сложение двух переменных
с = a-b; //вычитание
c = a*b; //умножение
c = a/b; //деление

Представленные операции можно выполнять не только с переменными, но и с конкретными числами, например

c = 10+5;
c = 8*4;
float d;
d = 7/2;

Результатом первых двух арифметических операций будут числа 15 и 32 соответственно, но при выполнении операции деления в переменную d будет записано число 3, а не 3,5. Это связано с тем, что число 7 в языке С++ будет интерпретироваться как целочисленная величина, которая не может содержать дробной части. Поэтому полученная дробная часть 0,5 будет отброшена. Для реализации корректного деления одного числа на другое следует использовать такую запись:

d = 7.0/2;

или

d = (float )7/2;

В первом случае вещественное число делится на два и результат (вещественный) присваивается вещественной переменной d. Во втором варианте выполняется приведение типов: целое число 7 приводится к вещественному типу float, а затем делится на 2. Второй вариант удобен, когда выполняется деление одной целочисленной переменной на другую:

int a,b;
a = 7; b = 2;
d = a/b;

В результате значение d будет равно 3, но если записать

d = (float )a/b;

то получим значение 3,5. Здесь следует также отметить, что если переменная d является целочисленной, то результат деления всегда будет записан с отброшенной дробной частью. Аналогичные правила справедливы для всех арифметических операций.

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

double n=2, SCALE = 1.2;
double arg = 25.0 + 60.0*n/SCALE;

В приведенном примере сначала будет выполнена операция умножения, затем деления и, наконец, сложения. То есть порядок вычисления соответствует математическим правилам. Для того чтобы изменить порядок вычисления (поменять приоритеты) используются круглые скобки как показано ниже

double arg = (25.0 + 60.0)*n/SCALE;

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

Кроме рассмотренных арифметических операций в С++ имеется полезная операция деления по модулю. Ее результатом является остаток от деления одного целого числа на другое. Так выражение

int a = 13 % 5;

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

int a = 13 – 13/5*5;

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

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

i++; // операция инкремента
++i; // операция инкремента
i--; // операция декремента
--i; // операция декремента

Разницу между первой и второй формами записи данных операторов можно продемонстрировать на следующем примере:

int i=10,j=10;
int a = i++; //значение a = 10; i = 11;
int b = ++j; //значение b = 11; j = 11;

Из полученных результатов видно, что если оператор инкремента стоит после имени переменной, то сначала выполняется операция присваивания и только затем операция инкремента. Во втором случае наоборот, операция инкремента реализуется до присвоения результата другой переменной. Поэтому значение a = 10, а значение b = 11. В первом случае говорят о постпрефиксной форме, а во втором – о префиксной. Подобный приоритет операции инкремента остается справедливым и при использовании арифметических операций, например

int a1=4, a2=4;
double b = 2.4*++a1; //результат b = 12.0
double c = 2.4*a2++; //результат c = 9.6

Из приведенного примера видно, что операция инкремента (декремента) обладает более высоким приоритетом, чем операция умножения (соответственно и деления). Для того чтобы изменить приоритеты используются круглые скобки.

Операция декремента действует аналогично операции инкремента с той лишь разницей, что она уменьшает значение переменной на 1.

1.7. Поразрядные операции языка С++

Поразрядные операции состоят из четырех основных операций: отрицание, логическое И, логическое ИЛИ и исключающее ИЛИ. Рассмотрим данные операции по порядку.

При выполнении операции поразрядного отрицания все биты, равные 1, устанавливаются равными 0, а все биты равные нулю, устанавливаются равными 1. Для выполнения данной операции в языке С++ используется символ ‘

’ как показано в следующем примере:

unsigned char var = 153; //двоичная запись 10011001
unsigned char not = var; //результат 01100110 (число 102)

В результате переменная not будет содержать число 102. В ходе выполнения операции поразрядного И результирующий бит будет равен 1, если оба бита в соответствующих операндах равны 1, т.е.

10010011 & 00111101 даст результат
00010001.

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

unsigned char var = 153; //двоичная запись 10011001
unsigned char mask = 0x11; // число 00010001 (число 17)
unsigned char res = var & mask; // результат 00010001

или

var &= mask; // то же самое, что и var = var & mask;

В ходе выполнения двоичной операции ИЛИ результирующий бит устанавливается равным 1, если хотя бы один бит соответствующих операндов равен 1. В противном случае, результирующее значение равно 0. Для выполнения данной логической операции используется символ ‘|’ как показано ниже:

unsigned char var = 153; //двоичная запись 10011001
unsigned char mask = 0x11; // число 00010001
unsigned char res = var | mask; // результат 10011001

Также допускается применение такой записи

var |= mask; // то же самое, что и var = var | mask;

Наконец, при операции исключающее ИЛИ результирующий бит устанавливается равным 0, если оба бита соответствующих операндов равны 1, и 1 в противном случае. Для выполнения данной операции в языке С++ используется символ ‘^’:

unsigned char var = 153; //двоичная запись 10011001
unsigned char mask = 0x11; // число 00010001
unsigned char res = var ^ mask; // результат 10001000

или

var ^= mask; // то же самое, что и var = var ^ mask;

Рассмотрим примеры использования логических операций, которые часто применяются на практике. Самой распространенной по использованию является операция логического И. Данная операция обычно используется совместно с так называемыми масками. Под маской понимают битовый шаблон, который служит для выделения тех или иных битов числа, к которому она применяется. Например, если требуется определить, является ли нулевой бит числа установленным в 1 или нет, то для этого задается маска 00000001, которая соответствует числу 1 и выполняется операция поразрядного И:

unsigned char flags = 3; // 00000011
unsigned char mask = 1; // 00000001
if((flag & mask) == 1) printf(“Нулевой бит включен”);
else printf(“Нулевой бит выключен”);

Здесь переменная flags, представленная одним байтом, содержит восемь флаговых битов. Для того чтобы узнать установлен или нет нулевой флаговый бит задается маска со значением 1 и выполняется операция логического И. В результате все биты переменной flags будут равны нулю за исключением нулевого, если он изначально имел значение 1. Таким образом, маска является шаблоном, который как бы накладывается на битовое представление числа, из которого выделяются биты, соответствующие единичным значениям маски. Рассмотренный пример показывает, как одна байтовая переменная flags может содержать восемь флаговых значений и тем самым экономить память ЭВМ.

Следующим примером использования логических операция является возможность включать нужные биты в переменной, оставляя другие без изменений. Для этого используется логическая операция ИЛИ. Допустим, в переменной flags необходимо установить второй бит равным 1. Для этого задается маска в виде переменной mask = 2 (00000010) и реализуется операция логического ИЛИ:

unsigned char flags = 0; // 00000000
unsigned char mask = 2; // 00000010
flags |= mask;

Этот код гарантирует, что второй бит переменной flags будет равен 1 без изменений значений других битов.

Для отключения определенных битов целесообразно использовать две логические операции: логическое И и логическое НЕ. Допустим, требуется отключить второй бит переменной flags. Тогда предыдущий пример запишется следующим образом:

unsigned char flags = 0; // 00000000
unsigned char mask = 2; // 00000010
flags = flags & mask;

или

flags &= mask;

Работа этих двух операций заключается в следующем. Приоритет операции НЕ выше приоритета операции И, поэтому переменная mask в двоичной записи будет иметь вид 11111101. Применяя операцию логического умножения переменной flags с полученным числом mask все биты останутся неизменными, кроме второго, значение которого будет равно нулю.

Наконец, операция исключающее ИЛИ позволяет переключать заданные биты переменных. Идея переключения битов основывается на свойствах операции исключающего ИЛИ: 1^1 = 0, 1^0 = 1, 0^0 = 0 и 0^1 = 1. Анализ данных свойств показывает, что если значение бита маски будет равно 1, то соответствующий бит переменной, к которой она применяется, будет переключен, а если значение бита маски равно 0, то значение бита переменной останется неизменным. Следующий пример демонстрирует работу переключения битов переменной flags.

unsigned char flags = 0; //00000000
unsigned char mask = 2; //00000010
flags ^= mask; //00000010
flags ^= mask; //00000000

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

10001010 << 2;

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

int var = 1;
var = var <<1; //00000010 – значение 2
var <<= 1; //00000100 – значение 4

Можно заметить, что смещение битов переменной на одну позицию влево приводит к операции умножения числа на 2. В общем случае, если выполнить сдвиг битов на n шагов, то получим результат равный умножению переменной 2 в степени n на . Данная операция умножения на число 2 в степени n является более быстрой, чем обычное умножения, рассматриваемое ранее.

Аналогично, при операции смещения вправо >> происходит сдвиг битов переменной на шаг, указанный в правом операнде. Например, сдвиг

00101011 >> 2;

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

int var = 128; //1000000
var = var >> 1; //0100000 – значение 64
var >>= 1; //0010000 – значение 32

значение переменной var каждый раз делится на 2. Поэтому сдвиг var >>= n можно использовать для выполнения операции деления значения переменной на величину 2 в степени n.

1.8. Директивы препроцессора

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

#define, #elif, #else, #endif, #if, #ifdef, #ifndef, #include, #undef.

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

#define <�идентификатор> <�текст>

или

#define <�идентификатор> (<�список параметров>) <�текст>

Следует заметить, что символ ‘;’ после директив не ставится. Приведем примеры вариантов использования директивы #define.

Листинг 1.2. Примеры использования директивы #define.

#include
#define TWO 2
#define FOUR TWO*TWO
#define PX printf(“X равно %d.\n”, x)
#define FMT «X равно %d.\n»
#define SQUARE(X) X*X
int main()
{
int x = TWO;
PX;
x = FOUR;
printf(FMT, x);
x = SQUARE(3);
PX;

return 0;
}

После выполнения этой программы на экране монитора появится три строки:

X равно 2.
X равно 4.
X равно 9.

Директива #undef отменяет определение, введенное ранее директивой #define. Предположим, что на каком-либо участке программы нужно отменить определение константы FOUR. Это достигается следующей командой:

#undef FOUR

Интересной особенностью данной директивы является возможность переопределения значения ранее введенной константы. Действительно, повторное использование директивы #define для ранее введенной константы FOUR невозможно, т.к. это приведет к сообщению об ошибке в момент компиляции программы. Но если отменить определение константы FOUR с помощью директивы #undef, то появляется возможность повторного использования директивы #define для константы FOUR.

Для того чтобы иметь возможность выполнять условную компиляцию, используется группа директив #if, #ifdef, #ifndef, #elif, #else и #endif. Приведенная ниже программа выполняет подключение библиотек в зависимости от установленных констант.

#if defined(GRAPH)
#include //подключение графической библиотеки
#elif defined(TEXT)
#include //подключение текстовой библиотеки
#else
#include //подключение библиотеки ввода-вывода
#endif

Данная программа работает следующим образом. Если ранее была задана константа с именем GRAPH через директиву #define, то будет подключена графическая библиотека с помощью директивы #include. Если идентификатор GRAPH не определен, но имеется определение TEXT, то будет использоваться библиотека текстового ввода/вывода. Иначе, при отсутствии каких-либо определений, подключается библиотека ввода/вывода. Вместо словосочетания #if defined часто используют сокращенные обозначения #ifdef и #ifndef и выше приведенную программу можно переписать в виде:

#ifdef GRAPH
#include //подключение графической библиотеки
#ifdef TEXT
#include //подключение текстовой библиотеки
#else
#include //подключение библиотеки ввода-вывода
#endif

Отличие директивы #if от директив #ifdef и #ifndef заключается в возможности проверки более разнообразных условий, а не только существует или нет какие-либо константы. Например, с помощью директивы #if можно проводить такую проверку:

#if SIZE == 1
#include // подключение математической библиотеки
#elif SIZE > 1
#include // подключение библиотеки обработки массивов
#endif

В приведенном примере подключается либо математическая библиотека, либо библиотека обработки массивов, в зависимости от значения константы SIZE.

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

Листинг 1.3. Пример компиляции отдельных блоков программы.

#include
#define SQUARE
int main()
{
int s = 0;
int length = 10;
int width = 5;

#ifdef SQUARE
s=length*width;
#else
s=2*(length+width);
#endif

return 0;
}

В данном примере происходит вычисление либо площади прямоугольника, либо его периметра, в зависимости от того определено или нет значение SQUARE. По умолчанию программа вычисляет площадь прямоугольника, но если убрать строку #define SQUARE, то программа станет вычислять его периметр.

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

#include < stdio.h >

указывает препроцессору добавить содержимое файла stdio.h вместо приведенной строки. Это дает большую гибкость, легкость программирования и наглядность создаваемого текста программы. Есть две разновидности директивы #include:

#include < stdio.h > - имя файла в угловых скобках

и

#include «mylib.h» - имя файла в кавычках

Угловые скобки сообщают препроцессору о том, что необходимо искать файл (в данном случае stdio.h) в одном или нескольких стандартных системных каталогах. Кавычки свидетельствуют о том, что препроцессору необходимо сначала выполнить поиск файла в текущем каталоге, т.е. в том, где находится файл создаваемой программы, а уже затем – искать в стандартных каталогах.

1.9. Функции ввода/вывода printf() и scanf()

Функция printf() позволяет выводить информацию на экран при программировании в консольном режиме. Данная функция определена в библиотеке stdio.h и имеет следующий синтаксис:

int printf( const char *format [, argument]... );

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

В самой простой реализации функция printf() просто выводит заданную строку на экран монитора:

printf(“Привет мир.”);

Однако с ее помощью можно выводить переменные разного типа: начиная с числовых и заканчивая строковыми. Для выполнения этой операции используются специальные управляющие символы, которые называются спецификаторами и которые начинаются с символа %. Следующий пример демонстрирует вывод целочисленной переменной num на экран монитора с помощью функции printf():

int num;
num = 5;
printf(“%d”, num);

В первых двух строках данной программы задается переменная с именем num типа int. В третьей строке выполняется вывод переменной на экран. Работа функции printf() выглядит следующим образом. Сначала функция анализирует строку, которую необходимо вывести на экран. В данном случае это «%d». Если в этой строке встречается спецификатор, то на его место записывается значение переменной, которая является вторым аргументом функции printf(). В результате, вместо исходной строки «%d» на экране появится строка «5», т.е. будет выведено число 5.

Следует отметить, что спецификатор «%d» выводит только целочисленные типы переменных, например int. Для вывода других типов следует использовать другие спецификаторы. Ниже перечислены основные виды спецификаторов:

%с – одиночный символ
%d – десятичное целое число со знаком
%f – число с плавающей точкой (десятичное представление)
%s – строка символов (для строковых переменных)
%u – десятичное целое без знака
%% - печать знака процента

С помощью функции printf() можно выводить сразу несколько переменных. Для этого используется следующая конструкция:

int num_i;
float num_f;
num_i = 5;
num_f = 10.5;
printf(“num_i = %d, num_f = %f”, num_i, num_f);

Результат выполнения программы будет выглядеть так:

num_i = 5, num_f = 10.5

Кроме спецификаторов в функции printf() используются управляющие символы, такие как перевод строки \n, табуляции \t и др. Например, если в ранее рассмотренном примере необходимо вывести значения переменных не в строчку, а в столбик, то необходимо переписать функцию printf() следующим образом:

printf(“num_i = %d,\n num_f = %f”, num_i, num_f);

Аналогично используется и символ табуляции.

Для ввода информации с клавиатуры удобно использовать функцию scanf() библиотеки stdio.h, которая имеет следующий синтаксис:

int scanf( const char *format [,argument]... );

Здесь, как и для функции printf(), переменная *format определяет форматную строку для определения типа вводимых данных и может содержать те же спецификаторы что и функция printf(). Затем, следует список необязательных аргументов. Работа функции scanf() демонстрируется на листинге 1.4.

Листинг 1.4. Пример использования функции scanf().

#include
int main()
{
int age;
float weight;
printf(“Введите информацию о Вашем возрасте: ”);
scanf(“%d”, &age);
printf(“Введите информацию о Вашем весе: ”);
scanf(“%f”, &weigth);
printf(“Ваш возраст = %d, Ваш вес = %f”, age, weigth);

return 0;
}

Основным отличием применения функции scanf() от функции printf() является знак & перед именем переменной, в которую записываются результаты ввода.

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

scanf(“ %d, %d ”, &n, &m);

Функция scanf() интерпретирует это так, как будто ожидает, что пользователь введет число, затем – запятую, а затем – второе число. Все происходит так, как будто требуется ввести два целых числа следующим образом:

88,221

или

88, 221

Функция scanf() возвращает число успешно считанных элементов. Если операции считывания не происходило, что бывает в том случае, когда вместо ожидаемого цифрового значения вводится какая-либо буква, то возвращаемое значение равно 0.

Контрольные вопросы и задания

  1. Каким образом можно задавать комментарии в программе написанной на языке С++?

  2. Запишите объявление целочисленной переменной с именем var_i.

  3. С каких символов должны начинаться имена переменных?

  4. Как изменится значение переменной i после выполнения операции i=i+1;?

  5. Какой результат получится после выполнения операции var=7/2;?

  6. Запишите вещественные типы переменных.

  7. Может ли переменная символьного типа char принимать целые числовые значения?

  8. Приведите пример использования функции printf() для вывода значений двух целочисленных переменных на экран.

  9. Запишите функцию scanf() для ввода символа с клавиатуры.

  10. Как в языке С++ записывается операция умножения?

  11. Какой результат получится после операции деления двух целочисленных переменных var1=7 и var2 = 2?

  12. Запишите директиву #define для задания константы с именем LENGTH равной 10.

  13. Приведите пример макроса, позволяющий возводить число в квадрат.

  14. С помощью каких директив можно выполнять условную компиляцию программы?

  15. Каким символом обозначается операция логическое И и что она делает?

  16. Как записывается операция логическое ИЛИ и для чего она предназначена?

  17. Запишите операцию логическое НЕ применительно к переменной var_i.

  18. Приведите пример использования операции исключающего ИЛИ и объясните полученный результат.

  19. С помощью какой поразрядной операции можно выполнять деление числа на 2?

  20. Запишите операцию умножения числа на 4 с помощью поразрядной операции.

2.2. Операторы цикла языка С++

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

2.2.1. Оператор цикла while

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

while(<�условие>)
{
<�тело цикла>
}

Приведем пример реализации данного цикла, в котором выполняется суммирование элементов ряда S = 0+1+2+3... пока S

int N=20, i = 0;
long S = 0L;
while(S < N)
{
S=S+i;
i++;
}

В данном примере реализуется цикл while с условием i < N. Так как начальное значение переменной i=0, а N=20, то условие истинно и выполняется тело цикла, в котором осуществляется суммирование переменной i и увеличение ее на 1. Очевидно, что на 20 итерации значение i=20, условие станет ложным и цикл будет завершен. Продемонстрируем гибкость языка С++, изменив данный пример следующим образом:

int N=20, i = 0;
long S = 0L;
while((S=S+i++) < N);

В данном случае при проверке условия сначала выполняются операторы, стоящие в скобках, где и осуществляется суммирование элементов ряда и только, затем, проверяется условие. Результат выполнения обоих вариантов программ одинаковый и S=21. Однако последняя конструкция бывает удобной при реализации опроса клавиатуры, например, с помощью функции scanf():

int num;
while(scanf(“%d”,#) == 1)
{
printf(“Вы ввели значение %d\n”,num);
}

Данный цикл будет работать, пока пользователь вводит целочисленные значения и останавливается, если введена буква или вещественное число. Следует отметить, что цикл while можно принудительно завершить даже при истинном условии цикла. Это достигается путем использования оператора break. Перепишем предыдущий пример так, чтобы цикл завершался, если пользователь введет число 0.

int num;
while(scanf(“%d”,&mun) == 1)
{
if(num == 0) break;
printf(“Вы ввели значение %d\n”,num);
}

Цикл завершается сразу после использования оператора break, т.е. в приведенном примере, при вводе с клавиатуры нуля функция printf() выполняться не будет и программа перейдет на следующий оператор после while. Того же результата можно добиться, если использовать составное условие в цикле:

int num;
while(scanf(“%d”,&mun) == 1 && num != 0)
{
printf(“Вы ввели значение %d\n”,num);
}

Таким образом, в качестве условия возможны такие же конструкции, что и в операторе if.

2.2.2. Оператор цикла for

Работа оператора цикла for подобна оператору while с той лишь разницей, что оператор for подразумевает изменение значения некоторой переменной и проверки ее на истинность. Работа данного оператора продолжается до тех пор, пока истинно условие цикла. Синтаксис оператора for следующий:

for(<�инициализация счетчика>;<�условие>;<�изменение значения счетчика>)
{
<�тело цикла>
}

Рассмотрим особенность реализации данного оператора на примере вывода таблицы кодов ASCII символов.

char ch;
for(ch = ‘a’; ch <= ‘z’; ch++)
printf(“Значение ASCII для %c - %d.\n”,ch,ch);

В данном примере в качестве счетчика цикла выступает переменная ch, которая инициализируется символом ‘a’. Это означает, что в переменную ch заносится число 97 – код символа ‘a’. Именно так символы представляются в памяти компьютера. Код символа ‘z’ – 122, и все малые буквы латинского алфавита имеют коды в диапазоне [97; 122]. Поэтому, увеличивая значение ch на единицу, получаем код следующей буквы, которая выводится с помощью функции printf(). Учитывая все вышесказанное, этот же пример можно записать следующим образом:

for(char ch = 97; ch <= 122; ch++)
printf(“Значение ASCII для %c - %d.\n”,ch,ch);

Здесь следует отметить, что переменная ch объявлена внутри оператора for. Это особенность языка С++ - возможность объявлять переменные в любом месте программы.

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

int line_cnt = 1;
double debet;
for(debet = 100.0; debet < 150.0; debet = debet*1.1, line_cnt++)
printf(“%d. Ваш долг теперь равен %.2f.\n”,line_cnt, debet);

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

int exit = 1;
for(int num = 0;num < 100 && !exit; num += 1)
{
scanf(“%d”,&mov);
if(mov == 0) exit = 0;
printf(“Произведение num*mov = %d.\n”,num*mov);
}

Оператор for с одним условием:

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

и без условия

int i=0;
for(;;;) {i++; if(i > 100) break;}

В последнем примере оператор break служит для выхода из цикла for, т.к. он будет работать «вечно» не имея никаких условий.
  1   2   3   4   5   6   7   8
написать администратору сайта