2013-03-23 2 views
3

Я отвечал на этот вопрос question, но когда я протестировал следующий код , я смутился.Почему int ** ptr указывает на тот же адрес, что и int arr [3] [3] при доступе к ptr [i] [j]?

#include <iostream> 

using namespace std; 

int main() 
{ 
     int **ptr; 
     int arr[3][3]; 
     ptr =(int **) arr; 
     for (int i=0;i<3;i++){ 
       for (int j=0;j<3;j++){ 
         cout << &arr[i][j] << " =? "; 
         cout << &(ptr[i][j]) << endl; 
       } 

     } 


     return 0; 
} 

Но я получаю этот поток вывода:

0x7fff5700279c =? 0 
0x7fff570027a0 =? 0x4 
0x7fff570027a4 =? 0x8 
0x7fff570027a8 =? 0 
0x7fff570027ac =? 0x4 
0x7fff570027b0 =? 0x8 
0x7fff570027b4 =? 0 
0x7fff570027b8 =? 0x4 
0x7fff570027bc =? 0x8 

Почему они не то же самое?

+2

Потому что вы использовали злую личность: 'ptr = (int **) arr;' 'ptr' должен быть объявлен' int (* ptr) [3]; '. –

+0

См. Http://stackoverflow.com/questions/3515045 –

+2

'int *' и 'int []' совместимы, но вы сделали общее, но неправильное обобщение, когда считали, что означает, что 'int **' совместим с ' ИНТ [] [] '. Вот почему вам пришлось добавить бросок, броски опасны, избегайте там, где это возможно. – john

ответ

10

int **ptr и int arr[3][3] различны, так как:

----------------------------------- 
| C |   Maths   | 
----------------------------------- 
| ptr + 1 | ptr + sizeof(int*)  | 
----------------------------------- 
| arr + 1 | arr + 3 * sizeof(int*) | 
----------------------------------- 

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

int (*ptr)[3] = arr; 

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

1

int ** - указатель на указатель на int. Это означает, что он ссылается на массив указателей. Однако int [x] [y] - это массив целых чисел x по y. Это единый блок памяти, размещенный в x строк столбцов y (если вы так думаете об этом.

Для достижения того, что вы хотите, вам нужно будет собирать адреса столбцов и хранить их в ряды ИНТ ** указатель

int arry[3][3]; 
int** ptr = malloc(sizeof(int*) * 3); 

for(int i = 0; i < 3; i++) 
    ptr[i] = arry[i]; 

for(int i = 0; i < 3; i++) 
    for(int j = 0; j < 3; j++) 
     printf("%d -> %d\n", arry[i][j], ptr[i][j]; 

free(ptr); 
12
ptr =(int **) arr; 

это очень плохо -. она включает в себя reinterpret_cast и приводит к неопределенному поведению двух типов. - int[3][3] и int** - совершенно несовместимы с точки зрения памяти макс.

3-на-3 2D массив представляет собой непрерывный блок памяти, который выглядит следующим образом:

0,0 0,1 0,2 1,0 1,1 1,2 2,0 2,1 2,2 
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ 
│ int │ int │ int │ int │ int │ int │ int │ int │ int │ 
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ 

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

┌─────┐ 
│  │ // The int** 
└──╂──┘ 
    ┃ 
    ▼ 
┌─────┬─────┬┄ 
│  │  │ // An array of int* 
└──╂──┴──╂──┴┄ 
    ┃  ┗━━━━━━━━━━┓ 
    ▼    ▼ 
┌─────┬─────┬┄ ┌─────┬─────┬┄ 
│ int │ int │ │ int │ int │ // Arrays of ints 
└─────┴─────┴┄ └─────┴─────┴┄ 
    0,0 0,1  1,0 1,1 

Это предполагает два уровня косвенности. Тип 2D-массива не имеет массива указателей, которые нужно пройти. Кроме того, массивы int s в этом случае int** не обязательно должны быть смежными.

Так что подумайте, когда сделаете ptr[0], например. Каков тип выражения? Поскольку ptr является int**, тип ptr[0] является int*. Однако, что такое на самом деле на месте ptr[0]? Не указатель! Вместо этого существует массив из int.

+0

+1 для ваших диаграмм. – md5

+3

@ Кириленко Спасибо! [Графические символы] (http://en.wikipedia.org/wiki/Box-drawing_character) являются лучшими! –

+0

Удивительные коробки, полный ответ. +1: D – s3rius

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