Для чего нужен тип переменной
Перейти к содержимому

Для чего нужен тип переменной

Переменные C# | Типы и виды переменных

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

Что такое переменная?

Определение переменной звучит примерно следующим образом:

Переменная – это именованная область памяти.

Но что это означает для нас. Давайте разбираться на примере.

Я думаю, что каждый из вас уже знаком с понятием переменной в алгебре. Это тот самый X, который приходиться искать в уравнении. В программировании переменная имеет схожие функции. Это своеобразный псевдоним, что-то неопределенное, неизвестное, под которым может скрываться кто угодно

Представь себе коробочку. На этой коробочке написано «Подарок» и это делает эту коробочку уникальной. Ты всегда сможешь найти именно эту коробку по этому имени (при условии, что не может существовать ни одной другой коробочки с таким именем).

А вот положить в эту коробочку ты можешь все что угодно. Это может быть и новенький IPhone, и миленький котеночек, и что-нибудь куда менее приятное (как в фильме «Семь»). Кстати, если не смотрел этот фильм, очень рекомендую, но только если у тебя крепкая психика и тебе больше 18 лет.

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

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

Типизация переменных

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

Это позволяет дополнительно защититься от ошибок, потому что ты будешь заранее знать, что будет в коробочке, и будешь готов к тому, как тебе нужно будет себя вести с содержимым.

Языки программирования условно можно разделить на два больших типа:

Сильнотипизированные – те, где вся ответственность за указание типа переменных ложится на программиста

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

Язык C# относится к первым. Возможно, это лишает его такой гибкости как тот же самый JavaScript (который относится ко вторым), но при этом дает большую защищенность от ошибок.

Виды переменных в языке C#

Перед тем, как мы приступим к знакомству с основными типами данных в языке C# необходимо узнать изучить еще один вопрос – виды переменных. На самом деле их всего два:

Ссылочные – хранятся в куче (сложные типы и классы)

Значимые – хранятся в стеке (базовые примитивные типы)

Мы не будем подробно останавливаться на этой теме, но общая идея следующая:

Условно в компьютере существует два вида памяти для работы приложения:

Стек (Stack) – быстрая память, но сильно ограниченная по размеру

Куча (Heap) – память, ограниченная только размером оперативки, но при этом значительно более медленная, чем стек.

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

Типы переменных в языке C#

Начнем со знакомства с наиболее часто используемыми типами данных (большинство их них значимые):

Имя Класс Описание Пример
int Int32 Целое число со знаком -2147483648, -1, 0, 1, 2147483647
double Double Число с плавающей запятой -12.34, -1.1, 0, 1, 53.6123123
char Char Символ ‘a’, ‘b’, ‘1’, ‘+’, ‘\t’, ‘_’
bool Boolean Логическое значение true, false
decimal Decimal Число с фиксированной запятой -123.2M, -1, 0, 1.10M
string String Строка (ссылочный тип) “hello”, “a”, “11”, “+++”, “”
object Object Базовый класс (ссылочный тип) Вообще все в C#

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

Надеюсь, ты заметил, что для типов float и decimal при дробном числе добавляется специальная литера (F и M соответственно). Это связано с тем, что по умолчанию в C# дробные числа хранятся в типе double, а это необходимо для того, чтобы компилятор правильно воспринимал эти числа. Для целых значений это не обязательно.

Объявление переменной в языке C#

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

Где int – тип, i – имя переменной, = — символ присваивания значения, 42 – значение, ; — символ окончания команды.

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

Аналогичным образом происходит объявление переменных и других типов.

Переменные типа var в языке C#

Тип var по своей сути является просто синтаксическим сахаром. Он позволяет не дублировать указание типа в объявлении переменных, получая данные о типе из контекста. Проще всего это понять на примере.

В данном случае компилятор и так может однозначно понять, что тип переменной должен быть целым числом, так как справа от = стоит целое число. Чтобы сэкономить силы программиста можно использовать тип var, который будет автоматически определять тип переменной из контекста, при этом она все также будет оставаться сильнотипизированой. То есть, если ты сначала объявишь переменную как целое число, а потом попробуешь добавить к ней строку, то получишь синтаксическую ошибку.

