2010-11-11 8 views
0

Можно создать дубликат:
How do pointer to pointers work in C?Необходимость указатель на указатель

Привет Все,

У меня есть очень простой вопрос: Что такое использование двойных указателей в C или C++?

Может кто-нибудь объяснить мне, что с некоторыми примерами, пожалуйста.

Спасибо,
Сен

+0

«двойной указатель», вы имеете в виду 'double *' или 'something **'? –

+0

Я думаю, что он имеет в виду указатель на указатель, но да, не сформулированный хорошо. –

+0

Я предполагаю, что он означает указатель на указатель – CashCow

ответ

4

Если вы хотите, чтобы изменить то, что исходный указатель указует в вызов функции вам нужно **. Это связано с тем, что, когда вы передаете указатель, вы передаете копию указателя, т. Е. Если вы изменяете то, что указывает указатель внутри функции (т. Е. Меняя значение самого указателя), оно отражается в копии, но не оригинал (отличный от изменения того, на что указывает исходный указатель, вместо этого указывает на совершенно новый объект).

Кроме того, к многомерным массивам можно получить указатель на указатель (указатель на указатель ... до бесконечности).

+0

Можете ли вы дать мне сценарий, где я могу реализовать логику только с помощью двойного указателя, а не с помощью одного указателя? – Sen

0

Одна вещь, которая приходит мне в голову сразу же -
Когда вы используете «pass by pointer» для передачи указателя на функцию, в функцию передается только копия указателя. Мы можем сказать «pass by pointer», это фактически передача указателя по значению. В большинстве случаев это не представляет проблемы. Но возникает проблема, когда вы изменяете указатель внутри функции. Вместо изменения переменной вы изменяете только копию указателя, а исходный указатель остается неизмененным, то есть он все еще указывает на старую переменную

+0

wow - кто-то решает проголосовать за действительный ответ, даже не давая объяснения! Кстати, есть ли какой-нибудь способ узнать, какой пользователь проголосовал за его/ее ответ? – anirvan

2

Обычный указатель данных является адресом некоторой переменной.

Указатели сами по себе являются переменными и, следовательно, имеют адреса, которые поэтому являются указателями на указатели.

Указатели используются больше в C, чем в C++, потому что в C++ существует альтернативный синтаксис с использованием ссылок, а также тот факт, что указатели много раз обернуты в классы и не используются совершенно как напрямую.

В следующем примере вы можете удалить структуру в указателе, а также установить указатель, переданный в NULL.

void FreeMyStruct(struct MyStruct ** ptr) 
{ 
    free((*ptr)->resource); 
    free(*ptr); 
    *ptr = NULL; 
} 

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

1

En Пример из стандарта C:

long int strtol(
       const char * restrict nptr, 
       char ** restrict endptr, 
       int base); 

... Указатель на строку ц конечного хранится в объекте, на который указывает endptr, при условии, что endptr не является нулевым указателем.

Если последовательность предметов пуста или не имеет ожидаемой формы, преобразование не выполняется ; значение nptr сохраняется в объекте, на который указывает endptr, при условии, что , что endptr не является нулевым указателем.

1

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

Типичным примером может быть случай, когда функции необходимо перераспределить память для некоторой структуры данных. В этом примере мы хотим передать массив символов в функцию, которая добавляет к ней один символ. Функция должна перераспределять память для нового (расширенного) массива, что означает, что ее указатель должен указывать на новое место в памяти - это значение нужно изменить. Обратите внимание на линию, где * р (разыменованный указатель на указатель) присваивается значение:

#include <iostream> 
using namespace std; 

void append_char(char** pp, char ch) 
{ 
    // copy of pp is passed here 

    if(pp) 
    { 
     if(*pp) 
     { 
      // pointer is already pointing to formed array of characters 

      // 1. allocate memory for a new (extended) array 
      int nLen = strlen(*pp); 
      // one place for ch and one for zero-termination 
      int nNewLen = nLen + 2; 
      char* pNewStr = new char[nNewLen]; 

      // 2. copy existing array into a new one 
      strcpy(pNewStr, (const char*)*pp); 

      // 3. append new character 
      pNewStr[nNewLen - 2] = ch; 
      pNewStr[nNewLen - 1] = '\0'; 

      // 4. free memory of old array 
      delete[] *pp; 

      // 5. assign new pointer's value 
      *pp = pNewStr; 
     } 
     else 
     { 
      // pointer is NULL - passed character will be the first in a new array 

      // 1. allocate memory, fill the array and assign new pointer's value 
      *pp = new char[2];   
      (*pp)[0] = ch; 
      (*pp)[1] = '\0'; 
     } 
    } 
} 

int main() 
{ 
    char* p = new char[3]; 
    p[0] = 'A'; 
    p[1] = 'B'; 
    p[2] = '\0'; 

    cout << p << endl; 

    append_char(&p, 'C'); 

    cout << p << endl; 

    delete[] p; 

    return 0; 
} 

Я использовал строку C-стиль здесь, как это общий пример управления памятью. В коде на C++ попробуйте избежать строк C и использовать операторы слияния C++.

Смежные вопросы