Разыменование пустого указателя как исправить
Перейти к содержимому

Разыменование пустого указателя как исправить

Указатели и ссылки в языке C++

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

  • переменных
  • констант
  • функций
  • других указателей
Объявление указателей

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

Инициализация указателей

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

Указателю нельзя присвоить адрес переменной другого типа. То есть нельзя указателю типа int* присвоить адрес переменной типа double.

Также указателю можно присвоить значение другого указателя.

Указатель также может быть проинициализирован пустым значением. Это можно сделать несколькими способами:

  • использовать значение 0 или макроопределение NULL
  • использовать значение nullptr
  • использовать значение std::nullptr_t (C++ 11)

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

Тип std::nullptr_t может иметь только одно значение — nullptr. Использование этого типа поможет в тех редких случаях, когда существуют перегруженные функции и требуется передать нулевой указатель. В этом случае непонятно какую именно функцию нужно будет вызвать. Поэтому в таком случае в функции можно задать аргумент с типом std::nullptr_t.

Напрямую записать адрес в указатель можно только с помощью операций преобразования типов, либо операции reinterpret_cast.

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

Для получения значения переменной, на которую ссылается указатель, используется операция разыменования указателя. Эта операция записывается как символ * (звездочка), написанный перед указателем.

Арифметические действия с указателями

С указателем можно производить следующие арифметические действия:

  • сложение и вычитание с целым числом
  • операции инкремента/декремента

При использовании арифметических операций, указатель изменяется на величину кратную размеру типа указателя. Например, если указатель имеет тип 32-разрядного int, то увеличение указателя на 1 приведет к увеличению значения адреса в указателе на 4.

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

В языке C++ можно объявить указатель, который будет указывать на другой указатель.

Синтаксис объявления такой же, как и у объявления указателя, за исключением того, что ставится два символа * (звездочка).

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

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

Язык C++ также позволяет работать с указателями на указатели на указатели, или сделать еще большую вложенность. Их можно объявлять просто увеличивая количество символов * (звездочек). Однако на практике такие указатели используются крайне редко.

Ссылки

Ссылка — это тип переменной в языке C++, который работает как псевдоним другого объекта или значения. При объявлении ссылки перед её именем ставится символ амперсанда &. Сама же ссылка не может быть пустой, и должна быть обязательно проинициализирована именем переменной, на которую она ссылается. Изменить значение ссылки после инициализации невозможно.

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

Любые действия со ссылкой трактуются компилятором как действия, которые будут выполняться над объектом, на который она ссылается.

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

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

Ссылки r-value

В стандарте C++11 ввели новый тип ссылок — ссылки r-value. Ссылки r-value — это ссылки, которые инициализируются только значениями r-values. Объявляются такие ссылки, в отличие от обычных, с помощью двух символов амперсанда &&.

Ссылки r-value, в отличие от обычных ссылок, ссылаются не на постоянный, а на временный объект, созданный при инициализации ссылки r-value.

Такие ссылки обладают двумя важными свойствами:

  • продолжительность жизни объекта, на который ссылается ссылка увеличивается до продолжительности жизни самой ссылки
  • неконстантные ссылки r-value позволяют менять значение r-values, на который они ссылаются

Ссылки r-value — позволяют избегать логически ненужного копирования и обеспечивать возможность идеальной передачи (perfect forwarding). Прежде всего они предназначены для использования в высокопроизводительных проектах и библиотеках.

Разыменование нулевого указателя, предупреждение

Я сделал «Построить и проанализировать» в xCode и получил «Разыменование нулевого указателя». В приведенном ниже коде я отметил, для какой строки я получаю сообщение. Разрабатываю для iPhone.

Это не полный код, вставлено то, что я считаю полезным.

Я нахожу это довольно странным. Как я получил это сообщение?

Введите описание изображения здесь

3 ответы

Если self равен nil, вы не можете получить доступ к переменным экземпляра self. Таким образом, вы должны ссылаться на эти переменные только внутри оператора if. Другими словами, только если self не равен нулю.