Переменные типа dynamic в C#

Я настоятельно рекомендую избегать использование данного типа на практике. Он делает переменные действительно не типизированными, снимая с компилятора вообще всю ответственность. Его внедрение связано с тем, что платформа .NET поддерживает множество языков, в том числе слаботипизированные, и для обеспечения совместимости и был создан этот тип.

В данном случае, компилятор на этапе написания не будет вообще контролировать типы, но естественно на этапе выполнения приложения вы получите сообщение об ошибке.

Я еще раз настоятельно рекомендую трижды подумать, перед тем как использовать этот тип, потом посоветоваться с опытными коллегами, а потом еще раз подумать, и только если не остается никакого другого варианта использовать этот тип.

Задание по теме переменные

Необходимо поэкспериментировать и объявить переменные всех типов данных. Вывести их на консоль. Изучить методы и свойства доступные для каждой переменной в помощнике intellisense.

Подписывайтесь на мой YouTube-канал, чтобы не пропускать живые уроки по программированию на языке C#, а также вступайте в мою группу Вконтакте и Telegram-канал. Там много обучающих материалов по всем языкам, а также отличный IT-юмор. А также рекомендую прочитать статью Монитор для программиста: как выбрать?

Типы данных, переменные

Переменная – это ячейка в оперативной памяти микроконтроллера, которая имеет своё уникальное название (а также адрес в памяти) и хранит значение соответственно своему размеру. К переменной мы можем обратиться по её имени или адресу и получить это значение, либо изменить его. Зачем это нужно? В переменной могут храниться п ромежуточные результаты вычислений, полученные “снаружи” данные (с датчиков, Интернета, интерфейсов связи) и так далее.

Измерение информации

Прежде чем перейти к переменным и их типам, нужно вспомнить школьный курс информатики, а именно – как хранятся данные в “цифровом” мире. Любая память состоит из элементарных ячеек, которые имеют всего два состояния: 0 и 1. Эта единица информации называется бит (bit). Минимальным блоком памяти, к которому можно обратиться из программы по имени или адресу, является байт (byte), который в Arduino (и в большинстве других платформ и процессоров) состоит из 8 бит, таким образом любой тип данных будет кратен 1 байту.

Максимальное количество значений, которое можно записать в один байт, составляет 2^8 = 256. В программировании счёт всегда начинается с нуля, поэтому один байт может хранить число от 0 до 255. Более подробно о двоичном представлении информации и битовых операциях мы поговорим в отдельном уроке.

Стандартные типы переменных в Arduino по своему размеру кратны степени двойки, давайте их распишем:

  • 1 байт = 8 бит = 256
  • 2 байта = 16 бит = 65 536
  • 4 байта = 32 бита = 4 294 967 296

Типы данных

Переменные разных типов имеют разные особенности и позволяют хранить числа в разных диапазонах.

  • (*) – да, bool занимает 1 байт (8 бит), так как это минимальная адресуемая ячейка памяти. Есть способы запаковать логические переменные в 1 бит, о них поговорим в другом уроке.
  • (**) – на esp8266 int и unsigned int имеет вес 4 байта, то есть является аналогом типа long !
  • (***) – не встречал упоминания в официальных источниках, но Arduino также поддерживает 64 битные числа. Arduino-библиотеки с переменными этого типа не работают, поэтому можно использовать только в своём коде.

Целочисленные типы

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

  • Проще ориентироваться в максимальных значениях
  • Легче запомнить
  • Название более короткое
  • Проще изменить один тип на другой
  • Размер переменной задан жёстко и не зависит от платформы (например int на AVR это 2 байта, а на esp8266 – 4 байта)

Максимальные значения хранятся в константах, которые можно использовать в коде. Иногда это помогает избавиться от лишних вычислений:

  • UINT8_MAX – 255
  • INT8_MAX – 127
  • UINT16_MAX – 65 535
  • INT16_MAX – 32 767
  • UINT32_MAX – 4 294 967 295
  • INT32_MAX – 2 147 483 647
  • UINT64_MAX – 18 446 744 073 709 551 615
  • INT64_MAX – ‭9 223 372 036 854 775 807

Логический тип

bool – логический, он же булевый (придуман Джорджем Булем) тип данных, принимает значения 0 и 1 или false и true – ложь и правда. Используется для хранения состояний, например включено/выключено, а также для работы в условных конструкциях.

Также переменная типа bool принимает значение true , если присвоить ей любое отличное от нуля число.

Символьный тип

char – тип данных для хранения символов, символ указывается в одинарных кавычках: char var = ‘a’; . По факту это целочисленный тип данных, а переменная хранит номер (код) символа в таблице ASCII:

blank

Отдельный символьный тип данных нужен для удобства работы, чтобы программа могла понять разницу между числом и символом, например для вывода на дисплей (чтобы вывести именно букву A, а не число 65). Из символов можно составлять строки, об этом более подробно поговорим в уроках про символьные строки и String-строки.

Дробные числа

float (англ. float – плавающий) – тип данных для чисел с плавающей точкой, т.е. десятичных дробей. Arduino поддерживает три типа ввода чисел с плавающей точкой:

Тип записи Пример Чему равно
Десятичная дробь 20.5 20.5
Научный 2.34E5 2.34*10^5 или 234000
Инженерный 67e-12 67*10^-12 или 0.000000000067

Особенности float чисел и работу с ними мы рассмотрим в уроках про математические операции и условия.

Объявление и инициализация

  • Объявление переменной – резервирование ячейки памяти указанного типа на имя: тип_данных имя;
  • Присваивание – задание переменной значения при помощи оператора = (равно): имя = значение;
  • Инициализация переменной – объявление и присваивание начального значения: тип_данных имя = значение;

Можно объявить и инициализировать несколько переменных через запятую:

  • Переменная должна быть объявлена до использования, буквально выше по коду. Иначе вы получите ошибку Not declared in this scope – переменная не объявлена.
  • Нельзя объявить две и более переменных с одинаковым именем в одной области определения.

Константы

Что такое константа понятно из её названия – что-то, значение чего мы можем только прочитать и не можем изменить: при попытке изменить получим ошибку компиляции. Задать константу можно двумя способами:

Как переменную, указав перед типом данных слово const: const тип_данных имя = значение; . Пример: const byte myConst = 10; . Фактически это будет обычная переменная, но её значение нельзя поменять. Особенности:

  • Занимает место в оперативной памяти МК.
  • Имеет адрес в памяти, по которому к ней можно обратиться.
  • Вычисления с ней не оптимизируются и чаще всего выполняются точно так же, как с обычными переменными.
  • Компилятор выдаст ошибку, если имя константы совпадает с именем другой переменной в программе.

При помощи директивы #define, без знака равенства и точки с запятой в конце: #define имя значение . Пример: #define BTN_PIN 10 . Работает так: указанное имя буквально заменяется в тексте программы на указанное значение. Такая дефайн-константа:

  • Не занимает места в оперативной памяти, а хранится во Flash памяти как часть кода программы.
  • Не имеет адреса в оперативной памяти.
  • Вычисления с такими константами оптимизируются и выполняются быстрее, так как это просто цифры.
  • Если имя дефайн-константы совпадёт с именем другого “объекта” в программе или даже в библиотеке – работа может быть непредсказуемой: можно получить невнятную ошибку компиляции, либо программа может просто работать некорректно! Дефайн буквально заменяет текст в коде программы, это довольно опасная штука.

Область видимости

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

Глобальная

  • Объявляется вне функций, например просто в начале программы.
  • Доступна для чтения и записи в любом месте программы.
  • Находится в оперативной памяти на всём протяжении работы программы, то есть не теряет своё значение.
  • При объявлении имеет нулевое значение.

Локальная

  • Объявляется внутри любого блока кода, заключённого в < фигурные скобки >.
  • Доступна для чтения и записи только внутри своего блока кода (и во всех вложенных в него).
  • Находится в оперативной памяти с момента объявления и до закрывающей фигурной скобки, то есть удаляется из памяти и её значение стирается.
  • При объявлении имеет случайное значение.

Важный момент: если имя локальной переменной совпадает с одной из глобальных, то приоритет обращения отдаётся локальной переменной (в её области определения).

Статические переменные

