Что такое ** в C++?
Описание проблемы
Я столкнулся с некоторым кодом, а также с ошибками, которые сгенерировал мой компилятор, содержащими токен <code>**</code> перед переменной (например, имя_переменной unreferenced - или что-то подобное, точно не помню). Я довольно уверен, что это связано с указателями. Если бы мне пришлось догадываться, то это выглядит так, будто компилятор пытается разыменовать указатель дважды. Токен <code>**</code> довольно сложно найти в интернете. Можете ли вы указать на хороший сайт или документацию, или кто-то мог бы объяснить это здесь?
Спасибо.
Также, если можно, добавлю: в каких ситуациях полезно иметь указатель на указатель? Разве не следует использовать оригинальный указатель вместо создания еще одного указателя на оригинальный указатель?
5 ответ(ов)
В языке C ** действительно представляет собой не только указатель на указатель (как в объявлении), но и разыменование разыменования (в выражении).
Этот подход часто используется в C, так как язык не поддерживает нотацию & для ссылок. Например, он полезен для обновления возвращаемого значения, которое является указателем:
int alloc_foo(struct foo **foo_ret)
{
*foo_ret = malloc(sizeof(struct foo));
return 1; /* указывает на успешное выполнение; возвращаемое значение в foo_ret */
}
В этом примере foo_ret является указателем на указатель на структуру foo. Разыменование *foo_ret позволяет выделить память для нового объекта типа struct foo и установить адрес этого объекта в память, на которую указывает foo_ret. Это способ, позволяющий функции изменять значение foo_ret в вызывающем коде.
Вы можете узнать сигнатуру функции main() следующим образом:
int main(int argc, char* argv[])
Следующий вариант является эквивалентным:
int main(int argc, char** argv)
В этом случае, argv представляет собой указатель на массив указателей на char.
В языке C оператор индексации [] является просто другим способом выполнения арифметики указателей. Например,
foo[i]
выдает такой же код, как и
*(foo + i)
Это означает, что использование [] в C — это просто более удобная форма записи работы с указателями.
Это не токен **. Это просто токен *, за которым следует другой токен *. В вашем случае у вас есть указатель на указатель, и он разыменовывается дважды, чтобы получить то, на что действительно указывает.
** — это указатель на указатель.
Он может использоваться для представления матрицы (массива массивов) или массива строк (массива типа char), и так далее.
Это двойная разыменовывающая операция.
В приведённом вами коде мы имеем три переменные:
int i = 3;— обычная переменная типаint, которая хранит значение 3.int* ptr_to_i = &i;— указательptr_to_i, который указывает на адрес переменнойi.int** ptr_to_ptr_to_i = &ptr_to_i;— указатель на указательptr_to_ptr_to_i, который указывает на адрес указателяptr_to_i.
Когда вы выполняете std::cout << **ptr_to_ptr_to_i << std::endl;, происходит следующее:
*ptr_to_ptr_to_iразыменовывает первый указатель, т.е. получает значениеptr_to_i, что является адресом переменнойi.- Далее, второе разыменование
**ptr_to_ptr_to_iполучает значение по этому адресу, т.е. значение переменнойi, которое равно 3.
Таким образом, код выводит на экран значение 3.
Сравнение регулярного приведения типов, static_cast и dynamic_cast
Разница между const int*, const int * const и int * const?
Почему следует использовать указатель вместо самого объекта?
Почему код явно вызывает статический метод через указатель, равный null?
Статические глобальные переменные в C++