§4 Поток ввода. Переменные. Указатели. Фундаментальные типы. Целый тип. Арифметические операции с целыми типами

Поток ввода. Потоковый объект cin

Для ввода данных используется поток ввода. Поток ввода начинается с определения потокового объекта ввода – cin (читается “си-ин”). По аналогии с потоком вывода, поток ввода использует операцию извлечения >> (или ввода) для чтения данных в поток со стандартного устройства (клавиатуры) или из файла (для файловых потоков определяются свои потоковые объекты ввода). Переменные, входящие в поток должны быть определены в программе раньше. Например:

int var_A;
cin >> var_A;

1
Можно вводить значения нескольких переменных за раз, но тогда, при вводе, в окне терминала, значения переменных должны разделяться пробелами (или иными пробельными символами). Пример ввода нескольких переменных:

int a = 10, b, c;
cin >> a >> b >> c;

Здесь вводятся переменные одного типа, но в потоке cin можно вводить значения переменных разного типа. В этом случае нужно следить за тем, чтобы вводимые значения переменных соответствовали требованиям предъявляемым к литералам данных типов. Если переменная имела уже какое-то значение (a), то оно будет заменено на новое. Данные в поток отправляются нажатием клавиши Enter на клавиатуре.
Примечание. Для потоков ввода также могут быть использованы манипуляторы, например, setw() для ограничения количества вводимых символов.
Данные не должны вводиться “вслепую”, т. е. для ввода тех или иных данных необходимо приглашение. Такие приглашения называются диалогами с пользователем или дружественными интерфейсами. Для создания диалогов потоки ввода/вывода используются совместно. Приведем пример. Создадим программу приветствия, опрашивающую пользователя и выводящую полученную информацию.
Программа 4.1

//============================================================================
// Name        : lesson-4-1.cpp
//============================================================================
#include <iostream>
#include <string>
using namespace std;

int main() {
	int Y;
	string S;
	cout << "Как тебя зовут?\n";
	cin >> S;
	cout << "Сколько тебе лет?\n";
	cin >> Y;
	cout << "Здравствуй, " << S
	     << "! Тебе всего " << Y
	     << " лет." << endl;
	return 0;
}

Обратите внимание, что поток вывода, например, в стр. 11 не завершается endl. Дело в том, что последующий поток ввода автоматически завершает предыдущий поток с установкой признака завершения строки.
Примечание. В этой программе подразумевается, что имя не будет содержать пробелов. В противном случае, строка должна вводится с помощью функции класса stringgetline(cin, S), т. к. cin не игнорирует пробелы в строке! Если функция getline() следует за потоком ввода, то необходимо предусмотреть также очистку потока ввода от нулевого символа с помощью методов потокового класса, например, cin.get().

Переменные

Компьютерная память устроена так, что данные разного типа хранятся в ней различным образом. Блок памяти называется байтом (не путать с единицей измерения информации). Все байты пронумерованы, т. е. имеют адреса. Существует множество различных типов данных: целые числа, действительные числа, символы, строки. Каждый из этих типов занимает в памяти различное количество байтов. Отсюда следует, что для каждого типа определен свой диапазон возможных принимаемых значений данных этого типа и возможный набор операций с этими данными. Например, для типа целое число (тип int, занимает в памяти 4 байта) диапазон принимаемых значений от -2147483648 до 2147483647. С данными этого типа могут выполняться такие операции: +, -, *, /, %, <<, >>. Для действительного типа (тип double, занимает в памяти 8 байтов) диапазон значительно "шире" (до максимального положительного значения 1.797693134862316e+308), но количество операций (из приведенных выше) будет значительно меньше, только: +, -, * и /.
18-1Для записи данных в память и извлечения их из памяти используются переменные. Переменные — это именованная область памяти, к которой можно обращаться из программы по имени. С каждой переменной связан адрес памяти (адрес первого байта с наименьшим значением). Для программиста - это не имеет значения, так как от него скрыта информация в каком адресном пространстве будет работать программа. Для программиста важно - какой тип данных будет связан с именем переменной.

Определение переменных

