Язык Си в примерах/Учимся складывать: различия между версиями

Материал из Викиучебника — открытых книг для открытого мира
Содержимое удалено Содержимое добавлено
→‎Вариант «арифметический»: Пример с «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) {
printf ("%lf %lf %lf %lf\n",
= scanf ("%lg%lg", &a, &b);
assert (r == 2);
a + b, a - b, a * b, a / b);
printf (("a + b = %10.3lf\n"
if (b != 0) {
"a - b = %10.3lf\n"
printf (("a + b = %lg\n"
"a * b = %10.3lf\n"
"a - b = %lg\n"
"a / b = %10.3lf\n"),
"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"),
a + b, a - b, a * b);
}
}
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 запятой в конце команды.
Одна из самых популярных синтаксических ошибок начинающих программистов — не ставить точку c запятой после утверждений.


==Примечания==
==Примечания==

Версия от 10:58, 1 февраля 2014

Язык Си в примерах


  1. Компиляция программ
  2. Простейшая программа «Hello World»
  3. Учимся складывать
  4. Максимум
  5. Таблица умножения
  6. ASCII-коды символов
  7. Верхний регистр
  8. Скобочки
  9. Факториал
  10. Степень числа
  11. Треугольник Паскаля
  12. Корень уравнения
  13. Система счисления
  14. Сортировка
  15. Библиотека complex
  16. Сортировка на основе qsort
  17. RPN-калькулятор
  18. RPN-калькулятор на Bison
  19. Простая грамматика
  20. Задача «Расчёт сопротивления схемы»
  21. Простая реализация конечного автомата
  22. Использование аргументов командной строки
  23. Чтение и печать без использования stdio
  24. Декодирование звукозаписи в формате ADX
  25. Другие примеры

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

Вариант «простой»

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

Как и в случае функций (в том числе 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 (intdouble) и указатели преобразований (%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 запятой после утверждений.

Примечания