- •А. Нейбауэр.
- •Глава 1. Основы программирования 11
- •Глава 3. Переменные и константы 39
- •Глава 6. Операторы 103
- •Глава 13. Как собрать все вместе 253
- •Благодарности
- •Введение
- •Что вам даст эта книга
- •Программные средства
- •Глава 1. Основы программирования
- •Компьютерная программа
- •Языки программирования
- •Компиляторы
- •Интерпретатор
- •Скорость
- •Переносимость
- •Структурирование
- •Библиотеки функций
- •Необходимые пояснения
- •Что такое объектно-ориентированное программирование
- •Что Си может и чего не может
- •Этапы программирования
- •План программы
- •Текст программы
- •Компиляция программы
- •Компоновка программы
- •Тестирование программы
- •Изучение основ программирования
- •Что нужно, чтобы писать программы
- •Структура программы
- •Прописные и строчные символы
- •Инструкция return
- •Использование комментариев
- •Понятие параметров
- •Директива #include
- •Проектирование программы
- •Глава 3. Переменные и константы
- •Символьные данные
- •Целочисленные величины
- •Вещественные числа
- •Почему надо использовать целые числа?
- •Константы и переменные
- •Имена констант и переменных
- •Определение констант
- •Почему используют константы?
- •Определение переменных
- •Присваивание значения
- •Определение строковой переменной
- •Типы данных и функции
- •Литералы
- •Проектирование программы
- •Функция puts()
- •Функция putchar()
- •Двойственность символьных переменных
- •Управляющие коды
- •Код «новая строка»
- •Код «табуляция»
- •Код «возврат каретки»
- •Код «возврат на шаг»
- •Код «перевод страницы»
- •Отображение специальных символов на экране монитора
- •Многогранная функция printf()
- •Вывод чисел
- •Перевод строки
- •Преобразование типов данных
- •Форматированный вывод
- •Выбор правильных средств вывода информации
- •Проектирование программы
- •Функция gets()
- •Функция getchar()
- •«Для продолжения нажмите Enter»
- •Оператор получения адреса &
- •Функция scanf()
- •Входной поток
- •Использование функции scanf()
- •Выбор соответствующих средств ввода данных
- •Будьте осторожны при использовании scanf()
- •Неинициализированные переменные
- •Используемые алгоритмы ввода
- •Глава 6. Операторы
- •Арифметические операторы
- •Деление нацело
- •Типыданныхи операторы
- •Выражения
- •Приоритет операторов и порядок вычислений
- •Используемые алгоритмы обработки данных
- •Счетчики
- •Операторы инкремента
- •Аккумуляторы
- •Операторы присваивания
- •Присваивание начального значения
- •Проектирование программы
- •Остерегайтесь логических ошибок
- •Ищите образцы
- •Диагностические проблемы
- •Глава 7. Для чего нужны функции
- •Как использовать функции
- •Переменные в функциях
- •Автоматические (локальные) переменные
- •Внешние (глобальные) переменные
- •Статические переменные
- •Передача параметров
- •Возвращаемые значения
- •Возврат значений типа float
- •Использование return() в функции main()
- •Использование макроопределений
- •Проектирование программы
- •Автоматические или внешние переменные?
- •Неправильный ввод
- •Глава 8. Позвольте компьютеру принимать решения
- •Условия
- •Составные инструкции
- •Конструкция if...Else
- •Дополненный Опросник
- •Логические операторы
- •Вложенные инструкции if
- •Конструкция switch/case/default
- •Проверка чисел с плавающей точкой и строк
- •Проектирование программы
- •Проверка правильности ввода
- •Глава 9. Циклы
- •Использование цикла for
- •Создание паузы в программе
- •Составные инструкции
- •Использование переменных
- •Вложенные циклы
- •Использование цикла do...While
- •Вложенные циклы do
- •Использование цикла while
- •Комбинирование циклов разных типов
- •Проектирование программы
- •Использование флагов
- •Использование инструкции break
- •Глава 10. Массивы и строки
- •Массивы
- •Определение массива
- •Ввод значений в массив
- •Работа с массивами
- •Просмотр массива
- •Поиск в массиве
- •Передача массива функции
- •Использование массивов
- •Сравнение двух строк
- •Определение длины строки
- •Присваивание строк
- •Слияние строк
- •Массивы строк
- •Проектирование программы
- •Глава 11. Структуры и указатели
- •Использование структур
- •Определение структуры
- •Определение структурных переменных
- •Присвоение начального значения
- •Использование структуры
- •Массивы структур
- •Структуры и функции
- •Указатели
- •Указатели и функции
- •Глава 12. Вывод на диск и принтер
- •Что такое файловая структура
- •Указатель на файл
- •Как открыть файл
- •Как избежать ошибок выполнения
- •Как закрыть файл
- •Функции ввода и вывода
- •Работа с символами
- •Посимвольное чтение из файла
- •Работа со строками
- •Чтение строк
- •Форматированный ввод и вывод
- •Чтение форматированных файлов
- •Работа со структурами
- •Чтение структур
- •Чтение в массив
- •Дополнение файла новыми данными
- •Текстовый и двоичный форматы
- •Двоичный формат
- •Печать данных
- •Проектирование программы
- •Глава 13. Как собрать все вместе
- •Прикладная программа
- •Глобальные определения
- •Функция main()
- •Добавление записей: функция addcd()
- •Удаление записи: функция delcd()
- •Редактирование данных: функция chcd()
- •Изменение номера ячейки: функция chloc()
- •Вывод записи на экран: функция locate()
- •Печать записей: функция plist()
- •Сортировка записей: функция sort()
- •Приложение I Ответы и решения Глава 1. Основы программирования.
- •Глава 3. Переменные и константы.
- •Глава 6. Операторы.
- •Глава 7. Для чего нужны функции.
- •Глава 8. Позвольте компьютеру принимать решения.
- •Глава 9. Циклы.
- •Глава 10. Массивы и строки.
- •Глава 11. Струтуры и указатели.
- •Глава 12. Вывод на диск и принтер.
- •Приложение II Прикладная программа
Приоритет операторов и порядок вычислений
Когда компьютер встречает уравнение, он выполняет математические действия не просто слева направо. Прежде всего он просматривает строку и определяет порядок выполнения операций, основываясь на приоритете операторов. Приоритет операторов означает, что одни операторы выполняются раньше других независимо от того, в какой последовтельности они записаны в уравнении. Приоритет операторов умножения и деления выше, чем приоритет сложения и вычитания, что совпадает с последовательностью выполнения математических действий в уравнении (вспомните школьные примеры на «порядок действий»).
Компьютер просматривает уравнение и выполняет все операции умножения и деления в том порядке, в каком они записаны в инструкции, не отдавая предпочтения ни одному из двух действий. Если оператор деления стоит перед оператором умножения, деление будет выполнено первым. Промежуточные результаты помещаются в специальной, временно отведенной для этого области памяти*. После выполнения всех операций умножения и деления, компьютер возвращается к началу выражения и выполняет сложение и вычитание в порядке, соответствующем расположению операторов.
Рассмотрим простое уравнение:
a = 1 + 4 / 2 * 5 + 3;
Если выполнять действия просто слева направо, не отдавая предпочтения ни одному из них, полученный результат будет равен 15.5 (рис.6.5). Однако компьютер учитывает порядок выполнения математических операций, и результат поэтому получится равным 14 (на рис.6.6 показано, как вычисляется этот результат). Когда вы пишете программу, следует внимательно следить за тем, выполняются ли математические операции в желаемом порядке.
Рис. 6.5. Выполнение математических операций без учета приоритета
Рис. 6.6. Компьютер выполняет математические операциис учетом приоритета операторов
____________________________________
* Автор имел в виду машинный стек, но на самом деле современные компиляторы чаще сохраняют промежуточные результаты вычислений на регистрах центрального процессора, а значения выражений, не содержащих имен переменных, вычисляют еще на стадии компиляции. (Прим.перев.)
Очень часто начинающие программисты допускают ошибку при расчетах средних значений. В Листинге 6.3 приведен текст программы, в которой сделана попытка ввести три числа и вычислить их среднее арифметическое. Мы говорим «попытка», так как полученное в результате работы этой программы значение будет неправильным. Проверьте, сможете ли вы определить, почему?
Листинг 6.3. Неправильная программа расчета среднего арифметического значения трех чисел.
/*average.c*/
main()
{
float number_1, number_2, number_3, average;
printf("Введите первое число: ");
scanf("%f", &number_1);
printf("Введите второе число: ");
scanf("%f", &number_2);
printf("Введите третье число: ");
scanf("%f", &number_3);
average = number_1 + number_2 + number_3 / 3;
printf("Среднее арифметическое равно %f", average);
}
Ошибка содержится в инструкции
average = number_1 + number_2 + number_3 / 3;
Дойдя до этой строки программы, компьютер будет выполнять математические действия в следующем порядке:
Поделит значение переменной number_3 на 3.
Сложит значения переменных number_1 и number_2 и прибавит к ним результат деления.
Если вы присвоите каждой переменной значение 100, выведенное на экран среднее арифметическое будет равняться 233.33. Вот правильная запись этой строки инструкций:
average = (number_1 + number_2 + number_3) / 3;
Круглые скобки изменяют порядок приоритетов. Просматривая эту строку, компьютер прежде всего выполнит действия в скобках, затем вернется к началу строки и выполнит остальные операции в соответствии с обычным приоритетом операторов, о котором мы только что говорили. Таким образом, в нашей программе будет сперва выполнено сложение трех чисел в скобках, а потом результат поделен на 3 (рис.6.7). Вуаля! Получился правильный ответ.
Рис. 6.7. Правильная формула расчета среднего арифметического значения
Рис. 6.8. Использование нескольких уровней круглых скобок
Для того чтобы установить нужный порядок выполнения операций, можно использовать несколько уровней скобок (рис.6.8). Порядок выполнения операций установлен от самых внутренних скобок к наружным.
Рассмотрим пример. Допустим, работник получает оплату в двойном размере за каждый час, проработанный сверх 40-часовой рабочей недели. Полагая, что он работает как минимум 40 часов и, соответственно, получает плату как минимум за 40 рабочих часов, расчет недельного заработка состоит из следующих частей:
40 * rate /* обычный недельный заработок */
hours – 40 /* сверхурочные часы */
rate * 2 /* оплата сверхурочных */
где rate — плата за 1 час работы, а hours — общее количество проработанных часов. В этом уравнении надо умножить количество сверхурочных часов на оплату в двойном размере, а затем прибавить полученный результат к обычной недельной оплате. Если вы напишете уравнение без учета приоритета операторов, оно будет выглядеть так:
total = 40 * rate + hours - 40 * rate * 2
Допустим теперь, некто проработал 48 часов в неделю, причем его обычный заработок составляет 10 долларов в час. В приведенном уравнении операции будут выполняться в следующем порядке:
Операция |
Результат |
40 * rate |
400 |
40 * rate |
400 |
400 * 2 |
800 |
400 + 48 |
448 |
448 – 800 |
–352 |
Согласитесь, что получить недельный заработок в размере –352 доллара несколько обидно. Чтобы написать правильное уравнение, используйте скобки: total = (40 * rate) +((hours - 40) * (rate * 2)) Теперь уравнение состоит из двух логических частей (полный текст программы приведен в Листинге6.4). В первых скобках вычисляется обычная заработная плата, во вторых — оплата сверхурочных. Расчет сверхурочных тоже состоит из двух частей, заключенных в собственные скобки. Си прежде всего выполнит операции во внутренних скобках. Порядок выполнения действий теперь станет таким:
Операция |
Результат |
40 * rate |
400 |
hours – 40 |
8 |
rate * 2 |
20 |
8 * 20 |
160 |
400 + 160 |
560 |
Листинг 6.4. Программа расчета недельного заработка с учетом сверхурочных.
/*payroll1.c*/
main()
{
float rate, hours, total;
printf("Введите оплату одного часа работы: ");
scanf("%f", &rate);
printf("Введите количество отработанных часов: ");
scanf("%f", &hours);
total = (40 * rate) + ((hours -40) * (rate*2));
printf("Ваш недельный заработок: %f", total);
}
Если вы находите, что использование скобок сбивает вас с толку, разбейте уравнение на несколько отдельных частей. В Листинге6.5 приведен текст программы, которая выполняет тот же расчет недельного заработка, но проводит его в несколько последовательных этапов, определяя для этого дополнительные переменные. Результат каждого отдельного вычисления присваивается конкретной переменной и может быть выведен на экран, что делает получаемую информацию даже несколько более наглядной. Этот прием позволяет полностью контролировать весь процесс вычисления и с большей легкостью находить ошибки.
Листинг 6.5. Программа, осуществляющая вычисление в несколько этапов.
/*payroll2.c*/
main()
{
float rate, hours, total, regular, extra, d_time, overtime;
printf("Введите оплату одного часа работы: ");
scanf("%f", &rate);
printf("Введите количество отработанных часов: ");
scanf("%f", &hours);
regular = 40 * rate;
extra = hours - 40;
d_time = rate * 2;
overtime = extra * d_time;
total = regular + overtime;
printf("Ваш недельный заработок: %f", total);
}