This commit is contained in:
2025-12-28 00:10:39 +03:00
parent 9f530baad8
commit 1640c3a6d2
5 changed files with 127 additions and 8 deletions

92
3variables/variables.c Normal file
View File

@@ -0,0 +1,92 @@
int main(){
// переменная типа int (integer) с именем a
int a = 1;
int b = 2;
return a+b;
}
// напоминаю, `echo %ERRORLEVEL%` после запуска
// Базовые "элементарные" типы:
int unused_code(){
char symbol = 'a'; // ASCII символ. Практически, это все символы на клавиатуре кроме кириллицы
float number = 2.3; // дробное число
unsigned int notnull = 2; // целое беззнаковое число.
// Строка в C определяется как массив ASCII символов, который заканчивается символом конца строки '\0'.
// Я не хочу сейчас говорить про массивы, т.к. они связаны с понятием указателя, поэтому отмечу только следующее:
char string1[] = {'S', 't', 'r', 'i', 'n', 'g', '\0'}; // так выглядит создание массива с заранее заданными значениями
char string2[] = "String"; // для строк есть более удобный синтаксис. строка 2 хранит то же самое, что и строка 1
// Что можно делать с переменными, кроме как создавать?
int c; // их можно задавать без указания значения. Тогда их байты могут быть
// как случайными (заполнеными мусором), так и заполнеными нулями, но на это лучше не полагаться
c = notnull; // в данном примере проблемы нет, так как у notnull значение 2, но
// если у переменных разный тип, то нет гарантии того, что присваивание значения
// одной переменной другой будет выполнять то, что вы думаете
c = number; // нам не нужно указывать, что у c тип int, т.к. это уже было сделано ранее.
// Аналогично, т.к. int может хранить значение 2, то в данном контексте операция законна,
// но не для любого float так можно делать.
// Т.к. компьютер воспринимает все примитивные типы как числа, то:
// Можно применять побитовые логические операции (число считается за вектор битов):
int a = 5, b = 3;
// ЛОГИЧЕСКОЕ И: &, ЛОГИЧЕСКОЕ ИЛИ: |, XOR: ^, ЛОГИЧЕСКОЕ НЕ: ~
c = a&b; // c = 0b...0101 & 0b...0011 = 0b...0001 = 1
c = a|b; // c = 0b...0101 | 0b...0011 = 0b...0111 = 7
c = a^b; // c = 0b...0101 ^ 0b...0011 = 0b...0110 = 6
c = ~a; // зависит от числа байт в int. Так-то не знаем, но на x86_64 процессорах int это 4 байта. Тогда:
// c = ! 0b 00000000_00000000_00000000_00000101 = 0b 11111111_11111111_11111111_11111010 = ?
// Начиная с C23 (последнего стандартно) в языке регламентировано то, что 1 бит соответствует знаку -.
// Тогда если все биты 1 - то получится -1, если первый бит 1 а остальные 0 - получится -2^{число битов -1}. 4 байта->32 бита -> -2^31
// 0b 11111111_11111111_11111111_11111010 = 0b 11111111_11111111_11111111_11111111 - 0b...0101 = -1 - 5 = -6
// По сути, для целых чисел ~x === -x-1
// float устроены внутри себя гораздо сложнее, чем целочисленные типы, лучше с ними такого не делать
// сдвиг влево/вправо: << и >>
c = a << 1; // c = 0b...0101 << 1 = 0b...01010 = 10
// по сути, для целых чисел x << y = x * 2^y
c = a >> 1; // c = 0b...0101 >> 1 = 0b...010 = 2
// по сути, для целых чисел x >> y = x / 2^y
// просто логические операторы. Тогда, с точки зрения C, false = 0, не false (т.е. true) = не 0:
// ЛОГИЧЕСКОЕ И: &&, ЛОГИЧЕСКОЕ ИЛИ: ||, ЛОГИЧЕСКОЕ НЕТ: !
c = a && b; // 1, т.к. оба истина
c = 0 && a; // 0, т.к. есть ложь. При этом a даже не вычисляется (всё ради оптимизаций)
c = 0 || 0; // 0, т.к. оба ложь
c = a || 0; // 1, т.к. есть истина. Правое значение тоже не вычисляется
c = !a; // 0, т.к. a - истина
// операторы сравнения
c = a==b; // 0, т.к. a > b
c = a!=b; // 1, т.к. a > b
c = a>b; // 1, т.к. a > b
c = a>=b; // 1, т.к. a > b
c = a<b; // 0, т.к. a > b
c = a<=b; // 0, т.к. a > b
float nan = 0.0/0.0; // за счёт '.' компилятор понимает, что 0.0 - это float, а не int
float inf = 1.0/0.0;
float negative_inf = -inf;
float negative_zero = -1/0/inf;
c = nan==nan; // ложь. Аналогично с >= и <=
c = nan!=nan; // истина
c = negative_inf==inf; // ложь
c = negative_zero==0.0; // истина
c = 1.0/0.0 == 1.0/negative_zero; // ложь (т.к. negative_inf != inf)
// арифметические действия
c = a+b;
c = a-b;
c = a%b; // остаток от деления. 5 % 3 = 2. При этом, почему-то, -5%3 = -2, а не 1
с = a/b; // целочисленное деление. 5/3 = 1. При этом -5/3 = -1.
// a == b*(a/b)+a%b (если b != 0)
// для дробных чисел, конечно же, не выполняется, т.к. они связаны с неточными вычислениями.
// возведения в степень нет
return 0;
}