Почему и когда стоит использовать указатель на указатель? [дубликат]

7
задан Community 23 May 2017 в 10:27
поделиться

7 ответов

На такой общий вопрос как-то сложно ответить.

Первым ответом программиста на C ++, безусловно, будет: Не используйте указатели в C ++! Поскольку у вас есть много более безопасных способов решения проблем, чем указатели, одной из ваших целей будет в первую очередь избегать их:)

Таким образом, указатели на указатели редко используются в C ++. В основном они используются в C. Во-первых, потому что в C строки - это «char *», поэтому, когда вам нужен «указатель на строку C», вы заканчиваете «char **». Во-вторых, поскольку у вас нет ссылок в C, когда вам нужна функция, которая изменяет указатель или выдает указатель в качестве выходного значения, вам необходимо указать указатель на параметр указателя. Обычно вы обнаруживаете это в функциях, которые выделяют память, поскольку они дают вам указатель на выделенную память.

Если вы идете по пути C ++, старайтесь избегать указателей, обычно у вас есть способы получше.

my2c

8
ответ дан 6 December 2019 в 06:35
поделиться

Я могу придумать два варианта использования.

Один из них - массивы , унаследованные от C. Во многих случаях массивы автоматически распадаются на указатели на свои первые элементы. Если у вас есть массив указателей, вы получите указатель на указатель для этого.
(Нечто подобное может произойти, когда у вас есть std :: vector указателей, BTW: указатель - идеальный итератор с произвольным доступом, и я действительно видел реализации std lib с использованием указателей для std :: vector <> :: iterator . Для std :: vector указателей, v.begin () вернет указатель на указатель.)

Другой вариант - для аргументов функции . Для аргументов функции принятие чего-либо на указатель означает, что вызывающие абоненты могут вызывать функцию, даже если у них нет объекта для передачи; тогда они могут передать NULL . (В противном случае зачем использовать указатель вместо ссылки? Подробнее об этом см. здесь ).
Принятие ссылки на указатель, отличной от const , будет означать, что вызываемая функция может присвоить этому указателю новый адрес.
Таким образом, получение указателя на указатель будет означать, что функция может назначить новый адрес указателю, если вызывающий объект передает указатель на него, но также может быть вызван с NULL . Например:

void f(int** ppi);
void g(int i);

void h()
{
   f(NULL); // call `f()` only for its side-effects

   int* pi = NULL;
   f(&pi);  // call `f()` and get some object in *pi
   if(pi) 
     g(*pi); // use result
}
4
ответ дан 6 December 2019 в 06:35
поделиться

Указатели на указатели имеют наибольшее значение в C.Изредка они вам нужны в C ++. Там вы можете работать с контейнерами из std lib или со ссылками.

Однако в C есть два популярных варианта использования:

  1. Массив указателей, наиболее часто используемый как argv для main (): указатель дает адрес массиву строк аргументов (тип char *). В C операторы [] работают с указателями на что-либо, поскольку указатели на что-либо рассматриваются как эквивалент массивов.

  2. Аргумент функции, обозначающий место для хранения адреса чего-либо. Пример использования: в C возвращаемое значение часто используется для обработки ошибок или информации о состоянии. Аргументы используются для переноса полезной нагрузки. Один пример: функция «возвращает» адрес вновь выделенной памяти, но с использованием аргумента. Вы даете функции указатель на указатель, который впоследствии должен указывать на данные. Функция перезаписывает это пространство, и для этого ей нужен указатель на указатель.

3
ответ дан 6 December 2019 в 06:35
поделиться

На самом деле существует два варианта использования.

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

int *p1 = 0, *p2 = 0, *p3 = 0;
multi_malloc(&p1, &p2, &p3); // Allocates three pointers

Во-вторых, когда вы хотите создать разреженные 2-мерные массивы:

int main (int argc, char ** argv)

Это указатель на указатель. argv [i] - указатель на char. Таким образом, argv [i] [j] является char j в строке i.

Вы будете рады услышать, что указатель на указатель на указатель практически не используется. int *** p; почти никогда не пригодится.

1
ответ дан 6 December 2019 в 06:35
поделиться

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

2
ответ дан 6 December 2019 в 06:35
поделиться

Где и когда следует использовать указатель на указатель?

В функции, которая при желании может возвращать указатель на вызывающую сторону, если вызывающая сторона этого требует. Часто используется системными API, некоторыми COM-объектами и т. Д.

int f(void** p = 0){
    //.......
}

Если вызывающий предоставляет p, тогда функция передает указатель через p. Если вызывающий абонент не предоставляет p, указатель не возвращается. Может быть полезно для отладки в определенных ситуациях.

Каковы преимущества?

Вопрос слишком широкий. Послушайте, это ОЧЕНЬ простая техника без каких-то таинственных преимуществ. Вы используете его, когда вам нужно. Это все. В этом понятии нет скрытого смысла и секретных преимуществ - это все равно, что спрашивать «каковы преимущества использования буквы« е »в английском языке».

3
ответ дан 6 December 2019 в 06:35
поделиться

В C аргумент передается функции, которая его изменяет, через указатель. Вы увидите то же самое с C ++ для старого или устаревшего кода ( int main (int argc, char ** argv) ), для кода, доступ к которому будет осуществляться из C (COM / XPCOM), или для кода, который был написано кем-то, кто привык к C (или стилю C).

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

6
ответ дан 6 December 2019 в 06:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: