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

227
15 декабря 2016, 16:14

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

int ** p;

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

Answer 1

Указатель в C — не семантика, а механизм. Он сам по себе не несёт смысла, но может использоваться для выражения того или иного смысла. То же относится и к двойному указателю: он может использоваться для разных вещей. Вот несколько примеров.

  1. В 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]);
    }
  2. В C указатель может обозначать массив. Если тип элемента массива — указатель, получается двойной указатель. Классический пример:

    int main(int argc, char** argv) { ... }
  3. Двойной указатель можно использовать для массива массивов. Например, квадратная матрица:

    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++ обычно ручное управление памятью не приветствуется, поэтому там кратные указатели встречаются куда реже.

Answer 2

Ни в языке С++, ни в языке С, нет такого понятия, как "указатель на указатель" в виде самостоятельной сущности с какими-то новыми качественными свойствами. Поэтому в строгом смысле слова, вопрос о том "зачем нужен указатель на указатель" не имеет никакого смысла.

В языках С и С++ есть такое понятие, как указатель. Просто указатель. Т.е. если у вас есть некий тип T, то вы можете объявить указатель p на этот тип

T *p;

и заставить этот указатель указывать на объект t типа T

T t;
p = &t;

После этого выражения t и *p будут обозначать один и тот же объект. Т.е. если вы, например, поменяете значение объекта *p, то тем самым вы поменяете и объект t (и наоборот). Вы можете также завести еще сколько угодно указателей на один и от же объект.

Это - элементарные основы идеи указателя.

Ну так а далее можно просто заметить, что тип T сам по себе может быть указательным типом. Но это совершенно ничего не меняет. Нет ничего принципиально разного между ситуацией, когда T - это int, и ситуацией, когда T - это double *. Все вышесказанное относится к обоим случаям в одинаковой мере.

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

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

Answer 3

Когда-то объяснял это на примере холодильника.

int **fridge; // Холодильник с полочками на которых еда
*fridge; // Полочка в холодильнике
**fridge; // Колбаса
Answer 4

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

READ ALSO
Указатели c++

Указатели c++

В C# я мог использовать свои объекты следующим образом:

252
Односвязный список с++

Односвязный список с++

Написал программу для создания односвязного списка

259
Создание Skip List, используя STL

Создание Skip List, используя STL

Кто-нибудь когда-то встречался с подобной реализацией скип списка? Рассматривал варианты реализации с помощью vector и setНо возникают затруднения...

240
Переход между элементами STL списка

Переход между элементами STL списка

Как можно, не используя итератор begin() и end(), двигаться в списке? Нужно просто nextСудя по описанию, то там нет просто next() итератора

190