2016-11-25 6 views
3

Я знаю, что статические массивы выложены смежно в памяти. Так, например, int T[10][10] в основном хранится так же, как int T[100]. я могу получить доступ к элементу индекса I, J многими способами, например:Доступ по указателю на многомерные статические массивы в C/C++

int T[10][10]; 
/*filling array*/ 
int i=3, j=7; 
int x = T[i][j]; 
//EDIT - old and wrong: int * ptr = T; 
int * ptr = &T[0][0]; 
int y = *(ptr + 10* i + j); 

С другой стороны, когда я создаю dynamicaly выделенный 2-мерный массив сам:

int ** T; 
T = malloc(10 * sizeof(int *)); 
for(i = 0; i < N; i++) 
    T[i] = malloc(10 * sizeof(int)); 

Мой массив содержит указатели на

очевидно, что я могу получить доступ к элементу этого массива с помощью:

int i=3, j=7; 
int x = *(*(T+i)+j); 

И теперь мой вопрос: почему и как он работает для статических массивов? Почему

int T[10][10]; 
/*filling array*/ 
int i=3, j=7; 
int x = *(*(T+i)+j); 

возвратных хорошее значение x, когда эта таблица не содержит указатели на массивы? *(*(T+i)) не должен иметь смысла там, на мой взгляд, конец, даже если он должен вернуть T[0][i], так как T указывает на первый элемент массива. Как компилятор интерпретирует это, * что-то другое, кроме разыменования здесь? Просветите меня.

+4

1) C не C++ не C. Это не компилируется как C++. 2) Ваше предпосылка неверно: 'int **' is ** not ** 2D-массив и не может указывать на один или не представлять его. 3) Выделите 2D-массив. Почему вы думаете, что то, что вы пытаетесь использовать для статического массива, также не верно для динамически распределенного 2D-массива? – Olaf

+0

попытка получить доступ к 2D-массиву через указатели - плохая идея. 2D-массивы хранятся по-разному на разных машинах. –

+1

@MarkYisri: Err no! Запись 'T [i] [j]' и '* (* (T + i) + j)' абсолютно идентична (по определению оператора '[]'). –

ответ

4

Для начала:

int * ptr = T; 

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

int * ptr = &t[0][0]; 

Этот вопрос действительно имеет отношение к вашему вопросу.

Как известно, при использовании в выражении массив попадает в указатель. Например:

char foo[10]; 

bar(foo); 

При использовании в выражении, как параметр функции, массив распадается на указатель базового типа. foo получает вас char *, здесь.

Однако, это ключевой момент: массив падает только на один уровень. Если массив является двумерным массивом, массив не будет разлагаться до базового значения, int в этом случае. Двухмерное ссылка на массив распадается на указатель на одномерный массив:

int T[10][10]; 
/*filling array*/ 
int i=3, j=7; 
int x = *(*(T+i)+j); 

последовательность шагов, которая происходит здесь:

  1. T распадается на указатель на массив из 10 целых чисел, или int (*)[10]

  2. Добавление i продвигает указатель на заданное значение. Указатель продвигается по размеру указательного элемента. Поскольку указатель указывает на array of 10 integers, указатель продвигается соответствующим образом. Если i было 2, указатель продвигается «двумя массивами из 10 целых чисел», свободно говоря.

  3. Оператор * принимает «указатель на массив из 10 целых чисел» и дает вам «массив из 10 целых чисел». Другими словами: от int (*)[10] до int [10].

  4. Поскольку результат используется в выражении, а именно в левом операнде + j, а левый операнд - тип массива, тип массива распадается на «указатель на int».

  5. j добавлен к результату и разыменован.

+0

'int * ptr = T;' должно быть равно 'int * ptr = & T [0] [0];' –

+0

@MarkYisri - вы ошибаетесь. Попробуйте сами: 't.C: 4: 14: error: не может преобразовать 'int (*) [10]' в 'int *' при инициализации int * ptr = T;'. –

+0

Я немного пропустил ответ. OP, похоже, спрашивает, почему одинаковый синтаксис работает как для двухмерного массива, так и для 'int **'.Что, по-видимому, является основной причиной, по которой новички (и некоторые не-новички) считают, что это тоже 2D-массив (они ошибочны). – Olaf

2

Why does

int T[10][10]; 
/*filling array*/ 
int i=3, j=7; 
int x = *(*(T+i)+j); 

return good value to x

Волшебное все в *(*(T+3)+7) (я преобразованы в буквенные значения).

T - это массив (размера 10) массивов (размером 10) от int.

Когда T используется в выражении, оно распадается на указатель на его первый элемент, поэтому оно распадается на «указатель на массивы (размером 10) от int».

Добавление целого числа к этому указателю будет продвигаться к четвертому элементу массива.

Так T+3 представляет собой указатель на массив 10 целых чисел, а именно четвертый такой массив в T.

*(T+3) indirects через этот указатель, чтобы дать L-значение типа «массив из 10 целых чисел».

Ah-ha! Это еще один массив, который используется в выражении - поэтому он распадается на указатель на его первый элемент! (Это бы не распада в sizeof, так sizeof(*(T+3)) будет обычно 40.)

(*(T+3) + 7) просто указывает на восемь элементов в массиве, и ...

*(*(T+3) + 7) является л-значение типа Int!

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