Движемся дальше по изучению языка C.
И теперь у нас наконец-то наступил момент, когда мы «заставим» наш процессор как-то обрабатывать наши данные. Думаю, что это важная ступень в освоении программирования.
Мы познакомимся с элементарными арифметическими операторами, с помощью которых мы сможем уже пользоваться нашими данными, которые мы инициализировали с помощью переменных, выполнять задачи по получению результатов каких-либо операций над этими данными.
Арифметические операторы бывают следующими:
+ сложение,
— вычитание,
* умножение,
/ деление,
% деление по модулю.
Данные операторы все являются бинарными, так как они производят операции между двумя операндами.
Думаю, что говорить о том, что представляют из себя операции сложения, вычитания, умножения и деления не имеет смысла, мы это знаем из курса начальной школы.
А вот деление по модулю — это такая операция, которая осуществляет деление значения первого операнда на значение второго, а в результат операции записывает не частное, а остаток от деления. В дальнейшем мы, думаю, увидим, насколько полезна такая операция. Также следует учесть, что данная операция не применяется к данным с плавающей точкой или вещественного типа.
Также к арифметическим операциям я бы отнёс знак '=' (равно), который является знаком присвоения который присваивает значение выражения, находящегося справа, переменной, находящейся слева.
Также существуют ещё две унарные математические операции
++ инкрементирование,
— декрементирование.
Инкрементирование — это математическая операция, которая увеличивает значение переменной, находящейся обычно слева от оператора инкрементирования, на единицу.
Декрементирование — это математическая операция, которая уменьшает значение переменной, находящейся обычно слева от оператора инкрементирования, на единицу.
Причём данные операторы интересны ещё тем, что они могут находиться и слева от операнда и результат операции как правило при этом не меняется. Называют в этом случае данные операторы или префиксными (оператор слева) или постфиксными (оператор справа).
Но существуют ситуации, когда мы должны выбрать определённый вариант. С такими ситуациям, я думаю, мы ещё встретимся на этапе изучения языка. Пока нам думать о них рановато.
Думаю, что разговаривать особо много об арифметических операторах нет никакого смысла, лучше всё-таки оценить их действие на ход программы по мере написания исходного кода.
Поэтому, давайте приступим к нашему проекту.
Как обычно, проект мы сделаем из проекта прошлого занятия MYPROG04 и назовём его MYPROG05. Как это делается, мы уже прекрасно знаем.
Откроем файл main.c в редактора и удалим из функции main() код всего тела кроме возврата нуля. Останется вот это
int main()
{
return 0; //Return an integer from a function
}
Объявим сразу несколько переменных всевозможных типов, некоторые из них сразу проинициализируем на этапе объявления
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
int main() { char c1 = 19, c2 = 100; char c_sub; unsigned char uc1 = 195, uc2 = 33; unsigned char uc_sum; short ns1 = -300; short ns2 = 51; short ns_mul; unsigned short uns1 = 51247; unsigned short uns2 = 1000; unsigned short uns_div, uns_divmod; int ni1 = -1011242517; int ni2 = 2011242517; int ni3 = 4; int ni_res; unsigned int uni1 = 4000000000; unsigned int uni2 = 1000000000; unsigned int uni3 = 2; unsigned int uni_res; long nl1 = -2011242517; long nl2 = 1011242517; long nl_sum; unsigned long unl1 = 4000000000; unsigned long unl2 = 1000000000; unsigned long unl_sub; long long nll1 = -8446744073709551615; long long nll2 = 8446744073709551615; long long nll_sum; unsigned long long unll1 = 18446744073709551234ULL; unsigned long long unll2 = 8446744073709551234ULL; unsigned long long unll_sub; float f1 = 12.456f; float f2 = 2.0f; float f_div; double d1 = 1.5364e20; double d2 = 2.5; double d_mul; |
Неинициализированные переменные — это переменные, в которых будет храниться результат операций. Так как мы ещё не производили никаких вычислений, то у нас это будут по факту просто зарезервированные места в памяти.
Произведём первую операцию, например, вычитания, между значениями двух переменных типа char знакового типа, а результат запишем в переменную c_sub
1 2 |
double d_mul; c_sub = c1 - c2; |
Теперь давайте выведем в консоль значения переменных, а затем результат операции с ними
1 2 3 |
c_sub = c1 - c2; printf("Signed char: "); printf("c1 = %hd; c2 = %hd\r\nc1 - c2 = %hd\r\n", c1, c2, c_sub); |
Соберём наш код и посмотрим результат выполнения нашей программы
Отлично! Мы получили первый наш результат, то есть мы осуществили обработку данных. Теперь наш процессор не просто занимается переброской данных из регистра в память и обратно. Он эти данные обработал и получил результат, который мы затем смогли посмотреть.
Теперь попробуем значение одной из переменных увеличить на единицу. Для этого нам не надо писать c2 = c2 +1; а применим мы для этого специальный оператор инкрементирования. А затем мы снова осуществим ту же операцию над данными и выведем результат в консоль
1 2 3 4 5 |
printf("c1 = %hd; c2 = %hd\r\nc1 - c2 = %hd\r\n", c1, c2, c_sub); c2++; //c2 = c2 + 1; c_sub = c1 - c2; printf("Signed char increment: "); printf("c1 = %hd; c2 = %hd\r\nc1 - c2 = %hd\r\n", c1, c2, c_sub); |
Я написал в комментарии, чему данная операция эквивалентна.
Теперь применим операцию декрементирования и также затем вычислим выражение и результат выведем в консоль, только оператор расположим до переменной
1 2 3 4 5 |
printf("c1 = %hd; c2 = %hd\r\nc1 - c2 = %hd\r\n", c1, c2, c_sub); c2--; //c2 = c2 - 1; c_sub = c1 - c2; printf("Signed char decrement: "); printf("c1 = %hd; c2 = %hd\r\nc1 - c2 = %hd\r\n ", c1, c2, c_sub); |
Соберём код и посмотрим результат его работы
Всё работает!
Теперь попробуем осуществить операцию сложения. А осуществим мы её над операндами беззнакового типа. Вообще, лучше всего осуществлять операции над данными одного типа, чтобы избежать различного рода проблем. Так как когда мы осуществляем операции над операндами разного типа, то произойдёт автоматическое (или неявное) преобразование типа, которое может произойти несколько непредсказуемым образом. Поэтому, если уж нам придётся осуществлять операции над операндами разного типа, то лучше применять явное преобразование типов. Но до этого мы в дальнейшем ещё дойдём. Сложим значения переменных типа unsigned char и результат выведем также в консоль
1 2 3 4 |
printf("c1 = %hd; c2 = %hd\r\nc1 - c2 = %hd\r\n ", c1, c2, c_sub); uc_sum = uc1 + uc2; printf("Unsigned char: "); printf("uc1 = %hd; uc2 = %hd\r\nuc1 + uc2 = %hd\r\n",uc1, uc2, uc_sum); |
Соберём код и посмотрим результат выполнения операции сложения
Всё работает.
Далее поработаем с данными типа short, у которых диапазон значений немного больше. На них мы испытаем операцию умножения
1 2 3 4 |
printf("uc1 = %hd; uc2 = %hd\r\nuc1 + uc2 = %hd\r\n",uc1, uc2, uc_sum); ns_mul = ns1 * ns2; printf("Signed short: "); printf("ns1 = %hd; ns2 = %hd\r\nns1 x ns2 = %hd\r\n", ns1, ns2, ns_mul); |
Соберём код и посмотрим результат операции
Всё правильно.
А операцию деления мы испытаем на беззнаковых величинах типа unsigned short
1 2 3 4 5 |
printf("ns1 = %hd; ns2 = %hd\r\nns1 x ns2 = %hd\r\n", ns1, ns2, ns_mul); uns_div = uns1 / uns2; uns_divmod = uns1 % uns2; printf("Unsigned short: "); printf("uns1 = %hu; uns2 = %hu\r\nuns1 : uns2 = %hu\r\nuns1 %% uns2 = %hu\r\n", uns1, uns2, uns_div, uns_divmod); |
Посмотрим результаты наших операций
Мы получили, как частное без остатка, так и остаток отдельно. Прекрасно!
Идём дальше.
Теперь мы попробуем поработать сразу над тремя величинами, комбинируя между ними различные операции.
Начнём со знакового типа int
1 2 3 4 5 |
printf("uns1 = %hu; uns2 = %hu\r\nuns1 : uns2 = %hu\r\nuns1 %% uns2 = %hu\r\n", uns1, uns2, uns_div, uns_divmod); ni_res = (ni1 + ni2) / ni3; printf("Signed integer: "); printf("ni1 = %d; ni2 = %d; ni3 = %d\r\n", ni1, ni2, ni3); printf("(ni1 + ni2) : ni3 = %d\r\n",ni_res); |
Мы видим, что у нас в выражении справа появились ещё 2 оператора — открывающая и закрывающая скобка. Данные операторы, ровно так же, как и в обычной математике, отделяют участок операции, который нужно выполнить раньше. То есть мы также сначала вычисляем выражение, находящееся в скобках, а уже затем приступаем к операциям за скобками. Скобки существуют потому, что так же, как и в математике, арифметические операторы тоже имеют различный приоритет и у операций умножения и деления он выше, чем у операций сложения и вычитания. Поэтому, если бы мы не заключили операцию сложения в скобки, то у нас бы сначала произошла операция умножения между значениями переменных mi2 и ni3, а уже потом бы результирующее значение этой операции прибавилось бы к значению переменной ni1. С приоритетами различных операций мы познакомимся в более поздних уроках, так как операторов нам проходить ещё много и они бывают не только арифметические.
Соберём и выполним наш код
Всё правильно сработало, результат это подтверждает.
Теперь подобную операцию между тремя операндами попробуем проделать с беззнаковыми данными типа unsigned int, но только уже без скобок
1 2 3 4 5 |
printf("(ni1 + ni2) : ni3 = %d\r\n",ni_res); uni_res = uni1 - uni2 / uni3; printf("Unsigned integer: "); printf("uni1 = %u; uni2 = %u; uni3 = %u\r\n", uni1, uni2, uni3); printf("uni1 - uni2 / uni3 = %u\r\n",uni_res); |
Соберём код и посмотрим, что теперь у нас получится
По результату всей нашей операции мы видим, что сначала выполнилось деление, а уже затем вычитание, иначе бы у нас получилось 1500000000, а не 2500000000.
Поиграем теперь с типами long
1 2 3 4 5 |
printf("uni1 - uni2 / uni3 = %u\r\n",uni_res); nl_sum = nl1 + nl2; printf("Signed long: "); printf("nl1 = %ld; nl1 = %ld\r\n", nl1, nl2); printf("nl1 + nl2 = %ld\r\n",nl_sum); |
Проверим результат
Всё правильно.
Теперь unsigned long
1 2 3 4 5 |
printf("nl1 + nl2 = %ld\r\n",nl_sum); unl_sub = unl1 - unl2; printf("Unsigned long: "); printf("unl1 = %lu; unl1 = %lu\r\n", unl1, unl2); printf("unl1 - unl2 = %lu\r\n",unl_sub); |
Смотрим результат операции
Также всё отлично работает.
Теперь попробуем поиграть с 8-байтными целыми значениями, сначала со знаковыми
1 2 3 4 5 |
printf("unl1 - unl2 = %lu\r\n",unl_sub); nll_sum = nll1 + nll2; printf("Signed long long: "); printf("nll1 = %I64d; nll1 = %I64d\r\n", nll1, nll2); printf("nll1 + nll2 = %I64d\r\n",nll_sum); |
Смотрим результат выполнения операции
Результат также правильный. Сумма двух одинаковых по модулю, но разных по знаку, чисел даёт ноль.
Теперь unsigned long long
1 2 3 4 5 |
printf("nll1 + nll2 = %I64d\r\n",nll_sum); unll_sub = unll1 - unll2; printf("Unsigned long long: "); printf("unll1 = %I64u; unll1 = %I64u\r\n", unll1, unll2); printf("unll1 - unll2 = %I64u\r\n",unll_sub); |
Соберём код и посмотрим результат
Всё отлично! Результат правильный.
А теперь давайте попробуем поработать с плавающей точкой.
Сначала float
1 2 3 4 5 |
printf("unll1 - unll2 = %I64u\r\n",unll_sub); f_div = f1 / f2; printf("Float: "); printf("f1 = %f; f2 = %f\r\n", f1, f2); printf("f1 : f2 = %f\r\n", f_div); |
Посмотрим результат выполнения нашей операции
Результат верный.
Теперь попробуем операцию над длинными величинами с плавающей точкой типа double
1 2 3 4 5 |
printf("f1 : f2 = %f\r\n", f_div); d_mul = d1 * d2; printf("Double: "); printf("d1 = %lf; d2 = %lf\r\n", d1, d2); printf("d1 x f2 = %lf\r\n", d_mul); |
Соберём код и посмотрим результат нашей операции
Отлично! Результат правильный.
И, на этом, думаю, мы закончим данное занятие, которое нас научило пользоваться арифметическими операторами и в котором, как всегда, по нашей славной традиции, мы наши знания подкрепили на практике.
Всем спасибо за внимание!
Предыдущий урок Программирование на C Следующий урок
Смотреть ВИДЕОУРОК (нажмите на картинку)
Здравствуйте! расскажите пожалуйста откуда берете модификаторы для разных типов данных, многих нет в уроке #2.
Некоторые модификаторы в вызове функции printf() позволяют отображать целые числа типа short и long. Такие модификаторы можно использовать для следующих спецификаторов типа: d, i, o, u и x. Модификатор l (эль) в вызове функции printf() указывает, что за ним следуют данные типа long. Например, %ld означает, что надо выводить данные типа long int. После модификатора h функция printf() выведет целое значение в виде short. Например, %hu означает, что выводимые данные имеют тип short unsigned int.