Вспомним, как работает обычная локальная переменная: при входе в свой блок кода локальная переменная создаётся заново, а при выходе – удаляется из памяти и теряет своё значение. Если локальная переменная объявлена как static – она будет сохранять своё значение на всём протяжении работы программы, но область видимости останется локальной: взаимодействовать с переменной можно будет только внутри блока кода, где она создана (и во всех вложенных в него).

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

Преобразование типов

Иногда требуется преобразовать один тип данных в другой: например, функция принимает int , а вы хотите передать ей byte . В большинстве случаев компилятор сам разберётся и преобразует byte в int , но иногда вылетает ошибка в стиле “попытка передать byte туда, где ждут int“. В таком случае можно преобразовать тип данных, для этого достаточно указать нужный тип данных в скобках перед преобразуемой переменной (тип_данных)переменная , иногда можно встретить запись тип_данных(переменная) . Результат вернёт переменную с новым типом данных, сам же тип данной у переменной не изменится. Например:

Система типов C++

Концепция типа очень важна в C++. Каждая переменная, аргумент функции и возвращаемое значение функции должны иметь тип, чтобы их можно было скомпилировать. Кроме того, перед вычислением каждого выражения (включая литеральные значения) компилятор неявно назначает ему тип. Некоторые примеры типов включают int хранение целых значений, double хранение значений с плавающей запятой (также называемых скалярными типами данных) или класс стандартной библиотеки std::basic_string для хранения текста. Вы можете создать собственный тип, определив или class struct . Тип определяет объем памяти, выделяемой для переменной (или результата выражения), типы значений, которые могут храниться в этой переменной, способ интерпретации значений (например, битовые шаблоны), и операции, допустимые с переменной. Эта статья содержит неформальный обзор основных особенностей системы типов C++.

Терминология

Переменная: символьное имя количества данных, чтобы его можно было использовать для доступа к данным, на которые он ссылается, во всей области кода, в котором он определен. В C++ переменная обычно используется для ссылки на экземпляры скалярных типов данных, тогда как экземпляры других типов обычно называются объектами.

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

Тип POD (обычные старые данные): эта неформальная категория типов данных в C++ относится к типам, которые являются скалярными (см. раздел «Основные типы») или являются классами POD. Класс POD не содержит статических данных-членов, которые не являются типами POD, а также не содержит пользовательских конструкторов, пользовательских деструкторов или пользовательских операторов присваивания. Кроме того, класс POD не имеет виртуальных функций, базового класса и ни закрытых, ни защищенных нестатических данных-членов. Типы POD часто используются для внешнего обмена данными, например с модулем, написанным на языке С (в котором имеются только типы POD).

Указание типов переменных и функций

C++ — это строго типизированный язык, который также является статически типизированным; каждый объект имеет тип и этот тип никогда не изменяется (не следует путать со статическими объектами данных). При объявлении переменной в коде необходимо явно указать его тип или использовать auto ключевое слово, чтобы указать компилятору выводить тип из инициализатора. При объявлении функции в коде необходимо указать тип каждого аргумента и его возвращаемое значение, или void если значение не возвращается функцией. Исключением является использование шаблонов функции, которые допускают аргументы произвольных типов.

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

При объявлении переменной типа POD настоятельно рекомендуется инициализировать ее, т. е. указать начальное значение. Пока переменная не инициализирована, она имеет «мусорное» значение, определяемое значениями битов, которые ранее были установлены в этом месте памяти. Необходимо учитывать эту особенность языка C++, особенно при переходе с другого языка, который обрабатывает инициализацию автоматически. При объявлении переменной типа, не являющегося классом POD, инициализация обрабатывается конструктором.

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

Базовые (встроенные) типы

В отличие от некоторых других языков, в C++ нет универсального базового типа, от которого наследуются все остальные типы. Язык включает множество фундаментальных типов, также известных как встроенные типы. Сюда входят числовые типы, такие как int , double , long bool , а также char типы и wchar_t типы для символов ASCII и ЮНИКОД соответственно. Большинство целочисленных фундаментальных типов (за исключением bool , double wchar_t и связанных типов) имеют unsigned версии, которые изменяют диапазон значений, которые может хранить переменная. Например, int 32-разрядное целое число со знаком может представлять значение от -2 147 483 648 до 2 147 483 647. Значение unsigned int , которое также хранится как 32-разрядные, может хранить значение от 0 до 4294 967 295. Общее количество возможных значений в каждом случае одинаково, отличается только диапазон.

