Язык Си в примерах/Учимся складывать: различия между версиями
→Числовые типы: Раздел перенесен в Язык Си в примерах/Скалярные типы#Числовые типы. |
→Вариант «арифметический»: Пример с «while» заменен на пример с «if». |
||
Строка 71: | Строка 71: | ||
Желающим изучить использование других числовых типов в этой задаче предлагается обратиться к разделу [[Язык Си в примерах/Скалярные типы#Числовые типы|Числовые типы]] приложения. |
Желающим изучить использование других числовых типов в этой задаче предлагается обратиться к разделу [[Язык Си в примерах/Скалярные типы#Числовые типы|Числовые типы]] приложения. |
||
== Вариант « |
== Вариант «арифметический» == |
||
В программе ниже мы также вычислим разность и произведение двух чисел, а также, если второе число отлично не ноль, — частное от деления первого на второе. |
|||
Ниже приведена программа, которая считывает два действительных числа и |
|||
выводит результат четырех арифметических операций: сложения, вычитания, умножения и деления. |
|||
Причём, программа выводит результаты вычислений два раза — сначала |
|||
в обычном виде, а потом со специальным форматированием. |
|||
Формат <code>"%10.3lf"</code> соответствует выводу числа типа <code>double</code>, |
|||
при котором под запись числа выделяется ровно 10 позиций (если это возможно), |
|||
а после запятой пишется ровно три знака. Равнение происходит по правому краю. |
|||
<source lang="c"> |
<source lang="c"> |
||
#include <assert.h> |
|||
#include <stdio.h> |
#include <stdio.h> |
||
Строка 88: | Строка 83: | ||
{ |
{ |
||
double a, b; |
double a, b; |
||
int r |
|||
while (scanf ("%lf%lf", &a, &b) == 2) { |
|||
= scanf ("%lg%lg", &a, &b); |
|||
assert (r == 2); |
|||
⚫ | |||
if (b != 0) { |
|||
printf (("a + b = %lg\n" |
|||
"a |
"a - b = %lg\n" |
||
"a |
"a * b = %lg\n" |
||
"a / b = %lg\n"), |
|||
a + b, a - b, a * b, a / b); |
a + b, a - b, a * b, a / b); |
||
} else { |
|||
printf (("a + b = %lg\n" |
|||
"a - b = %lg\n" |
|||
"a * b = %lg\n"), |
|||
⚫ | |||
} |
} |
||
return 0; |
return 0; |
||
Строка 101: | Строка 102: | ||
</source> |
</source> |
||
В этой программе нам потребовался ''условный оператор контекста утверждения'' (англ. {{lang|en|if statement}}) — один из четырех (наряду с <code>&&</code>, <code>||</code> и <code>? :</code>) условных операторов языка. Его синтаксис:<ref name="if" >[http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=166 WG14 N1570 Committee Draft — April 12, 2011] 6.8.4.1 ''The if statement''</ref> |
|||
В этой программе мы встречаемся с оператором <code>while</code>. Конструкция |
|||
<code>if (</code>⟨''выражение''⟩<code>)</code> |
|||
<source lang="c"> |
|||
⟨''тело-если-истинно''⟩ |
|||
while ( A ) B; |
|||
<!-- --> |
|||
</source> |
|||
<code>if (</code>⟨''выражение''⟩<code>)</code> |
|||
⟨''тело-если-истинно''⟩ |
|||
означает буквально следующее: |
|||
<code>else</code> |
|||
⟨''тело-если-ложно''⟩ |
|||
: Пока выполнено условие <code>A</code> делать <code>B</code>. |
|||
или, другими словами, |
|||
: Выполнять в цикле <code>B</code>, проверяя перед каждой итерацией, что выполнено условие <code>A</code>. |
|||
В нашем случае <code>A</code> есть |
|||
<source lang="c"> |
|||
scanf ("%lf%lf", &a, &b) == 2 |
|||
</source> |
|||
Что соответствует логическому выражению: |
|||
: пользователь ввёл два действительных числа, и они удачно считаны в переменные a и b. |
|||
Где ⟨''тело-если-истинно''⟩ и ⟨''тело-если-ложно''⟩ могут быть (каждый) единственным утверждением (завершаемым <code>;</code>), или же, как в примере выше, — <code>{ }</code>-блоком. |
|||
Таким образом, эта программа будет считывать пары чисел и выводить результаты |
|||
арифметических операций, пока пользователь не введёт что-нибудь непохожее на число. |
|||
В случае, если результат вычисления ''выражения'' — истина (другими словами — отличен от 0), выполняется ⟨''тело-если-истинно''⟩; в противном случае (и если используется <code>else</code>) — ⟨''тело-если-ложно''⟩. |
|||
Цикл <code>while</code> закончится тогда, когда функция <code>scanf</code> не сможет успешно считать два числа. |
|||
Заметьте, что |
Заметьте, что каждое простое ''утверждение'' (англ. {{lang|en|statement}}) завершается точкой с запятой. |
||
Одна из самых популярных синтаксических ошибок начинающих программистов — |
Одна из самых популярных синтаксических ошибок начинающих программистов — не ставить точку c запятой после утверждений. |
||
==Примечания== |
==Примечания== |
Версия от 10:58, 1 февраля 2014
- Компиляция программ
- Простейшая программа «Hello World»
- Учимся складывать
- Максимум
- Таблица умножения
- ASCII-коды символов
- Верхний регистр
- Скобочки
- Факториал
- Степень числа
- Треугольник Паскаля
- Корень уравнения
- Система счисления
- Сортировка
- Библиотека complex
- Сортировка на основе qsort
- RPN-калькулятор
- RPN-калькулятор на Bison
- Простая грамматика
- Задача «Расчёт сопротивления схемы»
- Простая реализация конечного автомата
- Использование аргументов командной строки
- Чтение и печать без использования stdio
- Декодирование звукозаписи в формате ADX
- Другие примеры
Разнообразные вычисления — моделирование, решение алгебраических и дифференциальных уравнений — это то, для чего и создавались первые компьютеры. Давайте и мы научимся использовать компьютер для вычислений. Начнём со сложения двух чисел.
Вариант «простой»
В отличие от рассмотренной ранее простейшей программы, в данной задаче нам потребуются переменные — ячейки памяти, в которые функция ввода сохранит введенные пользователем числа, подлежащие сложению.
Как и в случае функций (в том числе main
), объявление переменных в Си предполагает указание их типов. Основные числовые типы языка — int
(целое число фиксированной разрядности) и double
(число с плавающей запятой.) Поскольку мы уже использовали тип int
в описании функции main
, применим его же в данной задаче.
#include <assert.h>
#include <stdio.h>
int
main ()
{
int a, b;
int r
= scanf ("%d%d", &a, &b);
assert (r == 2);
printf ("%d\n", a + b);
return 0;
}
Рассмотрим выполнение этой программы почти с ее завершения — вызова функции printf
.[1] Данная функция выведет целое число в десятичной форме (согласно указателю преобразования %d
), завершая вывод переводом строки (\n
).
Число, которое будет выведено, является результатом вычисления выражения a + b
— или же, проще говоря, — суммой значений переменных a
и b
.
Вводимые пользователем числа помещаются в эти переменные функцией scanf
, вызываемой в коде выше как scanf ("%d%d", &a, &b)
.[2] Здесь, как и в printf
, используется указатель преобразования %d
, означающий на этот раз считывание числа в десятичной форме (возможно — предваряемого пробелами). Поскольку указатель повторен дважды, два числа будут считаны и помещены в упомянутые в аргументах две переменные a
и b
. (Необходимый здесь унарный оператор &
оставим пока без внимания.)
Как и printf
, функция scanf
объявлена в заголовке (англ. header) stdio.h
.[3]
В простейшей программе от действий пользователя не зависело ровным счетом ничего. Каким, однако, будет результат выполнения данной программы, если ввод пользователя не будет начат двумя числами в десятичной форме?
Для проверки соответствия ввода пользователя требованиям программы мы сохраняем (=
) результат выполнения scanf
— количество успешно измененных переменных — в целочисленной переменной с именем r
(int r
), после чего требуем равенства ее значения двум (assert (r == 2);
.)
Действие макроподстановки assert
заключается в вычислении выражения, переданного ей первым (и единственным) аргументом и аварийном завершении программы в случае, если полученное значение — ноль («логическая ложь».)[4]
Наконец, в самом начале функции main
определены (помимо упомянутой уже r
) целочисленные переменные a
и b
. Их значение в начале выполнения функции main
может быть произвольным,[5] но после успешного (что проверяется вызовом assert
) завершения scanf
они будут содержать два числа, которые удалось последовательно считать со стандартного ввода.
Вариант «дробный»
Рассмотренную выше программу несложно изменить для использования чисел с плавающей запятой.
#include <assert.h>
#include <stdio.h>
int
main ()
{
double a, b;
int r
= scanf ("%lg%lg", &a, &b);
assert (r == 2);
printf ("%lg\n", a + b);
return 0;
}
Как видно, в этом случае изменяются лишь тип переменных a
, b
(int
→ double
) и указатели преобразований (%d
→ %lg
.)
Здесь следует отметить, что в случае scanf
совершенно идентично будут действовать указатели преобразований %lf
и %le
. Напротив, в случае printf
не будет разницы между %lg
и %g
. Причины такого поведения мы также пока оставим без внимания.
Желающим изучить использование других числовых типов в этой задаче предлагается обратиться к разделу Числовые типы приложения.
Вариант «арифметический»
В программе ниже мы также вычислим разность и произведение двух чисел, а также, если второе число отлично не ноль, — частное от деления первого на второе.
#include <assert.h>
#include <stdio.h>
int
main ()
{
double a, b;
int r
= scanf ("%lg%lg", &a, &b);
assert (r == 2);
if (b != 0) {
printf (("a + b = %lg\n"
"a - b = %lg\n"
"a * b = %lg\n"
"a / b = %lg\n"),
a + b, a - b, a * b, a / b);
} else {
printf (("a + b = %lg\n"
"a - b = %lg\n"
"a * b = %lg\n"),
a + b, a - b, a * b);
}
return 0;
}
В этой программе нам потребовался условный оператор контекста утверждения (англ. if statement) — один из четырех (наряду с &&
, ||
и ? :
) условных операторов языка. Его синтаксис:[6]
if (
⟨выражение⟩)
⟨тело-если-истинно⟩if (
⟨выражение⟩)
⟨тело-если-истинно⟩else
⟨тело-если-ложно⟩
Где ⟨тело-если-истинно⟩ и ⟨тело-если-ложно⟩ могут быть (каждый) единственным утверждением (завершаемым ;
), или же, как в примере выше, — { }
-блоком.
В случае, если результат вычисления выражения — истина (другими словами — отличен от 0), выполняется ⟨тело-если-истинно⟩; в противном случае (и если используется else
) — ⟨тело-если-ложно⟩.
Заметьте, что каждое простое утверждение (англ. statement) завершается точкой с запятой. Одна из самых популярных синтаксических ошибок начинающих программистов — не ставить точку c запятой после утверждений.
Примечания
- ↑ WG14 N1570 Committee Draft — April 12, 2011 7.21.6.1 The fprintf function
- ↑ WG14 N1570 Committee Draft — April 12, 2011 7.21.6.2 The fscanf function
- ↑ WG14 N1570 Committee Draft — April 12, 2011 7.21 Input/output
stdio.h
- ↑ WG14 N1570 Committee Draft — April 12, 2011 7.2.1.1 The assert macro
- ↑ WG14 N1570 Committee Draft — April 12, 2011 6.7.9 Initialization
- ↑ WG14 N1570 Committee Draft — April 12, 2011 6.8.4.1 The if statement