В C, что означает объявление переменной с двумя звездочками (**)? - PullRequest
33 голосов
/ 01 декабря 2010

Я работаю с C, и я немного ржавый. Я знаю, что * имеет три применения:

  1. Объявление указателя.
  2. Разыменование указателя.
  3. Умножение

Однако, что это значит, когда перед объявлением переменной стоят две звездочки (**):

char **aPointer = ...

Спасибо

Scott

Ответы [ 5 ]

32 голосов
/ 01 декабря 2010

Он объявляет указатель на char указатель .

Использование такого указателя будет означать:

void setCharPointerToX(char ** character) {
   *character = "x"; //using the dereference operator (*) to get the value that character points to (in this case a char pointer
}
char *y;
setCharPointerToX(&y); //using the address-of (&) operator here
printf("%s", y); //x

Вот еще один пример:

char *original = "awesomeness";
char **pointer_to_original = &original;
(*pointer_to_original) = "is awesome";
printf("%s", original); //is awesome

Использование ** с массивами:

char** array = malloc(sizeof(*array) * 2); //2 elements

(*array) = "Hey"; //equivalent to array[0]
*(array + 1) = "There";  //array[1]

printf("%s", array[1]); //outputs There

Оператор [] для массивов по существу указывает арифметику указателя на передний указатель, поэтому способ вычисления array[1] будет следующим:

array[1] == *(array + 1);

Это одна из причин, по которой индексы массивов начинаются с 0, потому что:

array[0] == *(array + 0) == *(array);
28 голосов
/ 01 декабря 2010

C и C ++ позволяют использовать указатели, которые указывают на указатели (скажем, пять раз быстрее).Посмотрите на следующий код:

char a;
char *b;
char **c;

a = 'Z';
b = &a; // read as "address of a"
c = &b; // read as "address of b"

Переменная a содержит символ.Переменная b указывает на место в памяти, которое содержит символ.Переменная c указывает на место в памяти, которое содержит указатель, указывающее на место в памяти, которое содержит символ.

Предположим, что переменная a хранит свои данные по адресу 1000 (ВНИМАНИЕ: примерместа памяти полностью составлены).Предположим, что переменная b хранит свои данные по адресу 2000, а переменная c хранит свои данные по адресу 3000. Учитывая все это, мы имеем следующую схему памяти:

MEMORY LOCATION 1000 (variable a): 'Z'
MEMORY LOCATION 2000 (variable b): 1000 <--- points to memory location 1000
MEMORY LOCATION 3000 (variable c): 2000 <--- points to memory location 2000
4 голосов
/ 01 декабря 2010

Это означает, что aPointer указывает на указатель на символ.

Итак

aPointer: pointer to char pointer

*aPointer :pointer to char

**aPointer: char

Примером его использования является создание динамического массива из строк c

char **aPointer = (char**) malloc(num_strings);

aPointer дает вам символ , который может использоваться для представления строки с нулевым символом в конце.

*aPointer = (char*)malloc( string_len + 1); //aPointer[0]
*(aPointer + 1) = (char*)malloc( string_len + 1); //aPointer[1]
2 голосов
/ 01 декабря 2010

Он объявляет aPointer как указатель на указатель на символ.

Объявления в C сосредоточены вокруг типов выражений ;общее название для этого - «декларация имитирует использование».В качестве простого примера, предположим, что у нас есть указатель на int с именем p, и мы хотим получить доступ к целочисленному значению, на которое он в данный момент указывает.Мы разыменовываем указатель с унарным оператором *, например:

x = *p;

Тип выражения *p равен int,поэтому объявление переменной-указателя p равно

int *p;

В этом случае aPointer является указателем на указатель на символ;если мы хотим получить значение символа, на которое он в данный момент указывает, нам нужно было бы разыменовать его дважды:

c = **aPointer;

Итак, согласно логике выше, объявление переменной указателя aPointer равно

char **aPointer;

, поскольку тип выражения **aPointer равен char.

Зачем вам указатель на указатель?Это проявляется в нескольких контекстах:

  • Вы хотите, чтобы функция изменила значение указателя;одним примером является библиотечная функция strtol, чей прототип (по состоянию на C99) равен
    long strtol(const char * restrict str, char ** restrict ptr, int base);  
    
    Второй аргумент - указатель на указатель на char;когда вы вызываете strtol, вы передаете адрес указателя на char в качестве второго аргумента, и после вызова он будет указывать на первый символ в строке, которая не была преобразована.

  • Помните, что в большинстве случаев выражение типа «массив N-элементов из T» неявно преобразуется в тип «указатель на T», а его значением является адрес первого элементамассив.Если «T» - это «указатель на символ», то выражение типа «массив N-элементов указателя на символ» будет преобразовано в «указатель на указатель на символ».Например:
    
        void foo(char **arr)
        {
          size_t i = 0;
          for (i = 0; arr[i] != NULL; i++)
            printf("%s\n", arr[i]);
        }
    
        void bar(void)
        {
          char *ptrs[N] = {"foo", "bar", "bletch", NULL};
          foo(ptrs); // ptrs decays from char *[N] to char **
        }
    
    

  • Вы хотите динамически выделить многомерный массив:
    
    #define ROWS ...
    #define COLS ...
    ...
    char **arr = malloc(sizeof *arr * ROWS);
    if (arr)
    {
      size_t i;
      for (i = 0; i < ROWS; i++)
      {
        arr[i] = malloc(sizeof *arr[i] * COLS);
        if (arr[i])
        {
          size_t j;
          for (j = 0; j < COLS; j++)
          {
            arr[i][j] = ...;
          }
        }
      }
    }
    
1 голос
/ 01 декабря 2010

Это указатель на указатель на char.

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