2010-09-05 2 views
4

Это, наверное, глупый вопрос, но я не понимаю, почему это работает:Указатель на массив указателей понимания проблемы

int** test = new int*[7]; 

int x = 7; 
*(test+1) = &x; 

cout << (**(test+1)); 

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

(*test) // Now I have int* 
*((*test) + 1) // to access the first element. 

Где мое ошибочное мышление?

+1

Просто нести эстафету из других товарищей. Если просить об этом глупо, то не спрашивать в случае путаницы, это ошибка. – Chubsdad

ответ

9

Непонятно, что вы думаете, что создали указатель на массив из 7 int? Вы этого не сделали. Фактически вы создали массив указателей 7 для int. Таким образом, здесь нет «второго указателя», который указывает на массив. Существует только один указатель, указывающий на первый из 7 указателей (test).

И с *test вы получаете тот первый указатель, который вы еще не инициализировали.Если вы хотите добавить 1 в номер , то, вы бы добавили 1 в случайный адрес. Но если вы добавите 1 в test, вы получите указатель, указывающий на второй указатель массива. И отменяя , что вы получаете тот второй указатель, который вы сделал инициализировать.


То, что вы описали бы быть достигнуто с помощью другого синтаксиса

typedef int array[7]; 
array* test = new int[1][7]; 

// Note: "test" is a pointer to an array of int. 
// There are already 7 integers! You cannot make it 
// point to an int somehow. 
*(*test + 1) = 7; 

int *p1 = *test 
int i1 = *(p1 + 1); // i1 is 7, second element of the int[7] 

delete[] test; 

Без использования ЬурейеЕ, это выглядит следующим образом

int(*test)[7] = new int[1][7]; 

То есть, вы создали один- массив элементов, где тип элемента - это 7-элементный массив из int. new возвращает указатель на этот массив. Обратите внимание, что важна скобка: * имеет меньше приоритета, чем [7], так что в противном случае это было бы принято как массив из 7 указателей на целые числа.

+0

int (* test) [7] является указателем на int [7] прав? Как возможно, что одномерный массив содержит два измерения ... Я думаю, вы просто нашли другое, чего я не понимаю. Но я понимаю мою первоначальную проблему сейчас :) Повторное копирование для себя: работа с арифметикой указателей путем добавления смещения байта к адресу памяти. Неинициализированный указатель не указывает на что-либо еще, поэтому я не могу использовать на нем указательную математику. – Blub

+0

Я не смог найти какие-либо усовершенствованные учебные пособия в сети, которые касаются тонких изменений синтаксиса, таких как int (* test) [] и int * test []. У вас есть предложение, где я могу это прочитать? – Blub

+1

@Blub на самом деле не имеет двух размеров. Это как 'int * p = new int [1];'. Вы могли бы спросить: «Как мог скалярный дом массив?». Ответ заключается в том, что это наоборот: массив содержит скаляр (который указывает «p»), а в двухмерном массиве находится 1-мерный массив (на что мы указываем). –

0

Выражение *(test + 1) эквивалентно test[1], поэтому код можно переписать следующим образом:

int** test = new int*[7]; 

int x = 7; 
test[1] = &x; 

cout << *test[1]; 

С test[1] явно указывает на x, *test[1] является 7.

Просто, чтобы быть ясным, выражение **(test + 1) просто эквивалентно *(*(test + 1)), что в свою очередь эквивалентно *test[1].

+0

Я знаю это. Я не понимаю, почему тест [1] указывает на что-то разумное. В моем понимании тест - это указатель на указатель, который, в свою очередь, содержит кучу памяти. Пример: test-> array [0] [1] [2] [3] [..] Вызов теста [1] ничего не должен делать, я думал, что мне нужно будет вызвать массив [1]. – Blub

1

Пусть

test[0] = 0x12345678; // some pointer value 
test[1] = 0x23456789; // some pointer value 

* тест = 0x12345678;

* тест + 1 теперь 0x12345678 + 1 = 0x12345679;

* or dereference operator has higher precedence than binary +). Таким образом, выражение оценивается в этом порядке.

Однако то, что вы хотели, это проверить [0] = 0x23456789;

Таким образом, правильное выражение, чтобы добраться до test[1] = (*(test + 1))

arr[i] В общем это *(arr + i)

EDIT 2:

дал

int buf[10] = {0, 1, 2}; 
int *p = buf; 

ЬиЕ [0] == р [ 0] == * (p + 0), равным 0.

Обратите внимание, что отлично использовать синтаксис доступа к массиву с выражением lvalue p, даже если он не является типом массива. Фактически выражение buf[0] внутренне переводится компилятором на *(buf + 0).

+0

@chubsdad: Пожалуйста, см. Мой комментарий к Марсело. Я не понимаю, почему я должен иметь возможность проводить тесты разыменования, как это был массив с []. В моем понимании тест не является массивом, это указатель. Массив находится внутри второго указателя. – Blub

+0

@Blub: для данного «p», такого как «T * p;», где «T» является непустым типом и интегральным выражением «i», выражение «p [i]» в основном эквивалентно ' * (P + I) '. Компилятор не ограничивает этот синтаксис только для статически известных объектов типа массива. Тот факт, что 'p [i]' в свою очередь также является указателем на массив, не изменяет основное правило 'p [i] = * (p + i)' – Chubsdad

11

int ** test = new int * [7];

+------++------++------++------++------++------++------+ 
| int* || int* || int* || int* || int* || int* || int* | 
+------++------++------++------++------++------++------+ 

является эквивалентом массива с Int указателей:

int* test[0] 
int* test[1] 
... 
int* test[6] 

это

int x = 7; 
*(test+1) = &x; 

+------++------++------++------++------++------++------+ 
| int* || &x || int* || int* || int* || int* || int* | 
+------++------++------++------++------++------++------+ 

такая же, как

int x = 7; 
test[1] = &x 

так что теперь один из указателей в ваш оригинальный массив указывает на расположение в памяти х

cout << (**(test+1)); 

такое же, как

cout << *test[1] 

который является значение х (== 7) и которые оба теста [1] и & х пункт.

+1

+1 для искусства ASCII – Chubsdad

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