Базовые типы распознаются компилятором, в котором предусмотрены встроенные правила, управляющие операциями, выполняемыми с такими типами, а также преобразованием в другие базовые типы. Полный список встроенных типов и их размеров и числовых ограничений см. в разделе «Встроенные типы».

На следующем рисунке показаны относительные размеры встроенных типов в реализации Microsoft C++:

Diagram of the relative size in bytes of several built in types.

В следующей таблице перечислены наиболее часто используемые фундаментальные типы и их размеры в реализации Microsoft C++:

Тип Размер Комментарий
int 4 байта Выбор по умолчанию для целочисленных значений.
double 8 байт Выбор по умолчанию для значений с плавающей запятой.
bool 1 байт Представляет значения, которые могут быть или true, или false.
char 1 байт Используйте для символов ASCII в старых строках в стиле C или в объектах std::string, которые никогда не будут преобразовываться в Юникод.
wchar_t 2 байта Представляет «расширенные» символы, которые могут быть представлены в формате Юникод (UTF-16 в Windows, в других операционных системах возможно другое представление). Это символьный тип, используемый в строках типа std::wstring .
unsigned char 1 байт В C++ нет встроенного типа байтов. Используется unsigned char для представления байтового значения.
unsigned int 4 байта Вариант по умолчанию для битовых флагов.
long long 8 байт Представляет очень большие целочисленные значения.

Другие реализации C++ могут использовать разные размеры для определенных числовых типов. Дополнительные сведения о размерах и связях размера, необходимых стандарту C++, см. в разделе «Встроенные типы».

Тип void

Тип void является особым типом. Переменная типа void не может объявляться, но можно объявить переменную типа void * (указатель на void ), что иногда необходимо при выделении необработанной (нетипизированной) памяти. Однако указатели не void являются типобезопасными и, как правило, их использование настоятельно не рекомендуется использовать в современном C++. В объявлении функции возвращаемое void значение означает, что функция не возвращает значение; это общее и допустимое использование void . Хотя язык C требует функций, имеющих нулевые параметры для объявления void в списке параметров, например, fou(void) эта практика не рекомендуется в современном C++ и должна быть объявлена fou() . Дополнительные сведения см. в разделе «Преобразования типов» и «Безопасность типов».

Квалификатор типа const

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

Квалификатор const широко используется в объявлениях функций и переменных, и «константная правильность» является важной концепцией в C++. По сути, это означает, const что во время компиляции значения не изменяются непреднамеренно. Дополнительные сведения см. в разделе const .

Тип const отличается от его версии, const int отличной от константной, например, является отдельным типом. int Оператор C++ const_cast можно использовать в тех редких случаях, когда необходимо удалить const-ness из переменной. Дополнительные сведения см. в разделе «Преобразования типов» и «Безопасность типов».

Строковые типы

Строго говоря, язык C++ не имеет встроенного строкового типа; char и wchar_t сохранение отдельных символов — необходимо объявить массив этих типов, чтобы приблизить строку, добавив завершающее значение NULL (например, ASCII ‘\0’ ) в элемент массива, который был последним допустимым символом (также называется строкой в стиле C). Строки в стиле C требовали написания гораздо большего объема кода или использования внешних библиотек служебных функций. Но в современном C++у нас есть типы std::string стандартной библиотеки (для 8-разрядных char строк символов типа) или std::wstring (для 16-разрядных wchar_t строк символов типа). Эти контейнеры стандартной библиотеки C++ можно рассматривать как собственные типы строк, так как они являются частью стандартных библиотек, включенных в любую соответствующую среду сборки C++. Просто используйте директиву #include <string> , чтобы эти типы были доступны в программе. (Если вы используете MFC или ATL, класс также доступен, CString но не входит в стандарт C++.) Использование массивов символов, завершающихся значением NULL (упомянутые ранее строки в стиле C), настоятельно не рекомендуется использовать в современном C++.

