§ 8.3. Типы данных. Литералы. Переменные

Школьный курс python
Содержание

Типы данных

Любая программа работает с данными. На предыдущем уроке, для решения задач, мы использовали переменные двух типов данных – это целое (int) и действительное число (double). Мы выяснили по каким причинам используются разные типы. Давайте обобщим. Поскольку двоичное представление различных данных в памяти компьютера отличается, то, соответственно, будут отличаться и механизмы работы с данными разных типов. Таким образом, тип определяет организацию памяти для хранения данных. Но не только это. Для каждого типа определены соответствующие операции и функции применимые только к данному типу (тем не менее, существуют и общие операции, которые можно применять для разных типов, но внутренняя реализация операций с разными типами, естественно, будет отличаться). Итак, тип данных определяет как организована эта информация в памяти компьютера и какие операции можно производить с этим типом данных. Язык C++ является типизированным языком программирования. Это означает, что тип данных должен быть описан прежде использования программного объекта, такого как переменная, функция, массив, структура или класс (это отличает C++ от языка python и других языков, в которых реализована динамическая типизация). C++, помимо фундаментальных типов, содержит составные типы и поддерживает пользовательские типы. Стандартная библиотека (STD) определяет дополнительные фундаментальные типы такие, как size_t и byte, а также большое количество абстрактных типов, например string, vector, с которыми мы познакомися позднее. К фундаментальным типам относятся:

  • Целые типы (short, int, long long и др.)
  • Действительные типы (float, double и long double)
  • Логический тип (bool)
  • Символьный тип (char)
  • Специальный тип void
Целые, действительные, логический и символьные типы относятся к арифметическому типу. Тип void используется с функциями и указывает, что функция (процедура) не возвращает какого-либо значения. void является базовым типом для указателей, а также используется в приведении типов.

Литералы

Литералы, иначе константы – это неизменяемые величины. Примеры различных констант:

Целые

0, -1, 10000
По умолчанию целочисленные лексемы имеют тип int.
Представление целых литералов в различных системах счисления:
Двоичной: 0b1010, 0B111100111
Восьмеричной: 01, 020, 07155
Шестнадцатеричной: 0xA, 0x1B8, 0X00FF

Действительные

С фиксированной точкой: 5.7, .001, -35., 0.0
С плавающей точкой (экспоненциальный): -0.2E6, .11e-3, 5E10, 2.e-10
По умолчанию они имеют тип double.
Целые и действительные литералы могут использовать разделитель групп разрядов, принятый для упрощения чтения больших чисел (или чисел с длинной дробной частью): 100'000'001'111'100ull, 0.123'456'789, 0b0100’1100’0110

Символьные

Один или два символа заключенные в апострофы: 'S', 'щ', '\t', '\012', '\x07\x07', 'db'

Примечание: к символьным константам относятся специальные управляющие символы (escape-последовательности).
Escape-последовательности

Escape-последовательности (или управляющие последовательности) используются для описания определённых специальных символов внутри строковых литералов, то есть внутри ограничителей "". Полный список приведен в методичке (Таб. 12). Вот некоторые из них:
\n – новая строка
\t – горизонтальная табуляция
\v – вертикальная табуляция
\0 – нулевой символ
Например:

"Ветер на море гуляет\nИ кораблик подгоняет;\nОн бежит себе в волнах\nНа раздутых парусах."
Строковые

Последовательность символов, заключенные в кавычки:
"Hello world!", "Здесь был Вася :-))"

Примечание: к строковому литералу автоматически добавляется признак конца строки ('\0').
Прочие

Булевские (логические): false, true
и другие, с которыми мы познакомимся позднее.
В заключение добавим, что целые, действительные и строковые литералы используют специальные суффиксы, приказывающие компилятору изменить представление типов данных (используемых по умолчанию), примеры использования суффиксов мы покажем во время более близкого знакомства с типами данных.

Переменные

Адресуемость памяти

Программы вместе с данными, к которым они имеют доступ, находятся в оперативной памяти. Оперативная память состоит из двоичных запоминающих элементов – битов. Соседние биты объединены в группы (ячейки), которые называются байтами. Хотя название ячеек и совпадает с единицами измерения информации – байт (т. е. 8 бит), реально имеют размер от 8 до 64 бит, в зависимости от архитектуры. Все байты пронумерованы, начиная с нуля, т. е. имеют адреса. Номер ячейки памяти называется адресом.
От разработчика скрыта информация какие адреса памяти будут использоваться для хранения данных во время выполнения программы (с каждым запуском программы адреса будут различаться). Известно, что эти адреса будут располагаться близко друг к другу. ОС резервирует для выполнения программы определенное адресное пространство.

Переменные

Для записи данных в память и извлечения их из памяти используются переменные. Переменные — это именованная область памяти, к которой можно обращаться из программы по имени. С каждой переменной связан адрес памяти (адрес первого байта с наименьшим значением). Адрес памяти можно получить с помощью операции &. Но важен не сам адрес, а какой тип данных будет связан с именем переменной.

Программа 8.3.2
#include <iostream>
using namespace std;

int main() {
	int x, y, z;
	cout << "Адреса переменных в памяти:"
		 << "\nx -> " << &x
		 << "\ny -> " << &y
		 << "\nz -> " << &z
		 << endl;
	return 0;
}

Вывод программы в окне Konsole