Перед использованием переменных их нужно определить (definition). Определение состоит из спецификатора типа (для целой переменной это, например, int) и следующего за ним идентификатора. Определение производится в любом месте программы, но до использования самой переменной. Определение переменной следует производить в месте её использования, дабы избежать случайного появления в программе неиспользуемых переменных (современные компиляторы способны предупреждать их появление на этапе сборки, но не на этапе работы самой программы). Допустим, мы будем использовать переменную целого типа с именем a. Тогда определение будет иметь следующий вид:

int a;

Тип int является стандартным типом для целых переменных, так как имеет размер равный машинному слову (4 байта для 32-битной архитектуры). Если нет веских причин для использования иного какого-либо целого типа, то необходимо (для целой переменной) использовать именно этот тип.
Если используется несколько переменных одного типа, то они могут быть перечислены через запятую в одной инструкции:

int a, b, c, other;

Определение переменной может сопровождаться инициализацией (т. е. указанием начального значения):

int a = 10;
int b = a;
int c = 0, d, e, other = 1000;

Если переменная определяется (но не инициализируется) в теле главной функции main(), то она не будет иметь начального значения, её значением будет мусор (т. е. неопределенное состояние памяти).
Следует различать определение и объявление (declaration). Объявления вводят имена в программу (или повторно вводят). По существу, определения - это тоже объявления. Если для работы с объектом достаточно его определения в данном месте программы, то ограничиваются определением. Если переменная определяется вне тела главной функции, то говорят, что она объявлена. При объявлении переменная будет иметь значение по умолчанию (например, для типа int - это значение "0").
Программа 4.2

#include <iostream>
using namespace std;
int A;

int main() {
	int a;
	cout << A << endl;
	cout << a << endl; // Ошибка!
	return 0;
}

Компилятор выдаст предупреждение:

../src/test.cpp: В функции «int main()»:
../src/test.cpp:16:10: предупреждение: «a» используется без инициализации в данной функции [-Wuninitialized]
  cout << a << endl; // Ошибка!
          ^

Хотя, формально, предупреждение и не является ошибкой, но это, потенциально, может привести к ошибке в программе, поэтому такие ситуации нужно избегать.

Указатели

В С++ существует еще один необычный вид переменных - это указатель. Указатель - это специальный вид переменной, который хранит адрес памяти (см. рисунок выше) другого объекта, точнее байта с наименьшим значением из тех байтов, что выделены для хранения этого объекта. Поскольку указатель - это переменная, то, в этой связи, она тоже имеет свой адрес, который тоже можно получить. Указатели могут иметь разные типы (и даже абстрактные), а также вовсе не иметь типа (void). С указателями можно производить различные операции, но перечень таких операций невелик (подробно об операциях над указателями мы будем говорить позднее). Чтобы описать переменную-указатель используется операция * или разыменования:

int *p;

Также как и обычные переменные, указатели можно инициализировать, в процессе описания, адресом переменной, которая должна существовать к этому моменту:

int a = 10;
int *p = &a;

Операция & называется операцией взятия адреса. После описания указателям присваивается значение (адреса) подобно присваиванию значений другим объектам:

int a, *p, *c;
p = &a;
c = p;

Особенность указателя в том, что с его помощью можно получить значение переменной, на которую указывает указатель, путем применения операции разыменования (*) над указателем:

int a = 10, *p, c;
p = &a;
c = *p + 10;
cout << "a = " << a << endl;
cout << "c = " << c << endl;
cout << "p = " << p << endl;
a = 10
c = 20
p = 0x7ffe089fb270

Обратите внимание, что значение указателя в C++ представлено в виде шестнадцатеричного числа. С помощью указателей можно получать доступ к памяти и использовать динамические переменные, которые создаются на время, для выполнения каких-либо задач, с последующим их уничтожением. Для выделения памяти используется операция new, а для уничтожения delete. Например:

int *p = new int(10);
int *c = new int(40);
*p = *c / 2;
cout << "*c = " << *c << endl;
cout << "*p = " << *p << endl;
delete p;
delete c;

Работа с указателями - это низкоуровневые (на уровне памяти) операции языка. Поэтому программа будет работать производительнее. Но указатели, описанные выше, являются незащищенными. Это означает, что непосредственное их использование в программе чревато негативными последствиями, так как непродуманных алгоритм может привести к повреждению данных или утечкам памяти. В std языка С++ имеются безопасные типы указателей, с которыми мы познакомимся позднее.