is appDelegate экземпляр var класса? если да, то вы должны сделать это в if (self =. . то же самое с [self addSubview. ] . в основном, если этот оператор if не работает, у вас нет объекта для работы.

appDelegate на самом деле [self appDelegate] , поэтому, если вы присвоите null self , вы разыменовываете нулевой указатель.

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

И последнее — ты do использование self в любом случае явно в предпоследней строке, и здесь ясно, что это null:

Не тот ответ, который вы ищете? Просмотрите другие вопросы с метками iphone objective-c debugging code-analysis or задайте свой вопрос.

Указатели

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

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

Таким образом, каждая ячейка может быть легко расположена в памяти посредством своего уникального адреса. Например, ячейка памяти с адресом 1776 всегда следует непосредственно за ячейкой с адресом 1775 и предшествует ячейке с адресом 1777, а также находится точно на тысячу ячеек после 776 и точно на тысячу перед 2776.

Когда переменная объявлена, памяти, необходимой для хранения ее значения, назначается определенное место в памяти (ее адрес памяти). Обычно, программы на C++ не принимают активного участия в определении точного адреса памяти, в которой хранится переменная. К счастью, эта задача оставлена ​​для среды, в которой запускается программа, — обычно это операционная система, которая определяет конкретные области памяти во время выполнения. Тем не менее, программе может быть полезно иметь возможность получить адрес переменной во время исполнения, для доступа к ячейкам данных, которые находятся в определенной позиции относительно этой переменной.

Оператор взятия адреса (&)

Адрес переменной можно получить, поставив перед именем переменной знак амперсанда (&), известный как оператор взятия адреса. Например:

Это присвоит адрес переменной myvar переменной foo; ставя оператор взятия адреса (&) перед именем переменной myvar, мы присваиваем переменной foo не содержимое переменной myvar, а её адрес.

Фактический адрес переменной в памяти неизвестен до выполнения, однако, для выяснения некоторых понятий, давайте предположим, что myvar во время выполнения расположена в памяти по адресу 1776.

В этом случае, рассмотрим следующий фрагмент кода:

Значения, содержащиеся в каждой переменной после выполнения этого кода, показаны на следующей диаграмме:

Сначала мы присвоили значение 25 переменной myvar (переменная, адрес которой мы предположили равным 1776).

Второе выражение присваивает переменной foo адрес переменной myvar, равный 1776.

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

Главное отличие между вторым и третьим выражениями — появление оператора взятия адреса (&).

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

Оператор разыменования (*)

Как только что сказано, переменная, хранящая адрес другой переменной, называется указателем. Говорят, что указатели «указывают на» переменную, адрес которой они хранят.

Интересным свойством указателей является то, что они могут быть использованы для доступа к переменной, на которую они указывают, напрямую. Это делается путём добавления перед именем указателя оператора разыменования (*). Сам оператор может быть прочтен как «значение, на которое указывает».

Следовательно, следуя значениям предыдущего примера, получим выражение:

Это может быть прочтено как «baz равен значению, на которое указывает foo», а выражение, в действительности, присвоит значение 25 переменной baz, т.к. foo равна 1776, а значение по адресу 1776 равно 25.

Важно четко различать, что foo ссылается на значение 1776, тогда как *foo (со звездочкой *, предшествующей идентификатору) ссылается на значение, хранящееся по адресу 1776, в данном случае это 25. Обратите внимание на разницу включения или не включения оператора разыменования (Я добавил пояснительный комментарий о том, как можно прочитать каждое из этих двух выражений).

Операторы взятия адреса и разыменования, таким образом, дополняют друг друга:
& это оператор взятия адреса, и может быть прочтен просто как «адрес»
* это оператор разыменования, и может быть прочтен как «значение, на которое указывает»

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

Ранее мы выполняли следующие две операции присваивания:

Сразу после этих двух выражений, все следующие выражения будут иметь значение true в качестве результата:

Первое выражение вполне понятно, учитывая, что была произведена операция присваивания myvar=25. Второе выражение использует оператор взятия адреса (&), который возвращает адрес myvar, который мы предположили равным 1776. Третье выражение очевидно, т.к. второе выражение было истинным, и была произведена операция присваивания foo=&myvar. Четвертое выражение использует оператор разыменования (*), который может быть прочтен как «значение, на которое указывает». а значение, на которое указывает foo в действительности 25.

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

Объявление указателей

Благодаря способности указателя напрямую ссылаться на значение, на которое он указывает, указатель имеет разные свойства, когда он указывает на char или когда он указывает на int или float. После разыменования тип должен быть известен. И для этого в объявлении указателя должен быть указан тип данных, на который будет указывать указатель.

Объявление указателя имеет следующий синтаксис:

где type — это тип данных, на которые будет ссылаться указатель. Этот тип является типом не самого указателя, а типом данных, на которые он ссылается. Например:

Здесь объявлено три указателя. Каждый из них предназначен для указания на различные типы данных, но, в действительности, каждый из них является указателем и все они, вероятно, будут занимать одинаковое количество памяти (размер указателя в памяти зависит от платформы, на которой работает программа). Тем не менее, данные, на которые они указывают, не занимают одинаковое количество памяти и не имеют одинаковый тип: первый указывает на int, второй на char, а третий на double. Следовательно, хотя все эти три переменных являются указателями, в действительности, они имеют различные типы: int*, char* и double* соответственно, в зависимости от типа, на который они указывают.

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

Давайте посмотрим на пример с указателями:

Каждая операция присваивания включает комментарий о том, как можно прочитать каждую строку: т.е. амперсанды (&) заменены на «адрес», а звездочки (*) на «значение, адресуемое».

Обратите внимание, что существуют выражения с указателями p1 и p2, как с оператором разыменования (*), так и без него. Значение выражения, использующего оператор разыменования (*), очень отличается от выражения, не использующего его. Когда этот оператор предшествует имени указателя, выражение ссылается на значение по адресу указателя, тогда как без него, выражение ссылается на значение самого указателя (т.е. адрес, на который указывает указатель).

Ещё одна строка, которая может привлечь ваше внимание:

Она объявляет два указателя, использованные в предыдущем примере. Но обратите внимание, что для каждого указателя есть звездочка (*), чтобы оба указателя имели тип int * (указатель на int). Это требование обусловлено правилами приоритета. Обратите внимание, что если вместо этого код был таким:

p1 действительно будет иметь тип int *, но p2 будет иметь тип int. Пробелы не имеют значения в данном контексте. Но в любом случае, просто помнить о том, чтобы поставить одну звездочку на указатель, достаточно при объявлении множества указателей в одном выражении. Или даже лучше: используйте разные выражения для каждой переменной.

Указатели и массивы

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

Следующая операция присваивания будет корректной:

Давайте посмотрим на пример, который смешивает массивы и указатели:

Указатели и массивы поддерживают одинаковый набор операций с одинаковым смыслом для обоих. Основное отличие состоит в том, что указателям могут быть назначены новые адреса, а массивам — нет.
В главе о массивах скобки ( [ ] ) были объяснены как указание на индекс элемента массива. На самом деле эти скобки — это оператор разыменования, известный как оператор смещения. Они разыменовывают переменную, за которой следуют, так же, как и *, но они также добавляют число в скобках к адресу, на который делается разыменование. Например:

Эти два выражения эквивалентны и допустимы не только если a является указателем, но также и если a является массивом. Помните, имя массива можно использовать так же, как указатель на его первый элемент.

Инициализация указателей

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

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

Когда указатели инициализируются, инициализируется адрес, на который они указывают (то есть myptr), а не указываемое значение (то есть * myptr). Поэтому приведенный выше код не следует путать с:

Что в любом случае не имеет большого смысла (и не является корректным кодом).
Звездочка ( * ) в объявлении указателя (строка 2) показывает только то, что это указатель, а не оператор разыменования (как в строке 3). В обоих случаях просто используется один и то же символ: *. Как всегда, пробелы не имеют значения и никогда не изменяют смысла выражения.
Указатели могут быть инициализированы либо по адресу переменной (например, в приведенном выше случае), либо по значению другого указателя (или массива):

Адресная арифметика

Выполнение арифметических операций с указателями немного отличается от выполнения их с обычными целочисленными типами. Для начала, разрешены только операции сложения и вычитания; другие не имеют смысла в мире указателей. Но и сложение, и вычитание ведут себя немного иначе с указателями в зависимости от размера типа данных, на который они указывают.
Когда были представлены основные типы данных, мы увидели, что типы имеют разные размеры. Например: char всегда имеет размер 1 байт, short обычно больше него, а int и long еще больше; точный размер зависит от системы. Например, давайте представим, что в данной системе char занимает 1 байт, short занимает 2 байта, а long 4.
Предположим теперь, что мы определили три указателя в этом компиляторе:

и что мы знаем, что они указывают на ячейки памяти 1000, 2000 и 3000 соответственно.
Следовательно, если мы напишем:

mychar, как и следовало ожидать, будет содержать значение 1001. Но не так очевидно, что myshort будет содержать значение 2002, а mylong будет содержать 3004, хотя каждый из них был увеличен только один раз. Причина заключается в том, что при добавлении единицы к указателю, он будет указывать на следующий элемент того же типа, и поэтому к указателю добавляется размер в байтах того типа, на который он указывает.

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

Что касается операторов инкремента (++) и декремента (), они оба могут использоваться как префикс или суффикс выражения, с небольшим различием в поведении: в качестве префикса инкремент происходит до того, как вычислено выражение, а в качестве суффикса инкремент происходит после того, как вычислено выражение. Это также относится к выражениям, увеличивающим и уменьшающим указатели, которые могут стать частью более сложных выражений, которые также включают операторы разыменования (*). Вспоминая правила приоритета операторов, мы можем вспомнить, что постфиксные операторы, такие как инкремент и декремент, имеют более высокий приоритет, чем префиксные операторы, такие как оператор разыменования (*). Следовательно, следующее выражение:

эквивалентно *(p++). Это увеличивает значение p (так что теперь оно указывает на следующий элемент), но так как используется постфиксная запись оператора ++, все выражение вычисляется как значение, на которое указывал указатель изначально (адрес, на который он указывал до инкремента).
По сути, это четыре возможные комбинации оператора разыменования с префиксной и суффиксной версиями оператора инкремента (то же самое применимо и к оператору декремента):

Типичное, но не очень простое выражение, включающее эти операторы:

Поскольку ++ имеет более высокий приоритет, чем *, оба значения p и q увеличиваются, но поскольку оба оператора инкремента (++) используются в качестве постфикса, а не префикса, значение, присваиваемое *p, равно *q до увеличения как p, так и q. А затем оба увеличиваются. Это было бы примерно эквивалентно:

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

Указатели и const

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

Здесь p указывает на переменную, но указывает на нее константно, что означает, что он может прочитать указанное значение, но не может изменить его. Также обратите внимание, что выражение &y имеет тип int*, но оно присваивается указателю типа const int*. Это разрешено: указатель на не-константу может быть неявно преобразован в указатель на константу. Но не наоборот! Из соображений безопасности указатели на const неявно не конвертируются в non-const указатели.
Один из вариантов использования указателей на константные элементы — это параметры функции: функция, которая принимает указатель на non-const в качестве параметра, может изменить значение, переданное в качестве аргумента, а функция, которая принимает указатель на const в качестве параметра, не может.

Обратите внимание, что print_all использует указатели, которые указывают на константные элементы. Эти указатели указывают на константное содержимое, которое они не могут изменить, но сами они не являются константами: то есть указатели все еще могут увеличиваться или назначаться другим адресам, хотя они не могут изменять содержимое, на которое они указывают.
И здесь к указателям добавляется второе измерение константности: указатели также могут быть константами. И это указывается добавлением const к указанному типу (после звездочки):

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

Как и в случае пробелов, окружающих звездочку, порядок const в этом случае просто вопрос стиля. В этой главе используется префикс const, но оба они в точности эквивалентны. Достоинства каждого стиля до сих пор активно обсуждаются в Интернете.

Указатели и строковые литералы

Как указывалось ранее, строковые литералы — это массивы, содержащие символьные последовательности, заканчивающиеся нулем. В предыдущих разделах строковые литералы использовались для непосредственной вставки в cout, для инициализации строк и для инициализации массивов символов.
Но они также могут быть доступны напрямую. Строковые литералы — это массивы соответствующего типа, которые содержат все его символы плюс завершающий нулевой символ, причем каждый из элементов имеет тип const char (как литералы, они никогда не могут быть изменены). Например:

Это объявляет массив с литеральным представлением для «hello», а затем указатель на его первый элемент присваивается foo. Если мы представим, что «hello» хранится в ячейках памяти, которые начинаются с адреса 1702, мы можем представить предыдущее объявление как:

Обратите внимание, что здесь foo является указателем и содержит значение 1702, а не «h» или «hello», хотя 1702 действительно является адресом обоих.

Указатель foo указывает на последовательность символов. И поскольку указатели и массивы ведут себя по существу одинаково в выражениях, foo может использоваться для доступа к символам таким же образом, как массивы символов с нулем на конце. Например:

Оба выражения имеют значение «o» (пятый элемент массива).

Указатели на указатели

C++ позволяет использовать указатели, которые указывают на указатели, которые, в свою очередь, указывают на данные (или даже на другие указатели). Синтаксис просто требует звездочки (*) для каждого уровня косвенности в объявлении указателя:

Предполагая, что ячейки памяти для каждой переменной 7230, 8092 и 10502 выбраны случайно, это может быть представлено как:

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

  • c типа char** и значением 8092
  • *c типа char* и значением 7230
  • **c типа char и значением ’z’
Указатели на void

Указатель типа void — это специальный тип указателя. В C ++ void представляет отсутствие типа. Следовательно, указатели void — это указатели, которые указывают на значение, которое не имеет типа (и, следовательно, также имеет неопределенную длину и неопределенные свойства разыменования).
Это дает указателям void большую гибкость, поскольку позволяет указывать на любой тип данных, от целочисленного значения или с плавающей точкой до строки символов. В обмен на это у них есть большое ограничение: данные, на которые они указывают, не могут быть напрямую разыменованы (что логично, поскольку у нас нет типа для разыменования), и по этой причине, любой адрес в указателе на void должен быть преобразован в некоторый другой тип указателя, который указывает на конкретный тип данных перед разыменованием.
Одним из возможных применений может быть передача обобщенных параметров функции. Например:

sizeof — это оператор, интегрированный в язык C ++, который возвращает размер в байтах своего аргумента. Для нединамических типов данных это значение является константой. Поэтому, например, sizeof (char) равен 1, потому что char всегда имеет размер в один байт.

Недействительные и нулевые указатели

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

Ни p, ни q не указывают на адреса, о которых известно, что они содержат значение, но ни одно из приведенных выше выражений не приводит к ошибке. В C++ указатели могут принимать любое значение адреса, независимо от того, есть ли что-то по этому адресу или нет. Что может вызвать ошибку при разыменовании такого указателя (т.е. фактически при получении доступа к значению, на которое он указывает). Доступ к такому указателю вызывает неопределенное поведение — от ошибки во время выполнения до доступа к некоторому случайному значению.
Но иногда указатель действительно должен явно никуда не указывать, а не просто указывать на неверный адрес. Для таких случаев существует специальное значение, которое может принимать любой тип указателя: нулевое значение указателя. Это значение может быть выражено в C++ двумя способами: либо с целочисленным значением, равным нулю, либо с ключевым словом nullptr:

Здесь и p, и q являются нулевыми указателями, это означает, что они явно никуда не указывают, и они фактически равны между собой: все нулевые указатели равны любым другим нулевыми указателям. Также привычно видеть, что константа NULL используется в старом коде для ссылки на значение нулевого указателя:

NULL объявлен в нескольких заголовочных файлах стандартной библиотеки и определяется как псевдоним некоторого значения константы нулевого указателя (например, 0 или nullptr).
Не путайте нулевые указатели с указателями на void! Нулевой указатель — это значение, которое любой указатель может принять для представления того, что он указывает на «никуда», в то время как указатель на void — это тип указателя, который может указывать куда-то без определенного типа. Первый относится к значению, хранящемуся в указателе, а второй — к типу данных, на которые он указывает.

Указатели на функции

C++ позволяет работать с указателями на функции. Типичное использование — передача функции в качестве аргумента другой функции. Указатели на функции объявляются с тем же синтаксисом, что и обычное объявление функции, за исключением того, что имя функции заключено в круглые скобки (), а перед именем стоит звездочка (*):

В приведенном выше примере minus — указатель на функцию, имеющую два параметра типа int. Он непосредственно инициализируется для указания на функцию subtraction:

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

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