Используемые алгоритмы ввода
Алгоритмом называют способ выполнения определенной задачи. Изучая программирование, вы в то же время учитесь разрабатывать алгоритмы, то есть определять, каким именно образом решить ту или иную задачу, используя язык Си. Может показаться, что существует бесчисленное множество способов решения, столько же, сколько и задач, но на самом деле есть основной набор алгоритмов, которые используются в 90 процентах случаев. Изучив наиболее часто используемые алгоритмы, вы сможете легко проектировать программы, основываясь на уже известных вам методах.
Один из таких алгоритмов используется для изменения значения переменной. Речь идет о присваивании нового значения переменной, которая уже инициализирована. Если использовать просто функцию ввода и имя переменной в качестве параметра, исходное значение при вводе нового будет потеряно. А что делать, если вы не хотите, чтобы оно пропало? Например, вам нужно сравнить старое и новое значения (соответствующие примеры приведены в главе8). Один из возможных способов — это ввести дополнительную переменную для сохранения прежнего значения:
Здесь значение переменной amount передается в переменную cache, и до тех пор, пока в amount не записана новая информация, обе переменные имеют одну и ту же величину. Переменная cache обеспечивает хранение значения в памяти, пока в нем не возникнет необходимость. Когда оно вам потребуется, используйте переменную, которая служила для хранения.
В программе, приведенной в Листинге 5.2, показан пример присваивания переменной нового значения (в следующих главах вы увидите различные варианты практического применения этой процедуры).
Листинг 5.2. Программа присваивания переменной нового значения с сохранением старого.
/*storage.c*/main() { int number, storage; puts("Введите значение переменной"); scanf("%d", &number); storage = number; puts("Введите значение переменной"); scanf("%d", &number); printf("Исходное значение: %d\n", storage); printf("Новое значение: %d", number); }
Рис. 5.12. Присваивание переменной нового значения
Ввод значения переменной number обеспечивается следующими инструкциями:
puts("Введите значение переменной");scanf("%d", &number);Сохранение значения переменной number в переменной storage выполняет инструкция:
Для ввода второго значения переменной number используются точно такие же инструкции, как и в первом случае. Оба значения, старое и новое, позже могут быть отражены на экране. Прежнее содержимое переменной не было утеряно просто потому, что было сохранено в другой области памяти, как показано на рис.5.12.
<> | Вопросы |
|
<> | Упражнения |
|
ГЛАВА 6. ОПЕРАТОРЫ
Не возникло ли у вас впечатления, что кое-что пропущено? В пятой главе вы узнали, как данные вводятся в компьютер, а в четвертой — как информация выводится на дисплей. Вероятно, пора рассказать о том, что происходит в промежутке между этими двумя событиями — об обработке данных.
В процессе обработки программа превращает данные, которые мы вводили в компьютер, в информацию, которую компьютер представляет нам. Различие между данными и информацией трудноуловимо, но очень существенно. «Данные» — это, так сказать, исходный материал, символы и числа, которые не могут быть использованы как конечный продукт. «Информация» — это конечный продукт, ради получения которого и была написана программа.
Превращение данных в информацию может осуществляться различными способами. Для чисел, например, обработка зачастую включает некоторые математические операции. Скажем, вам надо умножить стоимость заказанных товаров на ставку налога, а затем добавить полученную сумму налога к сумме заказа. Эти две операции показаны на рис.6.1, они могут быть описаны как:
налог на продажи = стоимость заказа Ф ставка налогаобщая сумма заказа = стоимость заказа + сумма налога
Рис. 6.1. Процесс вычисления общей суммы заказа
Для того чтобы выполнить вычисления, превращающие данные в информацию, необходимы операторы. Оператором называется символ, который говорит компьютеру, как следует обрабатывать данные. В этой главе вы познакомитесь с арифметическими операторами, операторами приращения и операторами присваивания.
|
Арифметические операторы
При математических вычислениях используются следующие арифметические операторы:
Оператор | Функция оператора |
+ | сложение |
– | вычитание |
* | умножение |
/ | деление |
% | получение остатка от деления нацело |
Обратите внимание, что процедура умножения обозначается символом «звездочка» (а не символом «x»), а процедура деления — символом «прямая косая черта» (а не обратная «\»).
Операторы часто используются в инструкциях, требующих выполнения математических операций и присваивания полученного результата переменной в качестве значения. Ниже приводится пример расчета накладных расходов с помощью арифметических операторов. В этом примере не имеет смысла присваивать переменной точное значение в виде литерала, например:
sales_tax = 4500;напротив, величину накладных расходов требуется вычислить. При записи математических операций имя переменной всегда помещают слева от знака «равно», а арифметические операторы — справа:
sales_tax = amount * tax_rate;price = cost + shipping + insurance;per_unit = total / count;Эти инструкции говорят компилятору, что следует выполнить три операции:
- присвоить переменной sales_tax значение, полученное в результате умножения значения переменной amount на значение переменной tax_rate;
- присвоить переменной price значение, полученное из суммы значений трех переменных: cost, shipping и insurance;
- присвоить переменной per_unit значение, полученное в результате деления total на count.
Компьютер выполнит математические операции, указанные в правой части, а потом присвоит полученное значение переменной в левой части. Что касается правой части выражения, то она может содержать любые комбинации переменных, констант и литералов, например:
sales_tax = amount * 0.06;price = 56.90 + shipping + 7.87;per_unit = 156.65 / 12.50;Листинг 6.1 демонстрирует использование операторов в программе. В приведенном фрагменте необходимо ввести имя и адрес покупателя, а также стоимость его заказа. Затем программа рассчитывает стоимость транспортировки (10процентов от суммы заказа) и налог на продажи (6 процентов от суммы заказа). Наконец, весь список накладных расходов отображается на экране с помощью функций puts() и printf().
Листинг 6.1. Программа расчета и отображения накладной.
/*invoice.c*/#define TAX_RATE 0.06#define SHIPPING 0.10main(){char name[15], address[20], city[15], state[3], zip[6];float order, total, tax, ship;printf("Имя покупателя: ");gets(name);printf("Адрес: ");gets(address);printf("Город: ");gets(city);printf("Штат: ");gets(state);printf("Индекс:");gets(zip);printf("Сумма заказа: ");scanf("%f", &order);tax = order * TAX_RATE;ship = order * SHIPPING;total = order + tax + ship;puts("\n\n\n\n");puts(" НАКЛАДНАЯ\n");printf("%s\n%s\n%s, %s %s\n", name, adress, city, state, zip);printf("\t\t\t\t%-10s\t%10.2f\n", "Заказ:", order);printf("\t\t\t\t%-10s\t%10.2f\n", "Налог:", tax);printf("\t\t\t\t%-10s\t%10.2f\n", "Транспортировка:", ship);printf("\t\t\t\t\t\t______________\n);printf("\t\t\t\t%-10s\t%10.2f","Всего: ",total);}Деление нацело
Оператор % используется для расчета остатка от деления нацело. Если вы используете оператор деления (/) для целочисленных данных, то результат деления тоже всегда будет целым числом. Например, при делении 12 на 5 (12/5) вы получите 2, а не 2.4. Дробная часть, равная в данном случае 0.4, при делении целых чисел отбрасывается.
Разумеется, нередко возникает необходимость узнать значение остатка от деления. Пока мы имеем дело с целыми числами, мы не можем использовать значение 0.4, так как это число относится к типу float. Мы же определили результат деления как целое. В этом случае получается, что число 12 состоит из двух чисел 5, а лишняя двойка просто игнорируется. Число 2 в данном случае является остатком от деления нацело, для получения которого и используется оператор %. Остаток от деления нацело также всегда является целым числом.
В качестве примера приведен Листинг 6.2. В этой программе подсчитывается количество банкнот достоинством в двадцать, десять, пять и один доллар, необходимых для уплаты определенной суммы. Наиболее существенным, на что следует обратить внимание в этом примере, является алгоритм, то есть способ использования операции деления нацело при выполнении задачи, решение которой в другом случае потребовало бы произведения более сложных расчетов. Как и все прочие алгоритмы, данный алгоритм выглядит очень простым, стоит только понять его основную идею.
Листинг 6.2. Программа, в которой используется оператор получения остатка от деления нацело.
/*change.c*/main(){int amount, twenties, tens, fives, ones, r20, r10;printf("Введите необходимую сумму: ");scanf("%d", &amount);twenties = amount / 20;r20 = amount % 20; /*r20 - остаток от деления на двадцать*/tens = r20 / 10;r10 = r20 % 10; /*r10 - остаток от деления на десять*/fives = r10 / 5;ones = r10 % 5;putchar('\n');printf("Для того чтобы дать %d \ долларов сдачи, используйте:", amount);printf("%d банкнот(ы) достоинством 20 долларов", twenties);printf("%d банкнот(ы) достоинством 10 долларов", tens);printf("%d банкнот(ы) достоинством 5 долларов", fives);printf("%d банкнот(ы) достоинством 1 доллар", ones);}Если вы ввели, например, значение 57, то получите следующий результат:
Для того чтобы дать 57 долларов сдачи, используйте:2 банкнот(ы) достоинством 20 долларов1 банкнот(ы) достоинством 10 долларов1 банкнот(ы) достоинством 5 долларов2 банкнот(ы) достоинством 1 долларРис. 6.2 иллюстрирует работу этой программы. Количество двадцатидолларовых банкнот рассчитывается с помощью инструкции twenties = amount/20. Так как и переменная amount, и переменная twenties относятся к типу int, результат деления окажется целым числом. Он показывает, сколько раз число 20 содержится в значении переменной amount. Для компьютера результат — это просто некая величина, которую следует занести в память. Для нас же значение переменной twenties представляет значимую информацию, так как сообщает, сколько надо взять банкнот достоинством 20 долларов, чтобы дать сдачу.
Рис. 6.2. Как работает программа, использующаяоператор остатка от деления нацело
Теперь, когда мы знаем, что нужны две банкноты по 20 долларов, встает вопрос: как определить нужное количество десятидолларовых купюр? Вспомните, как поступают в таких случаях в реальной жизни. После того как мы отняли от общей суммы два раза по 20 долларов, надо взять сумму остатка и посмотреть, сколько банкнот по 10 долларов могло бы в нее войти. Программа поступает аналогичным образом. Для того чтобы определить размер остатка, используется оператор %. В инструкции r20 = amount % 20 переменной r20 присваивается значение, полученное в остатке после деления переменной amount на 20. Для нас это число означает сумму, оставшуюся после того, как из общей суммы вычли столько раз по 20, сколько это было возможно. Два раза по 20 долларов составляет сумму 40 долларов, вычитаем ее из общей суммы и получаем 17 долларов. Значение 17 присваивается переменной tens.
Та же процедура, которая описана для переменной twenties, повторяется для переменных tens и fives. Значение переменной ones равно остатку после деления на 5.
Типы данных и операторы
Как правило, при выполнении математических расчетов по обе стороны от знака равенства используют данные одного типа. Например, если складывают два числа типа float, тип переменной, которой присваивают результат, тоже должен быть определен как float. Это показано в следующем примере:
main(){float cost, shipping, total;cost = 56.09;shipping = 4.98;total = cost + shipping;printf("Общая стоимость составляет сумму %.2f \ долларов", total);}Результат работы программы, представленный на экране монитора, выглядит так:
Общая стоимость составляет сумму 61.07 долларов
Можно использовать и данные разных типов в правой и левой частях выражения. Отображаемое на экране значение будет определяться в зависимости от типа переменной в левой части выражения. Для примера приведен слегка измененный вариант той же программы:
main(){int total;float cost, shipping;cost = 56.09;shipping = 4.98;total = cost + shipping;printf("Общая стоимость составляет сумму %d долларов", total);}В операции сложения участвуют две переменные типа float (cost и shipping), но полученный результат присваивается целочисленной переменной total. Если сложить эти числа на калькуляторе, то в результате получим 61.07, но так как переменная total — целочисленная, то и результат будет преобразован в целое число. Использование указателя формата %d задает отображение на экране целого числа 61.
Рис. 6.3. Математические операции выполняются до того, как данные преобразуются к заданному типу переменной
Обратите внимание, вначале выполняется математическое действие, а затем происходит присваивание значения (рис.6.3). Если бы заданные значения преобразовывались в целые числа до их сложения, то результат оказался бы равен 60 (56+4).
Можно складывать два целых числа, определив сумму как float:
main(){int cost, shipping;float total;cost = 56;shipping = 4;total = cost + shipping;printf("Общая стоимость составляет сумму %.2f \ долларов", total);}В этом случае, в соответствии с типом переменной total и указателем формата %f, результат сложения будет представлен числом с плавающей точкой. Но вследствие того, что оба слагаемых являлись целыми числами, в десятичной части будут проставлены нули — 60.00.
Данные float и int можно объединять и в правой части уравнения, причем в случае сложения и вычитания полученные результаты будут отображаться в соответствии с заданным типом переменной в левой части. Посмотрите на следующую программу:
main(){int shipping;float total, cost;cost = 56.09;shipping = 4;total = cost + shipping;printf("Общая стоимость составляет сумму \ %.2f долларов", total);}Здесь выполняется сложение двух переменных типа int и float, с последующим отображением полученного результата в виде значения типа foat (60.09).
Аналогичные правила соблюдаются и при выполнении деления. Но имейте в виду: если вы хотите, чтобы переменная, содержащая результат деления и определенная как float, имела значимые цифры в десятичной части, необходимо, чтобы хотя бы у одного из участвующих в делении чисел (литералов) также имелась дробная часть. На рис.6.4 продемонстрировано, как одно и то же действие выполняется трижды. Каждый раз результат деления определен как тип float. Однако в первом случае ни одно из чисел не имеет знаков после точки, так что при отображении результата в десятичной части стоят нули.
Рис. 6.4. Деление литералов
Выражения
Выражение находится справа от знака равенства, и это понятие не включает переменную в левой части. Выражения можно использовать и в инструкциях вывода. Например:
main() { int count; count = 5; printf("Значение равно %d", count+19); }В результате выполнения программы появится сообщение:
Значение равно 24В этом примере вторым аргументом функции printf() является выражение count+19. При вызове функции значение выражения оценивается (вычисляется) в первую очередь. Результат вычисления выводится на дисплей при помощи указателя формата %d.
При использовании выражений значение переменной не изменяется. В нашем примере, после того как было вычислено и выведено на экран значение выражения count+19, содержимое переменной count по-прежнему осталось равным 5. Помните, что выражение является правой частью уравнения, и рассчитанная таким образом величина не присваивается никакой переменной.
Выражения могут состоять из любой комбинации констант, переменных, константных выражений и операторов:
printf("%d", count+number);printf("%d", 16-4);printf(%f", amount*TAX_RATE);В общем виде выражения можно использовать в тех же ситуациях, что и переменные. Однако в каждом конкретном случае следует хорошенько подумать, имеет ли смысл использовать выражение, или лучше занести полученный результат в значение переменной. Посмотрите на следующую программу:
main() { float cost, shipping; printf("Введите стоимость единицы товара: "); scanf("%f", &cost); printf("Введите величину транспортных расходов: "); scanf("%f", &shipping); printf("Общая сумма составляет %f", cost+shipping); }Выполнение инструкции
printf("Общая сумма составляет %f", cost+shipping);приведет к результату, который мог быть получен и другим способом:
total = cost + shipping;/*total следует определить как тип float*/printf("Общая сумма составляет %f", total);Обе инструкции выводят на экран монитора общую сумму затрат. В первом случае используется выражение, так что нет необходимости определять переменную, которой будет присвоено полученное значение, и нет необходимости писать уравнение. В процессе работы программы выполняется математическая операция сложения, и итог сразу же отображается на экране с помощью функции printf(). Результат, полученный таким образом, не заносится в память компьютера и, следовательно, если возникнет необходимость снова вывести на экран сумму затрат, придется опять воспользоваться выражением cost+shipping.
Если результат расчетов присваивается переменной в качестве значения, как это сделано во втором примере, необходимо определить переменную и написать уравнение. Зато в этом случае результат сложения хранится в памяти компьютера и к нему можно без труда обратиться снова, используя только имя соответствующей переменной вместо целого выражения.
Если вы предполагаете, что результат какой-либо математической операции может понадобиться не один раз, присвойте его значение какой-либо переменной. Выражения имеет смысл использовать только в том случае, если результат может понадобиться только однажды.