Лекция: Общее знакомство

Вид материалаЛекция

Содержание


Операции вызова функции, индексирования и выбора
Унарные операции
Мультипликативные операции
Арифметические действия с указателями
Подобный материал:
1   2   3   4   5   6   7   8   9   ...   33

Дополнительные операции


В языке Си имеется около сорока операций. Те операции, которые мы рассмотрели, являются наиболее общеупотребительными. Рассмотрим еще три операции, наиболее используемые программистами.

Операция деления по модулю: %


Эта операция используется в целочисленной арифметике. Ее результатом является остаток от деления целого числа, стоящего слева от знака операции, на число, расположенное справа от нее. Например, 63%5, читается как 63 по модулю 5, имеет значение 3, т.к. 12*5+3.

В результате выполнения оператора

minutes=time%60;

переменной minutes будет присвоено значение остатка от деления time на 60.

Операция увеличения: ++


Операция увеличения осуществляет следующее простое действие: она увеличивает значение своего операнда на единицу. Существуют две возможности использования данной операции: первая, когда символы ++ находятся слева от переменной (операнда), - "префиксная" форма, и вторая, когда символы ++ стоят справа от переменной, - "постфиксная" форма. Эти две формы указанной операции различаются между собой только тем, в какой момент осуществляется увеличение операнда. Префиксная форма изменяет значение операнда перед тем, как операнд используется. Постфиксная форма изменяет значение после того как операнд используется.

В примере,

j=i++;

переменной j сначала присваивается значение i, затем значение переменной i увеличивается на 1.

Операция уменьшения: --


Каждой операции увеличения соответствует некоторая операция уменьшения, при этом вместо символов ++ мы используем --. Когда символы -- находятся слева от операнда - "префиксная" форма операции уменьшения. Если символы -- стоят справа от операнда - это "постфиксная" форма операции уменьшения.

В соответствии с принятым в языке Си порядком вычислений операции увеличения и уменьшения имеют очень высокий уровень старшинства. Только круглые скобки обладают более высоким приоритетом. Поэтому выражение a/b++ означает (a)/(b++), а не (a/b)++.

!

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

Перечень операций языка Си


Рассмотрим множество операций языка Си. Описанные операции входят в это множество. Язык Си отличается их большим разнообразием. В этом разделе будет обсуждаться их семантика. Каждая операция характеризуется уровнем приоритета и порядком, в котором эти операции выполняются - слева направо или справа налево. Если все операции выражения имеют один и тот же уровень приоритета, то значение выражения вычисляется слева направо в соответствии с порядком выполнения операций. Все операции с одним и тем же уровнем приоритета имеют один и тот же порядок. Однако если в выражении имеются операции с различными уровнями приоритета, то сначала выполняются операции с наивысшим уровнем приоритета, затем - следующего за ним приоритета и так далее в порядке убывания приоритета. Операции одного уровня приоритета выполняются в последовательности, указанной их порядком.

Операции, уровень приоритета которых равен 1


^ Операции вызова функции, индексирования и выбора. В качестве операций языка Си рассматриваются также скобки в вызове функции, квадратные скобки для индексирования массивов, точка и стрелка вправо для выбора компонентов структуры или объединения. Уровень этих операторов равен 1, все операции выполняются слева направо.
Операция вызова функции: ( )

Пример 1:

fe(e1, e2,...,en);

Вызов функции fe с аргументами e1, e2, ..., en. Значением этого выражения является значение, которое возвращает функция.

Пример 2:

x = sqrt (y);
Операция индексирования массива: []

Синтаксис:

array [2]

Значением выражения является третий элемент массива.

Присвоение значения 26 одиннадцатому элементу массива записывается таким образом:

array[10]=26;

Первый элемент массива описывается выражением array[0] (более подробно о массивах описано в лекции 12).
Операция выбора компонентов структуры или объединения: .

Синтаксис:

struct.element

Значением этого выражения является элемент element структуры struct или объединения (см. лекцию 14). Оператор:

struct.element=1963;

присваивает значение 1963 этому элементу.
Операция выбора компонентов структуры с указателем: ->

Синтаксис:

my_birthday->day,

my_birthday - указатель на структуру. Оператор:

my_birthday->day=26;

присваивает значение 26 структурной переменной day, на которую указывает my_birthday.

Операции, уровень приоритета которых равен 2


