Чем характеризуется переменная?
Переменные (как и величины вообще) имеют три основные характеристики:
1) уникальное собственное имя, состоящие из допустимых символов и соответствующее правилам некоторого языка программирования;
2) тип переменной, который определяется исходя из ее назначения и хранимых в ней данных;
3) размер переменной (каждый тип имеет определенный размер, адаптированный под особенности кодирования конкретного типа данных, например, размер переменных целочисленнного типа меньше размера вещественных переменных).
Язык С: переменные
Переменная — это не что иное, как именованная область памяти, которой могут манипулировать программы. Каждая переменная в языке C характеризуется:
- типом, определяющим размер и расположение памяти переменной;
- диапазоном значений, которые могут храниться в этой памяти;
- набором операций, которые можно применить к переменной.
Имя переменной может состоять из букв, цифр и символа подчеркивания. Оно должно начинаться либо с буквы, либо с символа подчеркивания. Строчные и заглавные буквы различаются, поскольку C чувствителен к регистру. Выделим основные типы переменных:
- char — целочисленный тип, представляющий обычно один октет (один восьмибитовый байт);
- int — наиболее естественный размер целого числа для компьютера;
- float — значение с плавающей запятой одинарной точности;
- double — значение с плавающей запятой двойной точности;
- void — представляет отсутствие типа.
Язык C также позволяет определять другие типы переменных (перечисление, указатель, массив, структура, объединение и т.д.), которые будут рассмотрены в последующих разделах. Здесь уделим внимание только основным типам переменных.
Определение переменных
Определение переменной указывает компилятору, где и какой объем памяти нужно создать для этой переменной. Определение переменных задает тип данных и содержит список одной или нескольких переменных этого типа следующим образом:
type variable_list;
Здесь type должен быть допустимым типом данных языка C, включая char , w_char , int , float , double , bool или любой объект, определяемый пользователем; а variable_list может состоять из одного или нескольких имен идентификаторов, разделенных запятыми. Ниже показаны некоторые допустимые объявления:
int i, j, k;
char c, ch;
float f, salary;
double d;
Строка int i, j, k; объявляет и определяет переменные i , j и k ; которые инструктируют компилятор создать переменные с именами i , j и k типа int .
Переменные могут быть инициализированы (им присваивается начальное значение) в их объявлении. Блок инициализации состоит из знака равенства, за которым следует константное выражение, как показано ниже:
type variable_name = value;
extern int d = 3, f = 5; // объявление d и f.
int d = 3, f = 5; // определение и инициализация d и f.
byte z = 22; // определение и инициализация z.
char x = 'x'; // переменная x имеет значение 'x'.
Определение без инициализации: переменные со статической длительностью хранения неявно инициализируются со значением NULL (все байты имеют значение 0 ); начальное значение всех остальных переменных не определено.
Объявление переменных
Объявление переменной подтверждает компилятору, что существует переменная с заданным типом и именем. Получив такое подтверждение, компилятор может приступить к дальнейшей компиляции, не требуя полной информации о переменной. Определение переменной имеет значение только во время компиляции: компилятору необходимо фактическое определение переменной во время сборки программы.
Объявление переменной полезно при использовании нескольких файлов и определении переменной в одном из файлов, который будет доступен во время сборки программы. Можно использовать ключевое слово extern для объявления переменной в любом месте. Хотя в своей программе вы можете объявлять переменную несколько раз, она должна быть определена только один раз в файле, функции или блоке кода.
Пример
Рассмотрим пример, где переменные были объявлены в самом верху, но определены и инициализированы внутри главной функции.
#include // Объявление переменных:
extern int a, b;
extern int c;
extern float f;int main () /* объявление переменных: */
int a, b;
int c;
float f;
/* фактическая инициализация */
a = 10;
b = 20;
c = a + b;
printf("value of c : %d \n", c); f = 70.0/3.0;
printf("value of f : %f \n", f);
return 0;
>
Когда приведенный выше код компилируется и выполняется, выдается следующий результат:
value of c : 30
value of f : 23.333334
Тот же принцип применим к объявлению функции, когда вы указываете имя функции во время ее объявления, а ее фактическое определение может быть дано в любом другом месте. Например:
// объявление функции
int func();int main() // вызов функции
int i = func();
>// определение функции
int func() return 0;
>
L-значения и R-значения
В языке C есть два вида выражений:
- L-значения. Выражения, которые ссылаются на область памяти, называются выражениями l-значения. L-значение может появляться как в левой, так и в правой части присваивания.
- R-значения. Термин r-значение относится к значению данных, которое хранится по некоторому адресу в памяти. R-значение — это выражение, которому не может быть присвоено значение, что означает, что r-значение может появляться только в правой части присваивания.
Переменные — это l-значения, поэтому они могут появляться в левой части присваивания. Числовые литералы являются r-значениями, поэтому их нельзя присвоить и они не могут появляться в левой части. Посмотрите на следующие допустимые и недопустимые операторы:
int g = 20; // допустимый оператор10 = 20; // недопустимый оператор, который приведет к ошибке во время компиляции
- Обучение программированию лучше начать с языка С. И вот почему
- 7 моих любимых расширений VS Code
- Курс на продуктивность: 10 бесплатных инструментов и сайтов для разработчиков
Чем характеризуются переменные
Для хранения данных в программе в Kotlin, как и в других языках программирования, применяются переменные. Переменная представляет именованный участок памяти, который хранит некоторое значение.
Каждая переменная характеризуется определенным именем, типом данных и значением. Имя переменной представляет поизвольный идентификатор, который может содержать алфавитно-цифровые символы или символ подчеркивания и должен начинаться либо с алфавитного символа, либо со знака подчеркивания. Для определения переменной можно использовать либо ключевое слово val , либо ключевое слово var .
Формальное определение переменной:
val|var имя_переменной: тип_переменной
Вначале идет слово val или var, затем имя переменной и через двоеточие тип переменной.
Например, определим переменную age:
val age: Int
То есть в данном случае объявлена переменная age, которая имеет тип Int . Тип Int говорит о том, что переменная будет содержать целочисленные значения.
После определения переменной ей можно присвоить значение:
fun main()
Для присвоения значения переменной используется знак равно. Затем мы можем производить с переменной различные операции. Например, в данном случае с помощью функции println() значение переменной выводится на консоль. И при запуске этой программы на консоль будет выведено число 23.
Присвоение значения переменной должно производиться только после ее объявления. И также мы можем сразу присвоить переменной начальное значение при ее объявлении. Такой прием называется инициализацией:
fun main()
Однако обязательно надо присвоить переменной некоторое значение до ее использования:
fun main() < val age: Int println(age)// Ошибка, переменная не инициализирована >
Изменяемые и неизменяемые переменные
Выше было сказано, что переменные могут объявляться как с помощью слова val , так и с помощью слова var . В чем же разница между двумя этими способами?
С помощью ключевого слова val определяется неизменяемая переменная (immutable variable). То есть мы можем присвоить значение такой переменной только один раз, но изменить его после первого присвоения мы уже не сможем. Например, в следующем случае мы получим ошибку:
fun main() < val age: Int age = 23 // здесь норм - первое присвоение age = 56 // здесь ошибка - переопределить значение переменной нельзя println(age) >
А у переменной, которая определена с помощью ключевого слова var мы можем многократно менять значения (mutable variable):
fun main()
Поэтому если не планируется изменять значение переменной в программе, то лучше определять ее с ключевым словом val .
Определение констант
Также Kotlin поддерживает константы времени компиляции. Для их определения применяются ключевые слова const val :
const val maxAge = 120 // константа fun main()
В данном случае maxAge является константой.
Отличительной особенностью констант является то, что они на стадии компиляции должны иметь некоторое значение, и это значение изменить нельзя. Это накладывает на использование констант ряд ограничений:
-
Естественно нельзя изменить значение константы:
const val maxAge = 120 // константа fun main() < maxAge = 1500 // ошибка println(maxAge) >
fun main() < const val maxAge = 120 // ошибка println(maxAge) >
Также стоит отметит отличие val -переменных от констант ( const val ): значение val -переменных устанавливается во время выполнения, а значение констант — во время компиляции. Значение val -переменной также нельзя изменить после установки, однако мы можем объявить val -переменную, а потом дальше в программе присвоить ей значение. Константе же необходимо присвоить значение сразу при определении.
Переменные
Теги: Си переменные. char, int, unsigned, long, long long, float, double, long double, long float, lexical scoping. Объявление переменных. Область видимости. Инициализация переменных. Имена переменных. Экспоненциальная форма.
Переменные
Например, правильные идентификаторы
a, _, _1_, Sarkasm, a_long_variable, aLongVariable, var19, defaultX, char_type
неверные
1a, $value, a-long-value, short
Си — регистрозависимый язык. Переменные с именами a и A, или end и END, или perfectDark и PerfectDarK – это различные переменные.
Типы переменных
- 1) Размер переменной в байтах (сколько байт памяти выделит компьютер для хранения значения)
- 2) Представление переменной в памяти (как в двоичном виде будут расположены биты в выделенной области памяти).
Целые
- char — размер 1 байт. Всегда! Это нужно запомнить.
- short — размер 2 байта
- int — размер 4 байта
- long — размер 4 байта
- long long — размер 8 байт.
Указанные выше значения характерны для компилятора VC2012 на 32-разрядной машине. Так что, если ваша программа зависит от размера переменной, не поленитесь узнать её размер.
Теперь давайте определим максимальное и минимальное число, которое может хранить переменная каждого из типов. Числа могут быть как положительными, так и отрицательными. Отрицательные числа используют один бит для хранения знака. Иногда знак необходим (например, храним счёт в банке, температуру, координату и т.д.), а иногда в нём нет необходимости (вес, размер массива, возраст человека и т.д.). Для этого в си используется модификатор типа signed и unsigned. unsigned char — все 8 бит под число, итого имеем набор чисел от 00000000 до 11111111 в двоичном виде, то есть от 0 до 255 signed char от -128 до 128. В си переменные по умолчанию со знаком. Поэтому запись char и signed char эквивалентны.
Тип | Размер, байт | Минимальное значение | Максимальное значение |
---|---|---|---|
unsigned char | 1 | 0 | 255 |
signed char ( char ) |
1 | -128 | 127 |
unsigned short | 2 | 0 | 65535 |
signed short ( short ) |
2 | -32768 | 32767 |
unsigned int ( unsigned ) |
4 | 0 | 4294967296 |
signed int ( int ) |
4 | -2147483648 | 2147483647 |
unsigned long | 4 | 0 | 4294967296 |
signed long ( long ) |
4 | -2147483648 | 2147483647 |
unsigned long long | 8 | 0 | 18446744073709551615 |
signed long long ( long long ) |
8 | -9223372036854775808 | 9223372036854775807 |
sizeof
В си есть оператор, который позволяет получить размер переменной в байтах. sizeof переменная, или sizeof(переменная) или sizeof(тип). Это именно оператор, потому что функция не имеет возможности получить информацию о размере типов во время выполнения приложения. Напишем небольшую программу чтобы удостовериться в размерах переменных.
#include #include int main() < char c; short s; int i; long l; long long L; //Вызов sizeof как "функции" printf("sizeof(char) = %d\n", sizeof(c)); printf("sizeof(short) = %d\n", sizeof(s)); printf("sizeof(int) = %d\n", sizeof(i)); printf("sizeof(long) = %d\n", sizeof(l)); printf("sizeof(long long) = %d\n", sizeof(L)); //Вызов как оператора printf("sizeof(char) = %d\n", sizeof c); printf("sizeof(short) = %d\n", sizeof s); printf("sizeof(int) = %d\n", sizeof i); printf("sizeof(long) = %d\n", sizeof l); printf("sizeof(long long) = %d\n", sizeof L); _getch(); >
(Я думаю ясно, что переменные могут иметь любое валидное имя). Эту программу можно было написать и проще
#include #include int main() < printf("sizeof(char) = %d\n", sizeof(char)); printf("sizeof(short) = %d\n", sizeof(short)); printf("sizeof(int) = %d\n", sizeof(int)); printf("sizeof(long) = %d\n", sizeof(long)); printf("sizeof(long long) = %d\n", sizeof(long long)); //нельзя произвести вызов sizeof как оператора для имени типа //sizeof int - ошибка компиляции _getch(); >
В си один и тот же тип может иметь несколько названий
short === short int
long === long int
long long === long long int
unsigned int === unsigned
Типы с плавающей точкой
- float — 4 байта,
- long float — 8 байт
- double — 8 байт
- long double — 8 байт.
Переполнение переменных
Си не следит за переполнением переменных. Это значит, что постоянно увеличивая значение, скажем, переменной типа int в конце концов мы «сбросим значение»
#include #include void main() < unsigned a = 4294967295; int b = 2147483647; //Переполнение беззнакового типа printf("%u\n", a); a += 1; printf("%u", a); //Переполнение знакового типа printf("%d\n", b); b += 1; printf("%d", b); getch(); >
Вообще, поведение при переполнении переменной определено только для типа unsigned: Беззнаковое целое сбросит значение. Для остальных типов может произойти что угодно, и если вам необходимо следить за переполнением, делайте это вручную, проверяя аргументы, либо используйте иные способы, зависящие от компилятора и архитектуры процессора.
Постфиксное обозначение типа
- 11 — число типа int
- 10u — unsigned
- 22l или 22L — long
- 3890ll или 3890LL — long long (а также lL или Ll)
- 80.0f или 80.f или 80.0F — float (обязательно наличие десятичной точки в записи)
- 3.0 — число типа double
#include #include int main()
Следующий код, однако, не будет приводить к ошибкам, потому что происходит неявное преобразование типа
int a = 10u; double g = 3.f;
Шестнадцатеричный и восьмеричный формат
В о время работы с числами можно использовать шестнадцатеричный и восьмеричный формат представления. Числа в шестнадцатиричной системе счисления начинаются с 0x, в восьмеричной системе с нуля. Соответственно, если число начинается с нуля, то в нём не должно быть цифр выше 7:
#include #include void main()
Экспоненциальная форма представления чисел
Э кспоненциальной формой представления числа называют представление числа в виде M e ± p , где M — мантиса числа, p — степень десяти. При этом у мантисы должен быть один ненулевой знак перед десятичной запятой.
Например 1.25 === 1.25e0, 123.5 === 1.235e2, 0.0002341 === 2.341e-4 и т.д.
Представления 3.2435e7 эквивалентно 3.2435e+7
Существеут и другое представление («инженерное»), в котором степень должна быть кратной тройке. Например 1.25 === 1.25e0, 123.5 === 123.5e0, 0.0002341 === 234.1e-6, 0.25873256 === 258.73256e-3 и т.д.
Объявление переменных
В си переменные объявляются всегда в начале блока (блок — участок кода ,ограниченный фигурными скобками)
При объявлении переменной пишется её тип и имя.
int a; double parameter;
Можно объявить несколько переменных одного типа, разделив имена запятой
long long arg1, arg2, arg3;
#include #include int main() < int a = 10; int b; while (a>0) < int z = a*a; b += z; >>
Здесь объявлены переменные a и b внутри функции main, и переменная z внутри тела цикла. Следующий код вызовет ошибку компиляции
int main()
Это связано с тем, что объявление переменной стоит после оператора присваивания. При объявлении переменных можно их сразу инициализировать.
int i = 0;
При этом инициализация при объявлении переменной не считается за отдельный оператор, поэтому следующий код будет работать
int main()
Начальное значение переменной
О чень важно запомнить, что переменные в си не инициализируются по умолчанию нулями, как во многих других языках программирования. После объявления переменной в ней хранится «мусор» — случайное значение, которое осталось в той области памяти, которая была выделена под переменную. Это связано, в первую очередь, с оптимизацией работы программы: если нет необходимости в инициализации, то незачем тратить ресурсы для записи нулей (замечание: глобальные переменные инициализируются нулями, почему так, читайте в этой статье).
#include #include int main()
Если выполнять эту программу на VC, то во время выполнения вылетит предупреждение
Run-Time Check Failure #3 — The variable ‘i’ is being used without being initialized.
Если нажать «Продолжить», то программа выведет «мусор». В многих других компиляторах при выполнении программы не будет предупреждения.
Область видимости переменной
П еременные бывают локальными (объявленными внутри какой-нибудь функции) и глобальными. Глобальная переменная видна всем функциям, объявленным в данном файле. Локальная переменная ограничена своей областью видимости. Когда я говорю, что переменная «видна в каком-то месте», это означает, что в этом месте она определена и её можно использовать. Например, рассмотрим программу, в которой есть глобальная переменная
#include #include int global = 100; void foo() < printf("foo: %d\n", global); >void bar(int global) < printf("bar: %d\n", global); >int main()
Будет выведено
foo: 100
bar: 333
Здесь глобальная переменная global видна всем функциям. Но аргумент функции затирает глобальную переменную, поэтому при передаче аргумента 333 выводится локальное значение 333.
Вот другой пример
#include #include int global = 100; int main()
Программа выведет 555. Также, как и в прошлом случае, локальная переменная «важнее». Переменная, объявленная в некоторой области видимости не видна вне её, например
#include #include int global = 100; int main() < int x = 10; < int y = 30; printf("%d", x); >printf("%d", y); >
Этот пример не скомпилируется, потому что переменная y существует только внутри своего блока.
Вот ещё пример, когда переменные, объявленные внутри блока перекрывают друг друга
#include #include int global = 100; int main() < int x = 10; < int x = 20; < int x = 30; printf("%d\n", x); >printf("%d\n", x); > printf("%d\n", x); getch(); >
Программа выведет
30
20
10
Глобальных переменных необходимо избегать. Очень часто можно услышать такое. Давайте попытаемся разобраться, почему. В ваших простых проектах глобальные переменные выглядят вполне нормально. Но представьте, что у вас приложение, которое
- 1) Разрабатывается несколькими людьми и состоит из сотен тысяч строк кода
- 2) Работает в несколько потоков
Во-первых, глобальная переменная, если она видна всем, может быть изменена любой частью программы. Вы изменили глобальную переменную, хотите её записать, а другая часть программы уже перезаписала в неё другое значение (на самом деле это целый класс проблем, которые возникают в многопоточной среде). Во-вторых, при больших размерах проекта не уследить, кто и когда насоздавал глобальных переменных. В приведённых выше примерах видно, как переменные могут перекрывать друг друга, то же произойдёт и в крупном проекте.
Безусловно, есть ситуации, когда глобальные переменные упрощают программу, но такие ситуации случаются не часто и не в ваших домашних заданиях, так что НЕ СОЗДАВАЙТЕ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ!
Переменные могут быть не только целочисленными и с плавающей точкой. Существует множество других типов, которые мы будем изучать в дальнейшем.
ru-Cyrl 18- tutorial Sypachev S.S. 1989-04-14 sypachev_s_s@mail.ru Stepan Sypachev students
Всё ещё не понятно? – пиши вопросы на ящик