Министерство образования и науки Российской Федерации 2 страница

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

/* prog1.c */

main()

{

return 0;

}

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

Основными компонентами системного программного обеспечения служат редактор, компилятор, компоновщик, библиотеки. Какие функции выполняет каждый компонент?

Что означают расширения файлов .c, .obj, .exe, .lib?

Что такое код возврата программы?

Напишите программу, которая возвращает операционной системе число 7.

4. КОМАНДНЫЕ ФАЙЛЫ

Нам придется много раз компилировать программы, написанные на языке С. Достаточно утомительно каждый раз переписывать все параметры командной строки. Поэтому мы составим командный файл, который будет запускать компилятор в пакетном режиме. Этот файл также создается при помощи редактора notepad.exe, он должен иметь расширение .bat. Так как его основная работа – запуск компилятора bcc32.exe, то назовем его bcc.bat.

Наберем команду

notepad.exe bcc.bat,

подтвердим создание нового файла и введем в редактор следующий тект:

rem bcc.bat

if “%1”==“” goto error

path C:\Test\Bcc

bcc32.exe -I“C:\Test\Include” -L“C:\Test\Lib” %1.c

goto end

:error

echo Вы забыли указать имя программы (без расширения .c)

:end

Этот файл написан не на языке С, а на командном языке сеанса MS DOS. Его не надо компилировать, операционная система читает одну команду за другой и выполняет их. Расширение bat происходит от слова batch – пакет, оно означает, что файл выполняет группу команд как единое целое. Первая строка командного файла начинается со слова rem, это – начало комментария, концом комментария служит перевод строки. Как мы договорились, комменатрий должен содержать имя файла. Вторая строка содержит конструкцию %1; так обозначается аргумент пакетного файла. Теперь составим программу

/* prog2.c */

main()

{

return 2;

}

Если мы наберем в командной строке

bcc.bat prog2

то %1 будет именем слова prog2. Когда в командной строке стоит только имя пакетного файла bcc.bat аргумент пустой, “%1” - это просто пара двойных кавычек, два знака == - отношение равенства. Слово if служит началом оператора ветвления в пакетном файле, его формат

if [ NOT ] строка1 == строка2 команда

Операция NOT обращает истинность условия: истинное условие становится ложным, а ложное – истинным. Условие

строка1 == строка2

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

Слово NOT заключено в квадратные скобки, это означает, что оно является необязательной частью конструкции. Команду

if %1”==“” goto error

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

Если пользователь ввел аргумент – имя программы, то вместо перехода на метку error выполняется команда

path C:\Test\Bin

- теперь операционная система будет искать исполняемые файлы лишь в текущей директории и в директории Bin. Часто студенты говорят, что эта команда не нужна, «программа компилируется и так». На самом деле это означает, что список директорий поиска исполняемых файлов содержит путь к директории Bin пакета CBuilder, так что компилятор и компоновщик вызываются оттуда, откуда мы их копировали.

Следующая строка – вызов компилятора bcc32.exe с параметрами, указывающими имена директорий включаемых файлов и библиотек. Аргументом компилятора служит имя программы, в нашем случае – это аргумент пакетного файла %1. У любого файла с исходным текстом на языке С должно быть расширение .с; чтобы не повторять его каждый раз, мы передаем пакетному файлу имя файла - программы без расширения, а имя с расширением появляется при помощи конструкции %1.с. Команда безусловного перехода goto end позволяет обойти сообщение об ошибке, следующее за меткой error. После метки end команд нет, выполнение пакетного файла завершается.

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

@echo off

(символ @ подавляет вывод на экран самой команды echo off):

rem bcc.bat

@echo off

if “%1”==“” goto error

path C:\Test\Bcc

bcc32.exe -I“C:\Test\Include” -L“C:\Test\Lib” %1.c

goto end

:error

echo Вы забыли указать имя программы (без расширения .c)

:end

Задание. Составьте пакетный файл bcc.bat и убедитесь, что он корректно работает.

Код, который программа возвращает операционной системе в момент завершения, позволяет эмулятору командной строки управлять последовательностью выполнения команд пакетного файла. Для этого используется конструкция errorlevel. Оператор ветвления с этой конструкцией имеет такой формат:

"if [ NOT ] ERRORLEVEL число команда.

Условие

ERRORLEVEL число

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

Составим пакетный файл

rem test.bat

@echo off

prog2.exe

