Использует для нескольких уровней разыменования указателя? - PullRequest
42 голосов
/ 17 апреля 2009

Когда использование указателей на любом языке требует, чтобы кто-то использовал более одного, скажем, тройного указателя. Когда имеет смысл использовать тройной указатель вместо обычного?

Например:

char  * * *ptr;

вместо

char *ptr;

Ответы [ 17 ]

0 голосов
/ 17 апреля 2009

Когда вы используете вложенные динамически размещенные (или связанные с указателем) структуры данных. Все эти вещи связаны указателями.

0 голосов
/ 17 апреля 2009

Указатели на указатели редко используются в C ++. В основном они имеют два применения.

Первое использование - передать массив. Например, char** - это указатель на указатель на символ, который часто используется для передачи массива строк. Указатели на массивы не работают по уважительным причинам, но это другая тема (см. comp.lang.c FAQ , если вы хотите узнать больше). В некоторых редких случаях вы можете увидеть третью *, используемую для массива массивов, но обычно более эффективно хранить все в одном смежном массиве и индексировать его вручную (например, array[x+y*width] вместо array[x][y]). Однако в C ++ это происходит гораздо реже из-за контейнерных классов.

Второе использование - передача по ссылке. Параметр int* позволяет функции изменять целое число, на которое указывает вызывающая функция, и обычно используется для предоставления нескольких возвращаемых значений. Этот шаблон передачи параметров по ссылке для разрешения множественных возвратов все еще присутствует в C ++, но, как и другие способы передачи по ссылке, обычно заменяется введением реальных ссылок. Другая причина для передачи по ссылке - избежание копирования сложных конструкций - также возможна при использовании ссылки C ++.

C ++ имеет третий фактор, который уменьшает использование нескольких указателей: он имеет string. Ссылка на строку может иметь тип char** в C, так что функция может изменить адрес передаваемой строковой переменной, но в C ++ мы обычно видим string& вместо.

0 голосов
/ 17 апреля 2009

Имеет смысл использовать указатель на указатель всякий раз, когда указатель фактически указывает на указатель (эта цепочка не ограничена, поэтому возможны «тройные указатели» и т. Д.).

Причина создания такого кода заключается в том, что вы хотите, чтобы компилятор / интерпретатор мог правильно проверять используемые вами типы (предотвращать таинственные ошибки).

Вам не нужно использовать такие типы - вы всегда можете просто использовать простой void * и typecast всякий раз, когда вам нужно разыменовать указатель и получить доступ к данным, на которые указывает указатель. Но это, как правило, плохая практика и склонность к ошибкам - конечно, есть случаи, когда использование void * действительно полезно и делает код намного более элегантным. Думайте об этом больше как о вашем последнем прибежище.

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

0 голосов
/ 17 апреля 2009

Если вам нужно изменить указатель внутри функции, вы должны передать ссылку на него.

0 голосов
/ 11 июля 2016

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

struct woozle **my_woozle = newHandle(sizeof struct woozle);

и затем доступ (несколько неловко в синтаксисе C - синтаксис чище в Паскаль): (* my_woozle) -> someField = 23; важно, чтобы приложения не держать прямые указатели на цель любого дескриптора через вызовы функций, которые выделить память, но если существует только один указатель на каждый блок идентифицированный дескриптором менеджер памяти сможет перемещать вещи в случае, если фрагментация станет проблемой.

Подход не работает почти так же хорошо на диалектах Си, которые агрессивно использовать псевдонимы на основе типов, поскольку указатель, возвращаемый NewHandle, не идентифицировать указатель типа struct woozle*, но вместо этого идентифицирует указатель типа void* и даже на платформах, где эти типы указателей будут иметь то же представление стандарт не требует, чтобы реализации интерпретировать приведенный указатель как указание на то, что следует ожидать, что псевдонимы может произойти.

0 голосов
/ 24 апреля 2017

Двойная косвенность упрощает многие алгоритмы балансировки дерева, где обычно требуется возможность эффективно «отсоединить» поддерево от его родителя. Например, реализация дерева AVL может использовать:

void rotateLeft(struct tree **tree) {
    struct tree *t = *tree,
                *r = t->right,
                *rl = r->left;
    *tree = r;
    r->left = t;
    t->right = rl;
}

Без «двойного указателя» нам пришлось бы делать что-то более сложное, например, явно отслеживать родительский узел и определять, является ли это левой или правой веткой.

0 голосов
/ 17 апреля 2009

Если честно, я редко видел тройной указатель.

Я посмотрел на поиск кода Google, и есть некоторые примеры , но не очень хорошо освещающие. (см. ссылки в конце - ТАК не любит их)

Как уже упоминали другие, двойные указатели вы будете видеть время от времени. Простые одиночные указатели полезны, потому что они указывают на некоторый выделенный ресурс. Двойные указатели полезны, потому что вы можете передать их в функцию, и функция заполнит «простой» указатель для вас.

Звучит так, как будто вам нужно какое-то объяснение о том, что такое указатели и как они работают? Сначала вы должны это понять, если вы этого еще не сделали.

Но это отдельный вопрос (:

http://www.google.com/codesearch/p?hl=en#e_ObwTAVPyo/security/nss/lib/ckfw/capi/ckcapi.h&q=***%20lang:c&l=301

http://www.google.com/codesearch/p?hl=en#eVvq2YWVpsY/openssl-0.9.8e/crypto/ec/ec_mult.c&q=***%20lang:c&l=344

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...