Тестирование с помощью https://matplotlib.org/examples/animation/dynamic_image.html Я просто добавляю
%matplotlib notebook
, который, похоже, работает, но немного ухабирован. Мне пришлось останавливать ядро время от времени: - (
Наиболее распространенное использование как @aku указанный должно позволить изменению в параметре указателя быть видимым после функциональных возвратов.
#include <iostream>
using namespace std;
struct Foo {
int a;
};
void CreateFoo(Foo** p) {
*p = new Foo();
(*p)->a = 12;
}
int main(int argc, char* argv[])
{
Foo* p = NULL;
CreateFoo(&p);
cout << p->a << endl;
delete p;
return 0;
}
Это распечатает
12
Но существует несколько других полезных использований как в следующем примере, чтобы выполнить итерации массива строк и распечатать их к стандартному выводу.
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
const char* words[] = { "first", "second", NULL };
for (const char** p = words; *p != NULL; ++p) {
cout << *p << endl;
}
return 0;
}
IMO наиболее распространенное использование должен передать ссылку на переменную указателя
void test(int ** var)
{
...
}
int *foo = ...
test(&foo);
Можно создать многомерный зубчатый массив с помощью двойных указателей:
int ** array = new *int[2];
array[0] = new int[2];
array[1] = new int[3];
Один общий сценарий - то, куда необходимо передать нулевого указателя функции, и инициализировать его в той функции, и используемый вне функции. Без multplie косвенности функция вызова никогда не имела бы доступа к инициализированному объекту.
Рассмотрите следующую функцию:
initialize(foo* my_foo)
{
my_foo = new Foo();
}
Любая функция, которая звонит, 'инициализирует (нечто*)' не будет иметь доступа к инициализированному экземпляру Foo, потому что указатель, это передается этой функции, является копией. (Указатель является просто целым числом, в конце концов, и целые числа передаются значением.)
Однако, если функция была определена как это:
initialize(foo** my_foo)
{
*my_foo = new Foo();
}
... и это назвали как это...
Foo* my_foo;
initialize(&my_foo);
... затем у вызывающей стороны был бы доступ к инициализированному экземпляру через 'my_foo' - потому что это - адрес указателя, который был передан для 'инициализирования'.
Конечно, в моем упрощенном примере, 'инициализировать' функция могла просто возвратить недавно созданный экземпляр через ключевое слово возврата, но это не всегда подходит - возможно, функция должна возвратить что-то еще.
При передаче указателя в как выходной параметр Вы могли бы хотеть передать его как Foo**
и установленный его значение как *ppFoo = pSomeOtherFoo
.
И от algorithms-and-data-structures отдела, можно использовать ту двойную косвенность для обновления указателей, которые могут быть быстрее, чем, например, свопинг фактических объектов.
Carl: Ваш пример должен быть:
*p = x;
(У Вас есть две звезды.) :-)
Простой пример использовал бы int** foo_mat
как 2-й массив целых чисел. Или можно также использовать указатели на указатели - позволяет, говорят, что у Вас есть указатель void* foo
и у Вас есть 2 различных объекта, которые имеют ссылку на него со следующими членами: void** foo_pointer1
и void** foo_pointer2
, при наличии указателя на указатель можно на самом деле проверить ли *foo_pointer1 == NULL
который указывает, что нечто является ПУСТЫМ. Вы не смогли бы проверить, является ли нечто ПУСТЫМ, если foo_pointer1 был регулярным указателем. Я надеюсь, что мое объяснение не было слишком грязно :)
В C абсолютно требуется идиома. Рассмотрите проблему, в которой Вы хотите, чтобы функция добавила строку (чистый C, таким образом, символ *) к массиву указателей для обугливания *. Прототип функции требует трех уровней абстракции:
int AddStringToList(unsigned int *count_ptr, char ***list_ptr, const char *string_to_add);
Мы называем его следующим образом:
unsigned int the_count = 0;
char **the_list = NULL;
AddStringToList(&the_count, &the_list, "The string I'm adding");
В C++ у нас есть опция использования ссылок вместо этого, которые привели бы к другой подписи. Но нам все еще нужны эти два уровня абстракции, о которых Вы спросили в Вашем исходном вопросе:
int AddStringToList(unsigned int &count_ptr, char **&list_ptr, const char *string_to_add);
Обычно, когда Вы передаете указатель на функцию как возвращаемое значение:
ErrorCode AllocateObject (void **object);
куда функция возвращает код ошибки успеха/отказа и заполняет параметр объекта с указателем на новый объект:
*object = new Object;
Это используется много в COM, программирующем в Win32.
Это - больше вещи C сделать, в C++ можно часто переносить этот тип системы в класс для создания кода более читаемым.