Понимание указателей С++ (когда они указывают на указатель)
Я думаю, что я хорошо понимаю ссылки и указатели. Вот что я (думаю, я) знаю:
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])? (что именно называется, экземпляр?)
Ответы
Ответ 1
Несколько комментариев:
*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), а другой - указателем на (указатель на node).
Это легко увидеть объявлениями переменных, которые, кстати, могут быть легко прочитаны справа налево:
char **char_ptrs
Чтение справа налево: char_ptrs
является указателем на указатель на char
Помещение * рядом с указателем правильно называется разыменованием этого указателя. Поскольку массивы технически не существуют, оператор [] на массивах также выполняет операцию разыменования: arr[i]
- это еще один способ записи *(arr + i)
. Чтобы правильно понять это, вы должны быть знакомы с арифметикой указателя.
Несколько последовательных * s: каждый разучивает результат выражения, в котором он работает. Поэтому при написании:
char c = **char_ptrs;
что происходит:
char_ptrs
является указателем на указатель на char. Выделение его один раз (для самого правого *) получает ваше значение, которое является указателем на char. Выделение этого значения (для самого левого *) дает вам свое значение по очереди, что означает char. В конце, c
содержит значение char, хранящееся в памяти, в том месте, где указывает указатель, на который указывает char_ptrs (другими словами, первый указатель в вашем массиве).
И наоборот, если вы пишете **char_ptrs = 'a';
, вы меняете значение в этой ячейке памяти.
Ответ 2
**
всего лишь *
дважды, поэтому указатель на указатель.
При установке рядом с типом *
связывается влево, а не вправо. Выражение new char *[50]
на самом деле new char* [50]
и создает массив из 50 char*
.
Ответ 3
Если вы считаете, что * нотация трудно читать, используйте 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.
Ответ 4
Заявления, сделанные в вашем первом фрагменте кода, верны.
char **char_ptrs = new char *[50];
... означает, что у вас есть массив из 50 char *
s.
Ваша оценка
char_ptrs[0] = new char[20];
node_ptrs[0] = new Node;
также корректно.
**
просто означает "указатель на указатель". Это не оператор.
Когда вы пишете
new char *[50];
... вы говорите "распределите память на 50 char *
s".
Ответ 5
Разъяснение первого раздела:
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;