Страницы

Поиск по вопросам

четверг, 12 декабря 2019 г.

Указатель на указатель - что это?

#указатели #синтаксис #cpp


Часто встречаю вот такую конструкцию: 
int ** p;

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


Ответы

Ответ 1



Указатель в C — не семантика, а механизм. Он сам по себе не несёт смысла, но может использоваться для выражения того или иного смысла. То же относится и к двойному указателю: он может использоваться для разных вещей. Вот несколько примеров. В C параметры передаются по значению, то есть из коробки нету передачи параметров «по ссылке» (они же &-параметры C++, они же ref-/out-параметры C#). Для того, чтобы объявить такой параметр, пользуются указателем на фактический параметр (то есть, передают в функцию адрес параметра). Если тип самого параметра — указатель, получается двойной указатель. Пример: void split_half(char* input, char** first_half, char** second_half) { var len = strlen(input); var halflen = len / 2; *first_half = malloc(halflen + 1); strncpy(*first_half, input, halflen); (*firsthalf)[halflen] = 0; *second_half = strdup(&input[halflen]); } В C указатель может обозначать массив. Если тип элемента массива — указатель, получается двойной указатель. Классический пример: int main(int argc, char** argv) { ... } Двойной указатель можно использовать для массива массивов. Например, квадратная матрица: struct matrix { int** data; int width; int height; } void init_matrix(int width, int height, struct matrix* matrix) { matrix->width = width; matrix->height = height; matrix->data = malloc(height * sizeof(int*)); for (int y = 0; y < height; y++) matrix->data[y] = malloc(width * sizeof(int)); } В C++ обычно ручное управление памятью не приветствуется, поэтому там кратные указатели встречаются куда реже.

Ответ 2



Ни в языке С++, ни в языке С, нет такого понятия, как "указатель на указатель" в виде самостоятельной сущности с какими-то новыми качественными свойствами. Поэтому в строгом смысле слова, вопрос о том "зачем нужен указатель на указатель" не имеет никакого смысла. В языках С и С++ есть такое понятие, как указатель. Просто указатель. Т.е. если у вас есть некий тип T, то вы можете объявить указатель p на этот тип T *p; и заставить этот указатель указывать на объект t типа T T t; p = &t; После этого выражения t и *p будут обозначать один и тот же объект. Т.е. если вы, например, поменяете значение объекта *p, то тем самым вы поменяете и объект t (и наоборот). Вы можете также завести еще сколько угодно указателей на один и от же объект. Это - элементарные основы идеи указателя. Ну так а далее можно просто заметить, что тип T сам по себе может быть указательным типом. Но это совершенно ничего не меняет. Нет ничего принципиально разного между ситуацией, когда T - это int, и ситуацией, когда T - это double *. Все вышесказанное относится к обоим случаям в одинаковой мере. Вот, собственно и все. Т.е. нет никакого смысла вводить в рассмотрение такую сущность, как "указатель на указатель", и устраивать вокруг нее какие-то обсуждения. Все, что нам нужно - это обычный указатель, который может просто-напросто указывать и на другой указатель. Но эти два уровня указательности (три, четыре, пять уровней...) совершенно отдельны, ничего о друг друге не знают и знать не хотят. И рассматривать такие указатели надо как обычные указатели. То же самое в полной мере справедливо и об "указателях на указатели на указатели", "указателях на указатели на указатели на указатели" и т.д. до бесконечности.

Ответ 3



Когда-то объяснял это на примере холодильника. int **fridge; // Холодильник с полочками на которых еда *fridge; // Полочка в холодильнике **fridge; // Колбаса

Ответ 4



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

Комментариев нет:

Отправить комментарий