Определяемые пользователем типы

При определении class , struct union или enum , эта конструкция используется в остальной части кода, как если бы это был фундаментальный тип. Он имеет известный размер в памяти, и в его отношении действуют определенные правила проверки во время компиляции и во время выполнения в течение срока использования программы. Основные различия между базовыми встроенными типами и пользовательскими типами указаны ниже:

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

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

типы указателей

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

Первое, что необходимо знать, — это то, что при объявлении переменной необработанного указателя выделяется только память, необходимая для хранения адреса расположения памяти, на который будет ссылаться указатель при разыменовывании. Выделение памяти для самого значения данных (также называемого резервным хранилищем) еще не выделено. Другими словами, объявив переменную необработанного указателя, вы создаете переменную адреса памяти, а не фактическую переменную данных. Разыменовывание переменной указателя до проверки того, что она содержит действительный адрес в резервном хранилище, приведет к неопределенному поведению (обычно неустранимой ошибке) программы. В следующем примере демонстрируется подобная ошибка:

Пример разыменовывает тип указателя без выделения памяти для хранения фактических целочисленных данных или без выделенного допустимого адреса памяти. В следующем коде исправлены эти ошибки:

В исправленном примере кода используется локальной память стека для создания резервного хранилища, на который указывает указатель pNumber . Базовый тип используется для простоты. На практике резервное хранилище указателей — это наиболее часто определяемые пользователем типы, динамически выделяемые в области памяти, называемой кучей (или свободным хранилищем), с помощью new выражения ключевых слов (в программировании в стиле C была использована старая malloc() функция библиотеки среды выполнения C). После выделения эти переменные обычно называются объектами, особенно если они основаны на определении класса. Память, выделенная вместе с new ней, должна быть удалена соответствующим delete оператором (или, если для ее выделения использовалась malloc() функция free() среды выполнения C).

Однако легко забыть удалить динамически выделенный объект, особенно в сложном коде, что вызывает ошибку ресурса, называемую утечкой памяти. По этой причине в современном С++ настоятельно не рекомендуется использовать необработанные указатели. Почти всегда лучше упаковать необработанный указатель в интеллектуальный указатель, который автоматически освобождает память при вызове деструктора (когда код выходит за пределы области для интеллектуального указателя); используя интеллектуальные указатели, вы практически устраняете целый класс ошибок в программах C++. В следующем примере предположим, что MyClass — это пользовательский тип, который имеет открытый метод DoSomeWork();

Дополнительные сведения о смарт-указателях см. в разделе «Интеллектуальные указатели».

Дополнительные сведения о преобразованиях указателей см. в разделе «Преобразования типов» и «Безопасность типов».

Дополнительные сведения о указателях в целом см. в разделе «Указатели».

Типы данных Windows

В классическом программировании Win32 для C и C++ большинство функций используют зависящие от Windows определения типов и #define макросов (определенных в windef.h ) для указания типов параметров и возвращаемых значений. Эти Windows типы данных в основном представляют собой специальные имена (псевдонимы), которые предоставляются встроенным типам C/C++. Полный список этих определений типов и определений препроцессора см. в Windows типах данных. Некоторые из этих дескрипторов, таких как HRESULT и LCID , являются полезными и описательными. Другие, например INT , не имеют особого значения и являются просто псевдонимами для фундаментальных типов C++. Прочие типы данных Windows имеют имена, которые сохранились с эпохи программирования на языке C для 16-разрядных процессоров, и не имеют смысла или значения на современном оборудовании или в современных операционных системах. Существуют также специальные типы данных, связанные с библиотекой среда выполнения Windows, перечисленные как среда выполнения Windows базовые типы данных. В современном языке C++ в целом рекомендуется использовать базовые типы C++, за исключением случаев, когда тип Windows сообщает некоторые дополнительные сведения о том, как следует интерпретировать значение.

Дополнительные сведения

Дополнительные сведения о системе типов C++ см. в следующих разделах.

Типы значений
Описывает типы значений вместе с проблемами, связанными с их использованием.

Преобразования типов и безопасность типов
Описание типовых проблем преобразования типов и способов их избежать.

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

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