Какой операции нет в c
Перейти к содержимому

Какой операции нет в c

  • автор:

Какой операции нет в c

Указатели в языке Си поддерживают ряд операций: присваивание, получение адреса указателя, получение значения по указателю, некоторые арифметические операции и операции сравнения.

Присваивание

Указателю можно присвоить либо адрес объекта того же типа, либо значение другого указателя или константу NULL .

Присвоение указателю адреса уже рассматривалось в прошлой теме. Для получения адреса объекта используется операция & :

int a = 10; int *pa = &a; // указатель pa хранит адрес переменной a

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

Присвоение указателю другого указателя:

#include int main(void) < int a = 10; int b = 2; int *pa = &a; int *pb = &b; printf("Variable a: address=%p \t value=%d \n", (void*)pa, *pa); printf("Variable b: address=%p \t value=%d \n", (void*)pb, *pb); pa = pb; // теперь указатель pa хранит адрес переменной b printf("Variable b: address=%p \t value=%d \n", (void*)pa, *pa); return 0; >

Когда указателю присваивается другой указатель, то фактически первый указатель начинает также указывать на тот же адрес, на который указывает второй указатель.

Если мы не хотим, чтобы указатель указывал на какой-то конкретный адрес, то можно присвоить ему условное нулевое значение с помощью константы NULL , которая определена в заголовочном файле stdio.h:

int *pa = NULL;

Разыменование указателя

Операция разыменования указателя в виде *имя_указателя , позволяет получить объект по адресу, который хранится в указателе.

#include int main(void) < int a = 10; int *pa = &a; int *pb = pa; *pa = 25; printf("Value on pointer pa: %d \n", *pa); // 25 printf("Value on pointer pb: %d \n", *pb); // 25 printf("Value of variable a: %d \n", a); // 25 return 0; >

Через выражение *pa мы можем получить значение по адресу, который хранится в указателе pa , а через выражение типа *pa = значение вложить по этому адресу новое значение.

И так как в данном случае указатель pa указывает на переменную a , то при изменении значения по адресу, на который указывает указатель, также изменится и значение переменной a .

Указатель на void

Указатели указывают на данные определенных типов. Например, указатель типа int* указывает на значение типа int , но не может указывать на данные других типов, скажем, на объект типа float . Однако можно также определять указатели типа void* , которые могут указывать на данные любого типа. И неявно указатели любых можно преобразовать в указатель типа void* :

#include int main(void) < int x = 123; int *ip = &x; // указатель хранит адрес объекта int void *vp; vp = ip; // void-указатель получает адрес из указателя ip printf("Value: %d\n", *((int *)vp)); // Value: 123 return 0; >

Следует учитывать, что к void-указателю мы НЕ можем применить операцию разыменования и тем самым получить значение под адресу, который хранится в этом указателе. Поэтому для получения значения надо приводить к указателю соответствующего типа:

printf("Value: %d\n", *((int *)vp));

Одно из распространенных применений void-указателя — это вывод адреса на консоль:

#include int main(void) < int x = 123; int *ip = &x; // указатель хранит адрес объекта int void *vp = ip; // void-указатель получает адрес из указателя ip printf("vp: %p\n", vp); // получаем адрес, который хранится в указателе vp printf("ip: %p\n", (void*)ip); // преобразование к типу void* - получаем адрес из указателя ip return 0; >

Если мы хотим получить адрес из указателя другого типа, то, в соответствии со стандартами, его сначала надо преобразовать к типу void* .

Адрес указателя

Указатель хранит адрес переменной, и по этому адресу мы можем получить значение этой переменной. Но кроме того, указатель, как и любая переменная, сам имеет адрес, по которому он располагается в памяти. Этот адрес можно получить также через операцию & :

int a = 10; int *pa = &a; printf("address of pointer=%p \n", (void*)&pa); // адрес указателя printf("address in pointer=%p \n", (void*)pa); // адрес, который хранится в указателе - адрес переменной a printf("value on pointer=%d \n", *pa); // значение по адресу в указателе - значение переменной a

Операции сравнения

int a = 10; int b = 20; int *pa = &a; int *pb = &b; if(pa > pb) printf("pa (%p) is greater than pb (%p) \n", (void*)pa, (void*)pb); else printf("pa (%p) is less or equal pb (%p) \n", (void*)pa, (void*)pb);

Консольный вывод в моем случае:

pa (0060FEA4) is greater than pb (0060FEA0)

Приведение типов

Иногда требуется присвоить указателю одного типа значение указателя другого типа. В этом случае следует выполнить операцию приведения типов:

char c = 'N'; char *pc = &c; int *pd = (int *)pc; printf("pc=%p \n", (void*)pc); printf("pd=%p \n", (void*)pd);

Какой операции нет в c

Условные операции позволяют проверить истинность некоторого условия и оперируют понятиями «истина»/»верно» и «ложь»/»неверно». Причем «истина» (условие верно) соответствует значению 1, а «ложь» (условие не верно) — значению 0. К условным операциям относят операции сравнения и логические операции. Оба этих вида операций применяются к арифметическим операндам, то есть числам. .

Операции сравнения

Операции сравнения (еще называют операциями отношения) позволяют сравнить два значения и возвращают 1 , если выражение истинно, и 0 , если выражение ложно. В языке Си есть следующие операции сравнения:

    == Операция «равно». Возвращает 1, если оба операнда равны, и 0, если они не равны:

#include int main(void) < int a = 10; int b = 4; int c = a == b; // 0 - числа НЕ равны printf("c = %d \n", c); // c = 0 int num = 5; int result = num == 2 + 3; // 1 - числа равны printf("result = %d \n", result); // result = 1 return 0; >
int c = 10 != 4; // 1 int d = 4 != 4; // 0
int a = 10; int b = 4; int c = a > b; // 1
int c = 10 < 4; // 0
int c = 10 
int c = 10 >= 4; // 1

Как правило, операции отношения применяются в условных конструкциях типа if. else, которые мы далее рассмотрим.

Логические операции

Логические операции, как правило, применяются к отношениям и объединяют несколько операций отношения. К логическим операциям относят следующие:

    ! (операция отрицания) Если операнд равен 0, то возвращает 1, иначе возвращает 0.

int c = !2; // 0 int d = !0; // 1
int c = -2 && 5; // 1 int d = 0 && 7; // 0
int c = -2 || 5; // 1 int d = 0 || 7; // 1 int e = 0 || 0; // 0

Используем одновременно несколько логических операций и операций сравнения:

int a = -2 > 5; // 0 int b = 0 < 7; // 1 int c = 0 == 0; // 1 int d = a && b || c; // 1 printf("a = %d \n", a); printf("b = %d \n", b); printf("c = %d \n", c); printf("d = %d \n", d);

Операции сравнения имеют больший приоритет, чем логические операции, поэтому мы могли бы напрямую подставить операции сравнения:

int d = -2 > 5 && 0 < 7 || 0 == 0; // 1

Операторы назначения в C

Операция присваивания заключается в том, что значение правого операнда присваивается месту хранения, имя которого обозначено левым операндом. Поэтому левый операнд в операции присваивания должен иметь изменяемое l-значение. После назначения выражение присваивания имеет значение левого операнда, но не является l-значением.

Синтаксис

assignment-expression :
conditional-expression
unary-expression assignment-operator assignment-expression

assignment-operator : один из следующих символов:
= *= /= %= += -= >>= &= ^= |=

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

Оператор Выполняемая операция
= Простое присваивание
*= Присваивание умножения
/= Присваивание деления
%= Присваивание остатка
+= Присваивание сложения
-= Присваивание вычитания
Присваивание сдвига влево
>>= Присваивание сдвига вправо
&= Присваивание побитового И
^= Присваивание побитового исключающего ИЛИ
| = Присваивание побитового включающего ИЛИ

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