if ERRORLEVEL %1 echo Код возврата не меньше, чем %1

Исполняемый файл prog2.exe, полученный в результате компиляции программы prog2.c, возвращает операционной системе число 2 и завершается. Напомним, что программа test.bat представляет собой пакетный файл, её не надо компилировать. Запустим файл test/bat с аргументом 0:

test. bat 0

Первая команда после @echo off запускает файл prog2.exe.

Следующая команда состоит из двух частей. Первая часть - if ERRORLEVEL %1 - проверяет код возврата завершившейся программы и сравнивает его с аргументом - в нашем случае аргумент равен 0. Так как код возврата 2 не меньше, чем 0, то выполняется вторая часть: команда echo выводит на экран стоящее после неё сообщение: "Код возврата не меньше, чем 2". Запустим пакетный файл, увеличив аргумент:

test.bat 1.

На экране появится сообщений "Код возврата не меньше, чем 1". Запустим пакетный файл test.bat с аргументом 2. Условие ERRORLEVEL %1 по-прежнему будет истинным: 2 не меньше, чем 2. Команда echo выводит на экран сообщение: "Код возврата не меньше, чем 2". А после запуска

test.bat 3

на экране не появится никаких сообщений: код возврата 2 меньше, чем 3.

Задание. Cоставьте пакетный файл

rem test.bat

@echo off

prog2.exe

if NOT ERRORLEVEL %1 echo %1

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

test.bat 0

test.bat 1

test.bat 2

test.bat 3

5. ВЫВОД СИМВОЛЬНОЙ ИНФОРМАЦИИ

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

C:\Test\Include

_defs.h

_nfile.h

_null.h

_stddef.h

stdio.h

Расширение h представляет собой сокращение слова header – заголовок. В тексте программы следует указать только один из файлов – stdio.h (standard input/output – стандартный ввод/вывод).

Создадим с помощью редактора notepad.exe в директории C:\Test\Apps файл с исходным текстом программы prog3.c:

/*prog3.c*/

#include <stdio.h>

main

{

printf (“I am a student”);

return 0;

}

На первом этапе компиляции исходный текст программы обрабатывает специальный компонент компилятора, который называется препроцессором. Препроцессор изменяет программу так, чтобы её смог прочитать компилятор. В частности, он выполняет директивы, содержащиеся в исходном тексте. Каждая директива начинается с символа # - знака номера, или, как говорят программисты, «решётки». В отличие от команд, в конце директивы точка с запятой не ставится. Директива include имеет вид

#include <имя_файла>

Выполняя директиву include, препроцессор вставляет на её место содержимое указанного файла.

Стандартная функция printf (print – печатать, format – формат, способ представления данных) осуществляет вывод на экран содержимого строки – аргумента. Строка в языке С заключается в двойные кавычки.

Откомпилируем программу командой

bcc32.exe –I“C:\Test\Include” -L“C:\Test\Lib” prog3.c

Если программа составлена правильно, в директории Apps должен появиться файл prog2.exe. Запустив его, мы увидим на экране надпись “I am a student”.

Для того, чтобы функция printf не только выводила сообщения, но и осуществляла переход на новую строку, надо включить в строку управляющий символ \n:

printf (“I am a student\n”);

Если мы хотим отделить сообщение от последующих команд пустой строкой, то надо поставить два символа перевода строки:

printf (“I am a student\n\n”);

Вопросы для повторения:

Объясните, для чего нужна директива #include <stdio.h> в исходном тексте программы;

Что такое комментарии в исходном тексте программы? Объясните их назначение.

6. ОПЕРАЦИИ С ЦЕЛЫМИ ЧИСЛАМИ

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

/*prog4.c*/

#include <stdio.h>

main()

{

int x = 17, y = 18, z;

z = x*y;

printf(“17 * 18 = %d\n”, z);

return 0;

}

Первой командой тела функции main является объявление переменных целого типа x, y и z. Слово int (integer-целых) – это имя типа; объявление выделяет в памяти две ячейки для хранения целых чисел. При объявлении переменных x и y выполняется их инициализация – в ячейку х помещается значение 17, а в ячейку y – 18. В следующей строке – операция присваивания, значения переменных x и y перемножаются и результат помещается в ячейку z. Произведение x * y представляет собой выражение, перемножаются те значения, которые были присвоены переменным в ходе инициализации.

Результат работы программы – в нашем случае произведение чисел 17 и 18 – надо каким-то образом сообщить пользователю. Для этого используется функция printf. Теперь у нее два аргумента. Первый аргумент, как и прежде, строка, функция выводит ее на экран один ее символ за другим, пока не дойдет до знака %, он отмечает начало спецификации формата. Следующий за ним символ определяет представление второго аргумента функции - константы, переменной или выражения, d означает, что значение должно быть выведено в виде десятичного числа. Закончив вывод значения аргумента, функция printf продолжает выводить символы строки, пока не пройдет ее всю. Если в строке встретится новая спецификация формата, то она определит представление на экране следующего аргумента функции printf. После выполнения программы на экране должно появиться сообщение: 17 * 18 = 306.

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

int x=17, y=17*18;

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

int x = 17, y;

y = x * 18;

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

/*prog5.c*/

#include <stdio.h>

main()

{

int x, y, z;

z = x * y;

scanf ( “%d %d”, &x, &y);

printf ( “%d * %d = %d\n”, x, y, z );

return 0;

}

когда мы запустим исполняемый файл, полученный при компиляции этой программы, компьютер перейдет в состояние ожидания ввода данных. Наберем значения 17 18 и нажмем Enter (ввод). На экране снова появится сообщение 17 * 18 = 306. Но теперь мы можем перемножать и другие пары чисел, например, если мы введем 44 55, то получим 44 * 55 = 2420. Объявляя переменные x и y, мы их не инициализируем. Функция scanf должна содержать не менее двух аргументов – строку со спецификациями формата и ссылки на переменные. Спецификации формата у функций printf и scanf совпадают. Знак & (амперсанд) перед переменной означает операцию ссылки, т.е. определение адреса переменной. Когда переменная встречается в составе выражения (в частности, когда она служит аргументом функции), компилятор интерпретирует её как синоним значения, присвоенного ранее этой переменной. Рассмотрим снова фрагмент программы:

int x = 17, y = 18, z;

z = x * y;

printf ( “%d\n”, x );

После инициализации переменная х получила значение 17, а y – 18. при вычислении выражения х * у перемножаются именно эти значения. Новое присваивание помещает в ячейку z значение 306, его и выводит функция printf. Функция scanf помещает значение, которое ввел пользователь, в ячейку, именем которой служит х, выражение &х передает функции scanf адрес этой ячейки.

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

/*prog6.c*/

#include <stdio.h>

main()

{

int x, y;

scanf ( “х = %d у = %d”, &x, &y );

printf ( “%d * %d = %d\n”, x, y, x * y );

return 0;

}

Теперь пользователь должен ввести данные в таком виде:

х=17 у=18

Символы х, =, у, = функция прочитает, но сохранит лишь значения 17 и 18. Если пользователь вместо х, у, = наберёт другие символы, выполнение программы прекращается и на экране появляется сообщение об ошибке.

Значения типа int могут быть как положительными, так и отрицательными. Мы будем в основном работать с целыми неотрицательными числами. Они относятся к типу unsigned int – целых без знака. Каждый раз набирать в объявлении переменных оба слова неудобно, поэтому мы воспользуемся директивой препроцессора #define:

#define UINT unsigned int

Она заставляет препроцессор заменять в исходном тексте программы все вхождения параметра UINT директивы define словами unsigned int. Параметры директивы define всегда следует писать заглавными буквами.

Перечислим знаки основных арифметических операций над целыми числами:

+ сложить,

- вычесть,

* умножить,

/ выполнить целочисленное деление (деление с остатком)

% вычислить остаток от деления.

Как мы видим, символ % внутри первого аргумента функций printf, scanf интерпретируется как часть спецификации формата, а в арифметическом выражении – как знак операции вычисления остатка от деления одного числа на другое. Такие символы называются перегруженными. Значение перегруженного символа определяется его контекстом - той конструкцией, в состав которой он входит. Наличие перегруженных символов в языке программирования напоминает явление полисемии (многозначности) в естественном языке. Большая часть слов имеет не одно, а много значений: нос, коса, лист и т.п. Полисемия позволяет выражать самые разные мысли при помощи сравнительно небольшого запаса слов.

Спецификация формата %u, означает, что следует вводить и выводить целые числа без знака. Разность чисел х и у может быть как положительной, так и отрицательной, поэтому при её выводе следует сохранить спецификацию формата %d.

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

Вопросы для повторения:

приведите примеры констант, переменных, выражений, объясните их синтаксис и семантику;

объясните синтаксис и семантику объявления переменных и инициализации;

что такое спецификация формата? какие спецификации формата Вы знаете?

приведите примеры константных выражений и выражений, которые, по Вашему мнению, не являются константными. В чем разница между ними? Где используются константные выражения?

что такое операция ссылки на переменную? Объясните ее синтаксис и семантику. Где она применяется?

для чего применяется директива препроцессора #define?

Задание

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

7. ОПЕРАЦИИ С ВЕЩЕСТВЕННЫМИ ЧИСЛАМИ

Вещественные числа относятся к типам float и double. Английское слово float обозначает плавать. Плавающими числами, точнее, числами с плавающей точкой называют вещественные числа, представленные в виде a * bp, число a называется мантиссой, во внутреннем представлении вещественных чисел мантисса удовлетворяет условию 0.5 < a <=1. Число b равно 2 (во внутреннем представлении) или 10 (при выводе значения вещественного числа на экран), целое число p – порядок числа – может быть как положительным, так и отрицательным. Слово double означает двойной – вычисления выполняются с двойной точностью. Присваивая вещественному числу значение, выраженное десятичной дробью, ИСПОЛЬЗУЙТЕ ДЕСЯТИЧНУЮ ТОЧКУ. Ввод и вывод вещественных чисела осуществляется со спецификацией %f:

float x = 2.1, y = 3.8, z;

z = ( x + y ) / 2;

printf ( “среднее арифметическое чисел %f и %f равно %f”, x, y, z );

Для работы с функциями вещественных аргументов надо добавить в программу директиву препроцессору

#unclude<math.h>

(вставить заголовочный файл math.h) или описать эти функции перед функцией main, указав типы аргумента и возвращаемого значения:

double sin ( double x ) - синус;

double cos ( double x ) - косинус;

double tan ( double x ) - тангенс;

double asin ( double x ) - арксинус;

double acos ( double x ) - арккосинус;

double atan ( double x ) - арктангенс;

double exp ( double x ) - экспоненциальная функция;

double log ( double x ) - натуральный логарифм;

double log10 ( double x ) - десятичный логарифм;

double sqrt ( double x ) - квадратный корень;

double fabs ( double x ) - абсолютная величина;

Задания

(7.1) Составьте программу, которая вычисляет квадрат вещественного числа, поступающего на её вход.

(7.2) Составьте программу, которая вычисляет площадь треугольника по трём известным сторонам.

(7.3) Составьте программу, которая вычисляет среднее арифметическое трёх вещественных чисел.

(7.4) Составьте программу, которая вычисляет стороны прямоугольного треугольника по катету и прилежащему углу.

(7.5) Составьте программу, которая вычисляет стороны прямоугольного треугольника по катету и противолежащему углу.

(7.6) Составьте программу, которая вычисляет стороны прямоугольного треугольника по гипотенузе и острому углу.

(7.7) Составьте программу, которая вычисляет длину гипотенузы прямоугольного треугольника и его углы по двум катетам.

8. ОПЕРАТОРЫ

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

if ( условие )

команда1

[ else

команда2 ]

Сначала программа проверяет истинность условия. Если условие истинно, то выполняется команда1, если нет, и присутствует ключевое слово else – то выполняется команда2. Затем управление передается команде, следующей за ветвлением.

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

/*prog7.c*/

//программа вычисляет абсолютную величину вещественного числа

#include <stdio.h>

main()

{

float x, y;

scanf ( “х = %f”, &x );

if ( x >= 0 )

y = x;

else

y = - x;

printf ( “ | %f | = %f\n”, x, y );

return 0;

}

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

if ( условие )

{

команда1a

команда1b

...

}

[ else

{

команда2a

команда2b

...

}

]

Условие оператора ветвления обычно включает в себя операции сравнения:

> - больше;

< - меньше;

>= - больше или равно;

<= - меньше или равно;

== - равно (равняется)

!= - не равно.

Определённые трудности вызывает операция “==”. В языке математики символ равенства “=” обозначает две разных операции: присваивание (x = 1 – переменной x присваивается значение 1) и сравнения ( 2 = 2 – утверждение, что 2 равно 2).В языке C символ “=” обозначает операцию присваивания, слева от него должна стоять переменная, эта операция возвращает значение присвоенной переменной. Например, в результате выполнения команды x = ( y = 2 ) переменным x и y будет присвоено одно и то же значение – число 2. Операция сравнения обозначается с помощью символа “==”, слева и справо от него стоят выражения, результат операции сравнения может быть ложью или истиной. В языке C лжи соответствует число 0, а истине – неналевое число, как правило, это 1. Таким образом, результатом операции 2 == 2 является истина (1), а результатом операции 2 == 1 – ложь (0).

Логические операции:

&& - конъюнкция (и);

|| - дизъюнкция (или);

! - отрицание (не).

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

while ( условие )

тело цикла.

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

/*prog8.c*/

//программа вычисляет сумму квадратов чисел 1, 2,..., n

#include <stdio.h>

main()

{

unsigned int n, s = 0, i = 0; /* переменная s является сумматором, в ней будет накапливаться сумма чисел от 1 до n; переменные n и s относятся к типу “целые без знака” */.

scanf ( “n = %u”, &n );

while ( i < n )

{

s = s + i * i;

i++;

}

printf ( “ 1 * 1 + 2 * 2 +...+ %u * %u = %u\n”, n, n, s );

return 0;

}

Эту же задачу можно решить с использованием цикла for:

/*prog9.c*/

//программа вычисляет сумму квадратов чисел 1, 2,..., n

#include <stdio.h>

main()

{

unsigned int n, s, i; /* переменная s является сумматором, в ней будет накапливаться сумма чисел от 1 до n; переменные n и s относятся к типу “целые без знака” */.

scanf ( “n = %u”, &n );

for ( i = 1, s = 0; i <= n; i++)

s = s + i * i;

printf ( “ 1 * 1 + 2 * 2 +...+ %u * %u = %u\n”, n, n, s );

return 0;

}

Операции, которые отделяются друг от друга запятой, в языке С образуют единое целое; таким образом, в начале цикла for переменной i присваивается значение 1, а сумматору s - значение 0. После каждого прохода цикла значение переменной i увеличивается на 1, а к значению s программа прибавляет квадрат значения i. Повторение цикла прекратится, когда значение переменной i будет больше 1.

/*prog10.c*/

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

#include <stdio.h>

main()

{

unsigned int i, s = 0; /* переменная s является сумматором, в ней будет накапливаться сумма чисел, которые вводит пользователь; в ячейке i хранится очередное число, прочитанное программой; переменные i и s относятся к типу “целые без знака” */.

scanf ( “%u”, &i );

while ( i != 0 )

{

s = s + i;

scanf ( “%u”, &i );

}

printf ( “ сумма введённых ччисел равна %u\n”, s );

return 0;

}

Составьте программы для решения следующих задач:

(8.1) на вход поступают два целых числа, программа определяет, равны они или нет;

(8.2) на вход поступают два разных вещественных числа, программа выводит на экран снечала большее число, а под ним меньшее;

(8.3) на вход поступают три вещественных числа, программа определяет, есть ли среди них положительные числа;

(8.4) на вход поступают три вещественных числа, программа определяет, есть ли среди них отрицательные числа;

(8.5) на вход поступают три целых числа, программа определяет, есть ли среди них совпадающие числа;

(8.6) на вход поступают три вещественных числа, программа определяет, могут ли они быть сторонами треугольника;

(8.7) на вход поступают три вещественных числа, программа определяет, могут ли они быть сторонами треугольника;

(8.8) на вход поступает целое положительное число n, программа вычисляет произведение чисел 1, 2,..., n (значение n! - n факториал);

(8.9) на вход поступают целые неотрицательные числа, программа вычисляет их сумму; ввод чисел завершается, когда пользователь введёт отрицательное число;

(8.10) на вход поступают ненулевые целые числа, программа подсчитывет, сколко среди них положительных чисел и сколько отрицательных чисел; ввод чисел завершается, когда пользователь введёт нуль;

(8.11) на вход поступают целые числа, программа подсчитывет, сколко среди них положительных чисел и сколько отрицательных чисел; ввод чисел завершается, когда пользователь введёт два нуля подряд;

9. СИМВОЛЫ И СТРОКИ

Символьные константы в языке С относятся к типу char (character - буква). Их можно представлять как в виде числовых значений ASCII-кода, так и в виде соответствующих символов, в исходном тексте программы эти символы следует заключать в апострофы (одинарные кавычки). Для вывода символьной константы в виде символа используют спецификацию формата %с.

Наши рекомендации