^ Унарные операции. Для унарных операций требуется только один операнд; эти операции либо префиксные, либо префиксные и постфиксные. Операция sizeof имеет два варианта: префиксная операция и унарная операция.
Операция косвенной ссылки: *

Это указатель на любой тип T, кроме void. Тип результата T.

Использование:

*pe

Значением выражения является переменная, адресуемая указателем pe.

Пример 1:

*ptr=c;

Пример 2:

*fpe;

Значением выражения является функция, адресуемая указателем fpe.

Пример 3:

fpe=*funcname;

(*fpe)(arg1, arg2);
Операция получения адреса: &

У этой операции тип операнда есть переменная любого типа, кроме void. Тип результата - указатель на Т.

Использование:

&v

Значением выражения является адрес переменной v.

Пример:

myptr=&n;
Операция отрицания: -

Тип операнда - арифметический. Тип результата: unsigned, long, double, int.
Операция логического отрицания: !

Тип операнда - арифметический или указатель. Тип результата - int. Если операнд равен 0, то результат равен 1 и наоборот.

Пример:

if(!good) printf("not good");
Операция дополнения до 1: ~

Тип операнда - интегральный. Тип результата: int, long, unsigned.

Пример:

opposite=~mask;

Дополнение до единицы значения mask. Результат присваивается переменной opposite.
Операция увеличения: ++

Тип операнда - арифметический или указатель. Тип результата: int, unsigned, long, double, указатель. Значение операнда увеличивается, и становится новым значением операнда. Значение указателя увеличивается на величину указываемого объекта, значения других операндов увеличиваются на единицу.
Операция увеличения, постфиксная: ++

Тип операнда - арифметический или указатель. Тип результата: int, unsigned, long, double, указатель. Значение операнда увеличивается, но возвращается старое значение операнда. Значение указателя увеличивается на величину указываемого объекта, другие операнды увеличиваются на единицу.

Использование:

iv++

Увеличение iv на 1. Значением этого выражения является значение iv до увеличения.

Пример:

j=i++;

Использование:

pv++;

Увеличение указателя pv на 1, так что он будет указывать на следующий объект того же типа. Значением этого выражения является значение pv до увеличения.

Пример:

*ptr++=0;

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

Тип операнда - те же, что и для ++. Тип результата - те же, что и для ++.

Использование:

--iv

Уменьшение iv на 1. Значением этого выражения является значение iv после уменьшения.

Пример:

i=--j;
Операция уменьшения (постфиксная): --

Тип операнда - те же, что и для ++(постфиксная).

Использование:

iv--

Уменьшение iv на 1. Значением этого выражения является значение iv до уменьшения.

Пример:

j=i--;
Операция определения требуемой памяти в байтах: sizeof

Тип операнда - значение любого типа или имени типа. Тип результата - unsigned. Используется как sizeof (выражение) или sizeof (имя типа).

Пример:

n=sizeof(arname)/sizeof(int);

Число элементов в массиве целых чисел, определяемое как число байт в массиве, поделенное на число байт, занимаемых одним элементом массива.

Операции, уровень приоритета которых равен 3


^ Мультипликативные операции. Порядок выполнения мультипликативных операций - слева направо.
Операция умножения: *

Тип операндов - арифметический. Тип результатов: int, unsigned, long, double.

Использование:

ae1*ae2

Произведение значений ae1*ae2.

Пример:
z=35*5;
Операция деления: /

Тип операндов - арифметический. Тип результата - int, unsigned, long, double.

Использование:

ae1/ae2

Частное от деления ae1 на ae2.

Пример:

i=j/7;
Операция получения остатка: %

Тип операндов - интегральный. Тип результата int, unsigned, long. Знак остатка машинно-зависим.

Использование:

ae1%ae2

Остаток от деления по модулю.

Пример:

j=i%2;

Если i четное число, то j равно нулю.

Операции, уровень приоритета которых равен 4


Уровень приоритета аддитивных операций равен 4. Выполняются эти операции слева направо.
Операция сложения: +

Тип операндов:
  1. арифметический;
  2. один операнд указатель, другой - интегрального типа; оба операнда не могут быть указателями.

Тип результата: int, unsigned, long, double, указатель. Перед сложением значение целого операнда умножается на величину элемента данных, тип которых соответствует типу указателя.

Использование:

ae1+ae2

Сумма значений ae1 и ae2.

Пример 1:

i=i+100;

Первоначальное значение I увеличивает на 100.

Пример 2:

last=arname+arsize-1;

Присваивает переменной last адрес последнего элемента массива arname.
Операция вычитания: -

Тип операндов:
  1. арифметический;
  2. один операнд - указатель, другой - интегрального типа;
  3. операнды - указатели одного типа.

В первом случае тип результата: int, unsigned, long, double. Во втором случае тип результата - указатель. До вычитания значение целого операнда умножается на величину элемента данных, тип которых соответствует типу указателя. В третьем случае тип результата - int. Результат - число объектов, отделенных двумя указателями.

^ Арифметические действия с указателями. Арифметические действия с указателями отличаются от арифметических действий с обычными целыми значениями, и определяются следующим образом. Предположим, что i является целым выражением, а указатели p и q указывают на элементы типа Т. Сложение значения i и p эквивалентно сложению числа ячеек памяти в байтах, занятых i элементами типа Т. Аналогично определяется операция вычитания. Результат вычитания двух указателей типа *Т является не разностью значений двух указателей, а числом элементов типа Т, размещенных между ячейками, ссылки на которые обеспечиваются указателями. Никакие другие арифметические действия с указателями не допускаются. Вычитание указателей имеет смысл только для указателей, ссылающихся на элементы одного и того же массива, поскольку только в этом случае разность адресов элементов массива всегда равна произведению целого значения на величину элемента.

Использование:

ae1-ae2

Разность значений ae1 и ae2.

Пример 1:

i=j-100;

Использование:

pe-ie

Адрес переменной типа pe, меньше на ie адреса, заданного указателем pe.

Пример 2:

first=last-arsize+1;

Использование:

pe1-pe2

Число переменных типа pe в диапазоне от pe2 до pe1.

Пример 3:

arsize=last-first;

Операции, уровень приоритета которых равен 5


Уровень приоритета операций сдвига равен 5. Порядок выполнения операций - слева направо.
Операция сдвига влево: <<

Тип операнда - интегральный. Тип результата - такой же, как у левого операнда. Правый операнд преобразуется к типу int. Левый операнд сдвигается на число разрядов, равное значению правого операнда. Освобождающие разряды заполняются нулями.

Использование:

ie1<
Двоичное представление ie1 сдвигается влево на ie2 разрядов, освобождающие разряды заполняются нулями.

Пример:

four=x<<2;
Операция сдвига вправо: >>

Тип операнда - интегральный. Тип результата - такой же, как у левого операнда. Правый операнд преобразуется к типу int. Левый операнд сдвигается на число разрядов, равное значению правого операнда. Сдвиг будет логическим сдвигом, если левый операнд имеет тип unsigned.

Использование:

ie1>>ie2

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

Пример:

x=x>>3;

Операции, уровень приоритета которых равно 6


Уровень приоритета операций отношения равен 6. Выполняются эти операции слева направо.
Операция меньше: <

Тип операндов - арифметический или указатель. Тип результата - int.

Использование:

ae1
Истина, если ae1 меньше, чем ae2.

Пример:

if(x<0) printf("negative");
Операция больше: >

Тип операндов - арифметический или указатель. Тип результата - int.

Использование:

ae1>ae2

Истина, если ae1 больше, чем ae2.

Пример:

if(x>0) printf("positive");
Операция меньше или равно: <=

Тип операндов - арифметический или указатель. Тип результата - int.

Использование:

ae1<=ae2

Истина, если ae1 меньше или равно ae2.
Операция больше или равно: >=

Тип операндов - арифметический или указатель. Тип результата - int.

Использование:

ae1>=ae

Истина, если ae1 больше или равно ae2.

Операции, уровень приоритета которых равен 7


Уровень приоритетов операций равенства/неравенства равен 7, выполняются они слева направо.
Операция равенство: ==

Тип операндов - арифметический или указатель. Тип результата - int.

Использование:

ie1==ie2

Истина, если ie1 равно ie2, иначе - ложь.
Операция неравенство: !=

Тип операндов - арифметический или указатель. Тип результата -int.

Единственным целым значением, с которым можно сравнивать указатели, является нулевое значение!

Использование:

ie1!=ie2

Истина, если ie1 не равно ie2.

Пример:

while (i!=0)

i=func;

Операция, уровень приоритета которой равен 8


Уровень приоритета операции поразрядное И равен 8. Выполняются такие операции слева направо.
Операция поразрядное И: &

Тип операндов - интегральный. Тип результата: int, long, unsigned.

Использование:

ie1 & ie2

Побитовая операция И двоичных представлений ie1 и ie2. Значение выражения содержит 1 во всех разрядах, в которых и ie1 и ie2 содержат 1, и 0 во всех остальных разрядах.

Пример:

flag=((x&mask)!=0);

Операция, уровень приоритета которой равен 9


Уровень приоритета операции поразрядное исключающее ИЛИ равен 9. Порядок выполнения таких операций слева направо.
Операция поразрядное исключающее или: ^

Тип операндов - интегральный. Тип результата: int, long, unsigned.

Использование:

ie1^ie2

Побитовая операция исключающее ИЛИ двоичных представлений ie1 и ie2. Значение выражения содержит 1 в тех разрядах, в которых и ie1 и ie2 имеют разные двоичные значения, и 0 во всех остальных разрядах.

Пример:

diffbits=x^y;

Операция, уровень приоритета которой равен 10


Уровень приоритета операции поразрядное включающее или равен 10, порядок выполнения таких операторов - слева направо.
Операция поразрядное включающее или: |

Тип операндов - интегральный. Тип результата: int, long, unsigned.

Использование:

ie1 | ie2

Побитовая операция ИЛИ двоичных представлений ie1 и ie2. Значение выражения содержит 1 во всех разрядах, в которых ie1 или ie2 содержат 1, и 0 во всех остальных разрядах.

Пример:

attrsum=attr1 | attr2;

Операция, уровень приоритета которой равен 11


Уровень приоритета логический (условный) операции и равен 11. Выполняется операция слева направо.
Операция логическое И: &&

Тип операндов - арифметический или указатель. Тип результата - int. Если первый операнд равен 0, то результат равен 0. В противном случае результат будет равен 1, если второй операнд не равен 0, и равен 0, если второй операнд равен 0 (если первый операнд равен 0, то второй операнд не вычисляется).

Использование:

e1&&e2

Логическая операция И значений e1 и e2. Вначале проверяется значение e1; значение e2 проверяется только в том случае, если значение e1 -Истина. Значением выражения является Истина, если значения e1 и e2 - Истина.

Пример:

if(p!=NULL&&*p>7) n++;

Если p - не нулевой указатель и значение переменной, на которую указывает p, больше, чем 7, то в этом случае n увеличивается на 1. Обратите внимание, что если значение указателя p равно NULL(0), то выражение *p не имеет смысла.

Операция, уровень приоритета которой равен 12


Уровень приоритета операции равен 12, выполняются такие операции слева направо.
Операция логическое ИЛИ: ||

Тип операндов - арифметический или указатель. Тип результата int. Если хотя бы один операнд не равен 0, результат равен 1; иначе результат будет равен 0.

Использование:

e1 || e2

Логическая операция ИЛИ значений e1 и e2. Вначале проверяется значение e1; значение e2 проверяется только в том случае, если значение e1 - ложь. Значением выражения является Истина, если истинны значения e1 и e2.

Пример 1:

if(xB) printf("out of range");

Операция, уровень приоритета которой равен 13


Уровень приоритета операции равен 13, выполняются такие операции слева направо.
Операция условный оператор: ?

Тип операндов - арифметические; второй и третий операнды могут быть указателями, структурами, объединениями. Тип результата: int, long, unsigned, double, указатель, структура или объединение. Второй и третий операнды преобразуются к одному и тому же типу.

Условный оператор является единственным оператором, для которого необходимы три операнда; используется он следующим образом:

a ? b : c

где a, b, c - выражения. Если a не равно 0, то результат выражения a ? b : c равен b; иначе результат равен c. Из двух последних операндов вычисляется только один.

Использование:

ae?e1:e2

или

pe?e1:e2 (где pe - указатель)

Если истинно ae или pe, то выполняется e1; иначе выполняется e2. Значением этого выражения является значение выражения e1 или e2.

Пример:

abs=(I<=0)?-i:i;

Операция, уровень приоритета которой равен 14


Уровень приоритета операции равен 14, выполняются такие операции справа налево.
Операция простое присваивание: =