См. также

Логические операторы в си

Л огические операторы – это операторы, которые принимают в качестве аргументов логические значений (ложь или истину) и возвращают логическое значение. Как и обычные операторы, они могут быть одноместными (унарными, т.е. принимать один аргумент), двуместными (бинарные, принимают два аргумента), трёхместными и т.д.

Особенностью языка си является то, что в нём нет типа, хранящего булево значение (ложь или истину). В си ложью (логическим нулём) считается целочисленный 0, а любое ненулевое целое будет логической истиной. Например

#include #include void main() < char boolValue = -71; if (boolValue) < printf("boolValue is true"); >else < printf("boolValue is false"); >_getch(); >

Логические значения обычно порождаются операторами сравнения (==, !=, >, =. <=).

В языке си представлено три логических оператора: И, ИЛИ и НЕ. Начнём с самого простого

Логическое отрицание

О ператор НЕ (NOT) используется для того, чтобы инвертировать значение аргумента. Т.е., если ему передали истину, то он вернёт ложь, если получил ложь в качестве аргумента, то вернёт истину.

Логический оператор НЕ

X NOT X
0 1
1 0

В си отрицание представлено оператором !. Например

#include #include void main() < int i = 0; if (i) < printf("i is true\n"); >if (!i) < printf("i is not true\n"); >if (!!i) < printf("i is not not true\n"); >if (. i) < printf("i is not not not true\n"); >_getch(); >

Как и в обычной логике, здесь действует закон двойного отрицания – отрицание отрицания можно опустить.

Логическое И

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

Логический оператор И

X Y X AND Y
0 0 0
0 1 0
1 0 0
1 1 1

В си логическое умножение представлено оператором &&. Например, задача – в кружок военных спейсмаринов допускаются только совершеннолетние граждане мужского пола. То есть, претендентом может стать только тот, для которого одновременно два условия являются истиной

#define _CRT_SECURE_NO_WARNINGS #include #include void main() < char gender; unsigned int age; printf("Enter gender ('M' or 'F')\n"); scanf("%c", &gender); printf("Enter age\n"); scanf("%u", &age); if (gender == 'M' && age >17) < printf("Wellcome"); >else < printf("Go away"); >_getch(); >

Оператор И может применяться последовательно к нескольким аргументам. Для него действует ассоциативный и коммутативный законы. Усовершенствуем программу, будем также вводить рост:

#define _CRT_SECURE_NO_WARNINGS #include #include void main() < char gender; unsigned int age; unsigned int height; printf("Enter gender ('M' or 'F')\n"); scanf("%c", &gender); printf("Enter age\n"); scanf("%u", &age); printf("Enter height\n"); scanf("%u", &height); if (gender == 'M' && age >17 && height >= 180) < printf("Wellcome"); >else < printf("Go away"); >_getch(); >

Также условие могло быть записано

(gender == 'M' && age > 17) && height >= 180
gender == 'M' && (age > 17 && height >= 180)
(age > 17 && height >= 180) && gender == 'M'

Логическое ИЛИ

О ператор логическое ИЛИ (логическое сложение, OR) истинен тогда, когда истиной является хотя бы один его аргумент.

Логический оператор ИЛИ

X Y X OR Y
0 0 0
0 1 1
1 0 1
1 1 1

В си ИЛИ представлен оператором ||. Например, усовершенствуем программу: теперь пол можно вводить как большой, так и маленькой буквой

#define _CRT_SECURE_NO_WARNINGS #include #include void main() < char genderInput; char gender; unsigned int age; unsigned int height; printf("Enter gender ('M' or 'F')\n"); scanf("%c", &genderInput); printf("Enter age\n"); scanf("%u", &age); printf("Enter height\n"); scanf("%u", &height); if (genderInput == 'M' || genderInput == 'm') < gender = 1; >else < gender = 0; >if ((age > 17 && height >= 180) && gender) < printf("Wellcome"); >else < printf("Go away"); >_getch(); >