Другие способы инициализации

На прошлом уроке мы показали как можно инициализировать переменную с помощью операции =. Но это не единственная возможность. В C++11 появилась списочная инициализация с помощью фигурных скобок. Этот способ имеет преимущества, так как контролирует потерю точности при инициализации. К тому же, он позволяет инициализировать переменную значением по умолчанию (первая строка в примере ниже), а это, в свою очередь, может предупредить использование неинициализированного объекта.

int a {};
int b = {10};
int c(0);

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

int b = 10, c = 5;
int a = (2 * b - 4) / c - 1;

Фундаментальные типы данных

Любая программа работает с данными. Тип данных указывает как организована эта информация в памяти компьютера и какие операции можно производить с этим типом данных. Язык C++ является типизированным языком программирования. Это означает, что тип данных должен быть описан прежде использования программного объекта, такого как переменная, функция, массив, структура или класс. C++, помимо фундаментальных типов, содержит составные типы и поддерживает пользовательские типы. Стандартная библиотека определяет абстрактные типы: string, vector и др. В продолжении данного курса мы будем постепенно знакомиться со всеми разновидностями типов. Здесь же мы начнем рассмотрение фундаментальных (или базовых) типов. К фундаментальным типам относятся:

  • Целые типы
  • Действительные типы
  • Логический тип
  • Символьный тип
  • Специальный тип void

Целые, действительные, логический и символьные типы относятся к арифметическому типу. Тип void используется с функциями и указывает, что функция (процедура) не возвращает какого-либо значения. void является базовым типом для указателей, а также используется в приведении типов.

Целый тип

Целочисленный тип данных является одним из фундаментальных типов и относится (наряду с вещественными) к арифметическим типам. Он представлен в виде знаковых и беззнаковых разновидностей типов.
С помощью спецификаторов типа можно получить всё разнообразие целых типов (перечисленных в таблице ниже). Спецификаторы типа могут определять знак и/или размер. Знак определяют спецификаторы:

  • signed
  • unsigned
Для определения размера (или ширины) используются спецификаторы:
  • short
  • long
  • long long
Целые типы

Types               Size                   MIN                   MAX
short                  2                -32768                 32767
unsigned short         2                     0                 65535
int                    4           -2147483648            2147483647
unsigned int           4                     0            4294967295
long                   8  -9223372036854775808   9223372036854775807
unsigned long          8                     0  18446744073709551615
long long              8  -9223372036854775808   9223372036854775807
unsigned long long     8                     0  18446744073709551615

Типы определяют лишь небольшое множество соответствующих значений из бесконечной совокупности целых чисел. Чем больше количество различных значений, которые могут принимать переменные данного типа, тем шире используемый тип. Спецификатор signed используется по умолчанию, поэтому его можно опустить (т. е. int на самом деле signed int). Спецификатор int также можно опустить во всех типах, в которых используется один из спецификаторов определяющих знак или ширину. Поэтому, на практике, сокращение int используется только для типа signed int.
Примечание. Для вывода таблицы размеров максимального и минимального значений целых типов использовался заголовок limits и операция sizeof(). Константы numeric_limits<type>::min() и numeric_limits<type>::max() хранят максимальные и минимальные значения соответствующих типов.
Как видно из таблицы, знаковые типы могут принимать как отрицательные, так и положительные значения, в то время как беззнаковые типы только положительные и ноль. В стандарте C++ не определяются размеры того или иного типа. Стандарт дает лишь гарантию, что:

1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

Размер конкретного типа будет зависеть от платформы и реализации C++. Компилятор GCC не делает разницы между long и long long (а также unsigned long и unsigned long long), но, для переносимости программ, это соответствие целых типов следует учитывать.
Какой тип выбирать при решении задач при таком разнообразии целых типов? Как мы уже упоминали, тип int используется по умолчанию. Работа с данным типом будет осуществляться максимально эффективно. Но что, если максимального значения этой переменной станет недостаточным? В таком случае нужно выбирать тип "шире" или переходить к длинной арифметике с массивами (эту тему мы будем обсуждать позднее). В C++ ответственность соблюдения выхода за границы диапазона типа лежит целиком на разработчике алгоритма.

Арифметические операции с целыми типами

В C++ используются операции, которые реализуют все основные арифметические действия: сложение, вычитание, умножение, деление (для целых и действительных типов), а также взятие остатка отделения (только для целых типов). Эти операции являются бинарными, т. е. используют два операнда. Как мы уже говорили на прошлом уроке, операции могут иметь приоритет, иначе говоря - старшинство. Операции *, /, % имеют более высокий (и при этом равный) приоритет, чем операции + и -. Для изменения порядка вычисления используются ().
Любое арифметическое выражение (математическая формула) должно быть представлено в линейной нотации с помощью функций и операций языка C++. Приведем пример. Дана формула нахождения одного из двух корней квадратного уравнения:
 x_1=\frac{-b+\sqrt{b^2-4ac}}{2a}

Представить эту формулу в линейной нотации можно так

x1 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a) // или так
x1 = (-b + sqrt(b * b - 4 * a * c)) / 2 / a

Где sqrt - функция библиотеки cmath (извлечение квадратного корня).
Помимо приоритета, операции обладают также и ассоциативностью. Ассоциативность определяет порядок вычислительных действий в выражении. Так операция присваивания ассоциативна справа, то есть вычисляется справа налево. Поэтому во второй строке возможна следующая инструкция:

int a, b;
    a = b = 5;
    cout << "a = "   << a
    	 << "\nb = " << b
		 << endl;

Примечание. Инициализация и присваивание - разные вещи; в инструкции определения так сделать не получится.
Арифметические операции, наоборот, обладают ассоциативностью слева.
Скажем, нам нужно получить произведение цифр трехзначного числа 236 (см. программу 3.2):
n % 10 * n / 10 % 10 * n / 100
В этом выражении используются операции с равным приоритетом. Если мы не будем использовать скобки, то, при равном приоритете всех операций, выражение будет вычисляться в следующем порядке:

n % 10 => 6
n % 10 * n => 1416
n % 10 * n / 10 => 141
n % 10 * n / 10 % 10 => 1
n % 10 * n / 10 % 10 * n => 236
n % 10 * n / 10 % 10 * n / 100 => 2

При выводе даст нам неверный ответ - 2, а это не то, что мы ожидали увидеть! Здесь без скобок не обойтись. В скобки должно заключаться каждое выражение вычисляющее разряд:
(n % 10) * ((n / 10) % 10) * (n / 100)

Постфиксный и префиксный инкремент и декремент

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

Формы
префиксная   постфиксная
      инкремент
++a          a++
      декремент
--a          a--

Операция инкремента увеличивает значение переменной на единицу, а декремента уменьшают на единицу. Постфиксная и префиксная формы различаются тем, что при выполнении инструкций значение переменной будет изменяться так: для постфиксной формы - после выполнения инструкции, для префиксной формы - до выполнения инструкции. Это иллюстрирует следующий пример:
Программа 4.3

#include <iostream>
using namespace std;

int main() {
	int a = 5;
	cout << a++ << "\n"
	     << a   << "\n"
	     << ++a << endl;
	return 0;
}

На выводе:

5
6
7

Сначала выводится выражение с постфиксным инкрементом. Будет выведено первоначальное значение переменной (5), а затем происходит приращение и в следующей строке выводится уже измененное значение (5+1). В третьей строке вывода - сначала происходит приращение (6+1, префиксный инкремент), а затем вывод измененного значения (7).
Операции декремента --a и a-- эквивалентны присваиваниям a = a - 1 или a -= 1 . Аналогично операции инкремента ++a и a++ эквивалентны присваиваниям a = a + 1 или a += 1 . Однако, поскольку операции инкремента и декремента применяются довольно часто их реализация отличается от операций с присваиванием, что позволяет им работать быстрее аналогичных операций с присваиванием.
Унарные операции инкремента и декремента обладают высшим приоритетом. Они могут применяться в различных выражениях, но делать это нужно чрезвычайно осторожно, поскольку очередность выполнения операций при большой сложности выражения становится не очевидной. Типичное применение этих операций - счетчики циклов.

Операция взятия остатка от деления "%"

Для целых типов предусмотрены два вида операций деления:

  1. / - целочисленное деление с отбрасыванием дробной части и
  2. % - получение остатка от деления

С помощью операций целочисленного деления можно решать целый класс задач в которых требуется получать разряды числа. Постановка задачи:
Дано трехзначное число n. Получить сумму и произведение цифр составляющих это число.
Программа 4.4

//============================================================================
// Name        : lesson-4-4.cpp
// Description : Получение суммы и произведения разрядов трехзначного числа
//============================================================================
#include <iostream>
using namespace std;

int main() {
	int n;
	cout << "n = "; cin >> n;
	cout << "Сумма цифр числа = "
		 << n % 10 + (n / 10) % 10 + n / 100
		 << "\nПроизведение цифр = "
		 << (n % 10) * ((n / 10) % 10) * (n / 100)
		 << endl;
	return 0;
}

Результат в консоли:

n = 236
Сумма цифр числа = 11
Произведение цифр = 36

Однако, операция взятия остатка от деления, с точки зрения математики, не совсем корректна. Это иллюстрирует следующий пример:
Программа 4.5

#include <iostream>
using namespace std;

int main() {
	int a = 7, b = 2, c = -7, d = -2;
	cout << a % b << "\n"
		 << a % d << "\n"
		 << c % d << "\n"
		 << c % b << endl;
	return 0;
}

Вывод программы:

1
1
-1
-1

Как видно из примера остаток может быть отрицательным, когда делимое - отрицательное число.
Часто операции целочисленного деления используются в задачах на определение долей времени. Рассмотрим одну из таких задач. Дано время в виде целого числа секунд (3600 < t < 1000000000000000000). Определить количество прошедших полных суток и количество часов минут и секунд прошедших с начала последних суток.
Программа 4.6

#include <iostream>
using namespace std;

int main() {
	cout << "Введите время в секундах\n"
			"(3600 < t < 1000000000000000000):\n";
	unsigned long t;
	cin >> t;
	unsigned long d = t / 3600 / 24;
	int h = t / 3600 % 24;
	int m = t % 3600 / 60;
	int s = t % 3600 % 60;
	cout << "Дней = " << d
		 << "\nЧасов = " << h
		 << "\nМинут = " << m
		 << "\nСекунд = " << s
		 << endl;
	return 0;
}
Введите время в секундах
(3600 < t < 10000000000000000000):
123456
Дней = 1
Часов = 10
Минут = 17
Секунд = 36
Побитовые операции

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

  • Побитовое НЕ – ~
  • Это унарная операция, действие которой эквивалентно применению логического отрицания к каждому биту двоичного представления операнда. Другими словами, на той позиции, где в двоичном представлении операнда был 0, в результате будет 1, и, наоборот, где была 1, там будет 0.

    int a = 0b00000000000000000000000000101011; // 43
    int b = 0b11111111111111111111111111010100; // -44
    cout << a << endl;
    cout << ~a << endl;
    cout << b << endl;
    
  • Побитовое И - &
  • Это бинарная операция, действие которой эквивалентно применению логического «И» к каждой паре битов, которые стоят на одинаковых позициях в двоичных представлениях операндов. Другими словами, если оба соответствующих бита операндов равны 1, результирующий двоичный разряд равен 1; если же хотя бы один бит из пары равен 0, результирующий двоичный разряд равен 0.

    int a = 0b00000000000000000000000000101011; // 43
    int b = 0b00000000000000000000000000110111; // 55
    // res    00000000000000000000000000100011  => 35
    cout << (a & b) << endl;
    
  • Побитовое ИЛИ - |
  • Это бинарная операция, действие которой эквивалентно применению логического «ИЛИ» к каждой паре битов, которые стоят на одинаковых позициях в двоичных представлениях операндов. Другими словами, если оба соответствующих бита операндов равны 0, двоичный разряд результата равен 0; если же хотя бы один бит из пары равен 1, двоичный разряд результата равен 1.

    int a = 0b00000000000000000000000000101011; // 43
    int b = 0b00000000000000000000000000110111; // 55
    // res    00000000000000000000000000111111  => 63
    cout << (a | b) << endl;
    
  • Побитовое Исключающее ИЛИ (XOR) - ^
  • Это бинарная операция, результат действия которой равен 1, если число складываемых единичных битов нечётно, и равен 0, если чётно. Другими словами, если оба соответствующих бита операндов равны между собой, двоичный разряд результата равен 0; в противном случае, двоичный разряд результата равен 1.

    int a = 0b00000000000000000000000000101011; // 43
    int b = 0b00000000000000000000000000110111; // 55
    // res    00000000000000000000000000011100  => 28
    cout << (a ^ b) << endl;
    

    Данная операция часто применяется для обмена значениями между двумя целыми переменными без использования третьей:
    Программа 4.7

    #include <iostream>
    using namespace std;
    
    int main() {
    	int a = 2;
    	int b = 5;
    	cout << "Было \ta = " << a
    		 << "\n\tb = "    << b
    		 << endl;
    	a = a ^ b;
    	b = a ^ b;
    	a = a ^ b;
    	cout << "Стало \ta = " << a
    		 << "\n\tb = "     << b
    		 << endl;
        return 0;
    }
    
  • Побитовые сдвиги влево - << и вправо - >>
  • Операции сдвига << и >> сдвигают биты в переменной влево или вправо на указанное число. При этом на освободившиеся позиции устанавливаются нули (кроме сдвига вправо отрицательного числа, в этом случае на свободные позиции устанавливаются единицы, так как числа представляются в двоичном дополнительном коде и необходимо поддерживать знаковый бит). Сдвиг влево на 1 может применяться для быстрого умножения числа на два, сдвиг вправо — для деления на два.

    int a = 0b00000000000000000000000000000001; // 1
    // res    00000000000000000000000000010000  => 16
    int b = 0b00000000000000000000001000000000; // 512
    // res    00000000000000000000000000100000  => 32
    cout << (a << 4) << endl;
    cout << (b >> 4) << endl;
    
Сокращенная форма присваивания

Разработчики языка C++ стремились сделать кодинг (верстку программного кода) более лаконичным и компактным. Еще одним способом сократить запись выражений является сокращенная форма присваивания. Используется она тогда, когда значение данной переменной с помощью арифметических операций изменяется значением другой переменной или более сложным выражением:

Полная форма    Краткая форма
a = a + b       a += b
a = a - b       a -= b
a = a * b       a *= b
a = a / b       a /= b
a = a % b       a %= b
a = a << b      a <<= b
a = a >> b      a >>= b
a = a & b       a &= b
a = a ^ b       a ^= b
a = a | b       a |= b

Пробелы между операцией "=" и арифметической операцией не допускаются.

Вопросы
  1. В чем отличие префиксной формы инкремента и декремента от постфиксной?
  2. Что такое приоритет и ассоциативность?
  3. Когда появляется необходимость использовать скобки в выражениях?
  4. Когда можно применить сокращенную форму присваивания?
  5. В чем отличие явного преобразования типа от неявного?
  6. Какая форма явного преобразования типа используется в С++?
  7. Приведите примеры использования знаковых и беззнаковых типов.
  8. Перечислите формы записи вещественных чисел.
  9. Почему в процессе вычислений с вещественными числами падает точность вычислений?
  10. Какие действительные типы вам известны? Какой тип наиболее точный при вычислениях?
  11. Какой тип данных мы получим если целое число разделим на вещественное? Вещественное на целое?
  12. Когда нужно выбирать для вычислений целый, а когда действительный тип?
Практические задания

1. Дано трехзначное число n. Получить новое значение n образованное прочтением исходного числа справа налево (то есть поменять разряды числа. Например 123 -> 321).
2. Дни недели пронумерованы следующим образом: 0 — воскресенье, 1 — понедельник, 2 — вторник, …, 6 — суббота. Дано целое число K, лежащее в диапазоне 1–365. Определить номер дня недели для K-го дня года, если известно, что в этом году 1 января было понедельником. (См. ссылку).
3. Составить программу. Даны длины сторон треугольника a, b, c. Найти длины высот. Длина высоты вычисляется по формуле:
 h_a = \frac{2S}{a} , где S - площадь треугольника (вычисляется по формуле Герона).
4. Составить программу. По заданным величинам радиусов оснований r и R и высоты h найти объем и площадь поверхности усеченного конуса.

Ссылки

» Как узнать номер дня недели?
» Функции. Заголовочный файл
» Что нужно знать про арифметику с плавающей запятой
» Алгоритмы на С++ (олимпиадный подход)

Презентации к уроку
[ODF] [PDF]


Print Friendly, PDF & Email

Comments are closed.