Выводимый адрес представлен в виде шестнадцатеричного числа. Обратите внимание, что шаг приращения равен 4. Поскольку размер типа int 4 байта, следовательно, переменные программы находятся в соседних ячейках.

Определение переменных

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

Тип int является стандартным типом для целых переменных, так как имеет размер равный машинному слову (4 байта, вне зависимости от архитектуры). Если для целых данных нет веских причин для использования какого-либо иного целого типа, то необходимо использовать именно этот тип.

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

int a, b, c, other;

Определение переменной может сопровождаться инициализацией (т. е. указанием начального значения):

int a = 10;
int b = a;
int c = 0, d, e, other = 1000;

Следует различать определение и объявление (declaration). Объявления вводят имена в программу (или повторно вводят). По существу, определения – это тоже объявления. Если для работы с объектом достаточно его определения в данном месте программы, то ограничиваются определением. Если переменная определяется вне тела главной функции, то говорят, что она объявлена. При объявлении переменная будет иметь значение по умолчанию (например, для целочисленных типов – это значение "0"). Последняя версия компилятора GCC устанавливает значение по умолчанию и для объектов без инициализации определяемых внутри функции main, но, при попытке обращения к такому объекту, будет выдано предупреждение.

Программа 8.3.2
#include <iostream>
using namespace std;
int A;

int main() {
	int a;
	cout << A << endl;
	cout << a << endl; // Нельзя!
	return 0;
}

Компилятор выдаст предупреждение:

../src/test.cpp: В функции «int main()»:
../src/test.cpp:16:10: предупреждение: «a» используется без инициализации в данной функции [-Wuninitialized]
  cout << a << endl;
          ^
Хотя, формально, предупреждение и не является ошибкой, но это, потенциально, может привести к ошибке в программе, поэтому такие ситуации нужно избегать.
Другие способы инициализации переменных

Выше мы показали как можно инициализировать переменную с помощью операции =. Но это не единственная возможность. В стандарте C++11 появилась списочная инициализация с помощью фигурных скобок. Этот способ имеет преимущества, так как контролирует потерю точности при инициализации. К тому же, он позволяет инициализировать переменную значением по умолчанию (первая строка в примере ниже), а это, в свою очередь, может предупредить использование неинициализированного объекта.

int a {};
int b = {10};
int c(0);
Спецификатор auto

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

auto c = (5 * 300000000ll - 27u) / 2, a = 100u / 10ll;
Чтобы узнать какого типа получился объект c после выполнения этой инструкции можно воспользоваться функцией typeid(c).name() (заголовочный файл typeinfo). Если вывести значение, которое возвращает данная функция, то мы получим "x", что соответствует типу long long. Впрочем, определить здесь тип было не сложно. Так как тип long long шире, чем unsigned, то итоговым типом будет первый. О преобразовании типов мы будем говорить позднее.

Применять auto для описания переменных, тип которых и так очевиден - не имеет смысла, но может сделать код более лаконичным и изящным:

auto r = 1000000ull;
// вместо
// unsigned long long r = 1000000;

Действительно полезное значение auto приобретает при работе с составными типами.

Если вместо типа указано auto, то список инициализации, без использования операции "=", создавать нельзя:

auto x1 = {3};   // std::initializer_list
auto x2 {1, 2};  // ошибка
auto x3 {3};     // переменная типа int

Инициализатором переменной может быть выражение любой сложности. Например, вот такая инструкция с функцией и константой библиотеки cmath:

double a = (2 * pi * sqrt(b) - 4) / (c * 2 - x);
Идентификаторы (имена объектов программы)

Идентификатор - это имя программного объекта: переменной, константы, массива, функции, класса и т. п. В идентификаторах могут использоваться латинские буквы, цифры и знак нижнего подчеркивания ( _ ). В C++ различаются строчные и прописные буквы (т. е. имена регистро-зависимы), так: Name, name и NAME - это разные идентификаторы. Правила использования идентификаторов:

  1. можно использовать латинские символы: A..Z, a..z;
  2. можно использовать арабские цифры: 0..9 и символ нижнего подчеркивания, но не в начале;
  3. пробелы в имени не допускаются;
  4. не рекомендуется начинать с нижнего подчеркивания или с двух нижних подчеркиваний и заглавной буквы, например: _S (такие идентификаторы имеют специальное назначение);
  5. двойное подчеркивание используется только для служебных целей to__boo
  6. не допускается использования ключевых слов;
  7. необходимо воздерживаться от использования ключевых слов, как части имени, например: for_and_if (за исключением наименования типов)

При составлении имен желательно придерживаться какого-либо стиля, например, стиля CamelCase: имена пишутся слитно, каждое слово, описывающее назначение идентификатора, пишется с заглавной буквы. Этот стиль используется в двух вариантах: UpperCamelCase и lowerCamelCase. Первый используется для именования классов, второй для прочего: переменных, методов и т.п.

Ключевые слова

Ключевые слова - это лексемы специального назначения. Они зарезервированы, использовать их в качестве идентификаторов (имен объектов программы) запрещено. Список ключевых слов см. в методичке (Таблица 3).

Приложение

Примеры решения задач
Вопросы
Темы сообщений
Задания А
Задания Б
Задания С
Ссылки
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 5,00 из 5)
Загрузка...

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.


Обсуждение закрыто.