Как и в случае оператора И, ИЛИ коммутативен и ассоциативен.

Операторы можно перемешивать друг с другом, создавая сложные операторы

#define _CRT_SECURE_NO_WARNINGS #include #include void main() < char gender; unsigned int age; unsigned int height; printf("Enter gender ('M' or 'F')\n"); scanf("%c", &gender); printf("Enter age\n"); scanf("%u", &age); printf("Enter height\n"); scanf("%u", &height); if ((age >17 && height >= 180) && (gender == 'M' || gender == 'm')) < printf("Wellcome"); >else < printf("Go away"); >_getch(); >

Стоит только помнить о том, что оператор отрицания имеет больший приоритет, чем И или ИЛИ, поэтому будет выполняться в первую очередь. Если может случиться ситуация, когда порядок выполнения не ясен, определите его с помощью скобок.

Пример: закон де-Моргана. Чтобы сменить И на ИЛИ (или наоборот), необходимо инвертировать значения всех операндов, заменить И на ИЛИ (или ИЛИ на И) и инвертировать конечный результат. В случае с нашим условием

(age > 17 && height >= 180) && (gender == 'M' || gender == 'm')

Рассмотрим сначала кусок

(age > 17 && height >= 180)

Меняем все значения на обратные

(!(age > 17) && !(height >= 180))

заменяем оператор && на ||

(!(age > 17) || !(height >= 180))

и инвертируем ответ

!(!(age > 17) || !(height >= 180))

Как видим, результат тот же. Очевидно, что

!(age > 17)

Таким образом, изменим условие

Поменяем таким же образом вторую скобку

(gender == 'M' || gender == 'm')
!(gender != 'M' && gender != 'm')

Теперь можно применить это же правило и для всего выражения

Порядок выполнения логических операторов

Р ассмотрим выражение

где a, b, c, d – логические значения. Всё выражение равно истине тогда и только тогда, когда все операнды истинны. Если хотя бы один из операндов ложь, то остальные уже не важны. Поэтому, для оптимизации работы, вычисление происходит слева направо и останавливается, как только был найден первый операнд, равный нулю.

В си оператор присваивания может возвращать значение. Иногда он используется непосредственно в условии:

#define _CRT_SECURE_NO_WARNINGS #include #include #include void main() < int a = 0; int *p = &a; if (a && (p = (int*) malloc(sizeof(int) * 2))) < printf("memory was allocated"); >free(p); _getch(); >

В данном случае, оператор malloc не будет выполнен, так как первый операнд a равен 0 (соответственно, всё выражение равно нулю). Таким образом, оператор free попытается очистить память, которую не может очистить (т.к. p продолжит ссылаться на a). Если же мы поменяем a = 1, то всё отработает без проблем.

То же самое происходит и при выполнение ||. Выражение

выполняется слева направо до тех пор, пока не встретит первое ненулевое значение. После этого выполнение останавливается, так как известно, что всё выражение равно истине.

Очевидно, что это касается не только оператора присваивания, но и любого другого вызова функции. Например, в этом случае функции foo будет вызвана, bar нет.

#define _CRT_SECURE_NO_WARNINGS #include #include #include int foo() < printf("foo\n"); return 0; >int bar() < printf("bar\n"); return 0; >void main() < int a = 0, b = 1; if (a || foo() || b || bar()) < printf("OK\n"); >_getch(); >

Вывод – не используйте присваивания и вызовов функций (особенно, если они изменяют состояние программы) внутри условий.

ru-Cyrl 18- tutorial Sypachev S.S. 1989-04-14 sypachev_s_s@mail.ru Stepan Sypachev students

email

Всё ещё не понятно? – пиши вопросы на ящик

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *