Понимание указателей C ++ (когда они указывают на указатель) - PullRequest
11 голосов
/ 12 мая 2010

Мне кажется, я хорошо понимаю ссылки и указатели. Вот что я (думаю, я) знаю:

int i = 5; //i is a primitive type, the value is 5, i do not know the address.
int *ptr;  //a pointer to an int. i have no way if knowing the value yet.
ptr = &i;  //now i have an address for the value of i (called ptr)
*ptr = 10; //Go to the value in ptr, use it to find a location and store 10 there

Пожалуйста, не стесняйтесь комментировать или исправлять эти заявления.

Теперь я пытаюсь перейти на массивы указателей. Вот что я не знаю:

char **char_ptrs = new char *[50];
Node **node_ptrs = new Node *[50];

Насколько я понимаю, у меня есть 2 массива указателей, один набор указателей на символы и один на узлы. Поэтому, если бы я хотел установить значения, я бы сделал что-то вроде этого:

char_ptrs[0] = new char[20];
node_ptrs[0] = new Node;

Теперь у меня есть указатель, в позиции 0 моего массива, в каждом соответствующем массиве. Опять же, не стесняйтесь комментировать здесь, если я запутался.

Итак, что делает оператор **? Аналогично, что помещает один * рядом с созданием экземпляра (* [50])? (как это называется, инстанцирование?)

Ответы [ 5 ]

7 голосов
/ 12 мая 2010

Несколько комментариев:

*ptr = 10; // Doesn't need to "go get" the value. Just overwrites it.

Также:

char **char_ptrs = new char *[50];
Node **node_ptrs = new Node *[50];

Проще думать, что у вас есть два массива. Однако, технически (и что касается компилятора) у вас есть два указателя . Один из них - указатель на (указатель на символ), а другой - указатель на (указатель на узел).

Это легко увидеть по объявлениям ваших переменных, которые, кстати, легче всего прочитать справа налево:

char **char_ptrs

Чтение справа налево: char_ptrs - указатель на указатель на char

Помещение * рядом с указателем правильно называется разыменованием этого указателя. Поскольку массивы технически не существуют, оператор [] для массивов также является операцией разыменования: arr[i] - это еще один способ записи *(arr + i). Чтобы правильно понять это, вы должны быть знакомы с арифметикой указателя .

Более одного последовательного * s: каждый разыменовывает результат выражения, с которым он работает. Так что при написании:

char c = **char_ptrs;

что происходит:

char_ptrs - указатель на указатель на символ. Разыменование его один раз (для самого правого *) возвращает вам его значение, которое является указателем на символ. Разыменование этого значения (для самого левого *) дает вам свое собственное значение, которое является символом. В конце c содержит значение символа, хранящегося в памяти в том месте, куда указывает указатель, на который указывает char_ptrs (другими словами, первый указатель в вашем массиве).

И наоборот, если вы пишете **char_ptrs = 'a';, то вы меняете значение в этой ячейке памяти.

6 голосов
/ 12 мая 2010

** - это просто * дважды, поэтому указатель на указатель.

Когда ставится рядом с типом, * связывается влево, а не вправо. Сказать new char *[50] на самом деле new char* [50] и создать массив из 50 char*.

3 голосов
/ 12 мая 2010

Если вам трудно читать * нотацию, используйте typedef, чтобы облегчить чтение вашего кода.

typedef char*      CharPtr;
typedef CharPtr*   CharPtrPtr;
// Alternative to the line above
// typedef char**     CharPtrPtr;

// When you call new. You get a ptr to the type you are newing.
// new int returns an intPtr. new char returns a charPtr
CharPtrPtr char_ptrs = new CharPtr[50];

// So new CharPtr returns a CharPtrPtr
// In this case we return a pointer to contigious
// chunk of memory large enough to hold 50 CharPtr objects.
2 голосов
/ 12 мая 2010

Все утверждения, сделанные в вашем первом фрагменте кода, верны.

char **char_ptrs = new char *[50];

... означает, что у вас есть массив 50 char * с.

Ваша оценка

char_ptrs[0] = new char[20];
node_ptrs[0] = new Node;

тоже правильно.

** просто означает «указатель на указатель». Это не оператор.

Когда вы пишете

new char *[50];

... вы говорите: «выделите хранилище для 50 char * с».

0 голосов
/ 12 мая 2010

Уточнение первого раздела:

int i = 5; // i is a primitive type, the value is 5, the address is retrieved via &i.
int *ptr;  // an unassigned pointer to an int
ptr = &i;  // ptr now point to the address of variable i
*ptr = 10; // access (dereference) the value through ptr and change it to 10 (same as i=10)

Нет ** оператора, только * оператор. Как и другие, ** объявляет указатель на указатель. Поскольку вы объявляете массивы указателей, а указатели объявляются с помощью оператора *, вы должны объявить их как таковые при выделении памяти для них с помощью new. Следовательно, у вас есть:

char **char_ptrs = new char *[50]; // allocates memory for 50 contiguous char* (pointers)
Node **node_ptrs = new Node *[50]; // allocates memory for 50 contiguous Node* (pointers)

Указатели на указатели не обязательно должны объявлять массивы. Вы также можете иметь обычный указатель, на который указывает другой указатель, например:

char i = 'p';
char *myptr = &i;
char **mysecondptr = &myptr;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...