Тип операндов: арифметические, указатели, объединения или структуры. Тип результата: если оба результата имеют арифметический тип, то значение правого операнда преобразуется к типу левого операнда.

Использование:

v=e

Присваивание значения e переменной v.

Пример:

x=y;
Операция сложное присваивание: =

Обозначим <знак> один из знаков : +, -, *, /, %, >>, <<, &, ^, |.

В результате выполнения операции присваивания

v=e

где v - переменная, а e - выражение, значение выражения становится новым значением переменной v.
Операция присваивания

v <знак> = e

приблизительно эквивалентна оператору присваивания

v = v<знак> e

Пример 1:

y+=2; /* Увеличение переменной y на 2 */

p+=n;

x-=3;

ptr-=2;

timesx*=x;

x/=2;

x%=10;

x>>=4;

x<<=1;

remitems&=mask;

control^=seton;

additems I=mask;

Типы операндов и результата сложного оператора присваивания можно определить на основании этой эквивалентности. Однако приведенный эквивалент для сложного оператора присваивания не совсем точен. В выражении

v = <знак> e

операнд v вычисляется только один раз, в то время как в выражении

v = v <знак> e

этот операнд вычисляется дважды. Это различие проявляется в побочных эффектах, связанных с вычислением операнда v, например, при изменении значения какой-либо переменной. Рассмотрим это на примерах:

a[i++]* = n;

При выполнении вычисление левого операнда дает побочный эффект - увеличение значения переменной i. Следовательно, это присваивание не эквивалентно присваиванию

a[i++] = a[i++]*n;.

Эквивалентом первой операции присваивания может служить последовательность операций

a[i]=a[i]*n;

i=i+1;

а эквивалентом второй - последовательность операций

a[i]=a[i+1]*n;

i=i+2;

или последовательность операций

a[i+1]=a[I]*n;

i=i+2;

в зависимости от того, какая часть операции присваивания вычисляется раньше - левая или правая. Порядок таких вычислений не определен.

Операция, уровень приоритета которой равен 15


Уровень приоритета операции равен 15, выполняются такие операции слева направо.
Операция запятая: ,

Тип результата совпадает с типом правого операнда. Операция объединяет два выражения в одно выражение, значением которого является значение правого операнда; значение левого операнда вычисляется только для получения побочных эффектов.

Использование:

el,e2

Сначала выполняется выражение e1, потом выражение е2. Значением всего выражения является значение выражения е2.

Пример:

for(i=A,j=B;i
/* организация циклического повторения.

Оператор со счетчиком */

p[i]=p[j];

Примеры простых задач

/* Задача № 1 (пример на использование операции *)

Определить площадь боковой поверхности конуса радиуса

r и имеющего длину образующей 1.*/

#include

#include

/* подключение библиотеки математических функций */

const float pi=3.14159;

float r=10; float l=50; float s;

main()

{

s=pi*r*l;

printf("\n Площадь боковой поверхности s=%f",s);

}


/* Задача № 2 (пример на использование операций +,

* и /. Тело движется прямолинейно с ускорением.

Даны а(м/сек2) - ускорение, V(M/C) - начальная

скорость. Требуется определить, какой путь пройдет

тело за t секунд.*/

#include

float а, v, t, s ;

main()

{

a=20.2;

v=50.3;

t=65;

s=(v*t)+(a*t*t/2);

printf("\n Путь s=%f M",S);

}

/* Задача № 3 (пример на использование операций =,

/ и вычисления степени). Вычислите среднее арифметическое

и среднее геометрическое трех чисел а,b,с.*/

#include

#include

float a=b=c=2005.1; float x,у;

main ()

{

x=(a+b+c)/3;

y=pow( (a*b*c),(1/3));

/*функция pow берется из библиотеки math.h*/

printf("\n среднее арифметическое x=%f",x);

printf("\n среднее геометрическое y=%f",y);

}

/* Задача № 4 (пример на использование операций

=,*, / и функции hypot. Даны катеты прямоугольного

треугольника. Найти его гипотенузу и площадь.*/

#include

#include

float x=y=50.7; float z,s;

main()

{

z=hypot(х, у) ;/* вычисление гипотенузы*/

s=x*y/2;

printf("\n гипотенуза=%f см",z);

printf("\n Плoщaдь=%f кв см",s);

}