Карта памяти для двумерного массива на С - PullRequest
12 голосов
/ 13 июля 2011

Как вы думаете, что это обсуждение о карте памяти двумерного массива является правильным? Особенно это фото? Можете ли вы объяснить теорию?

Предположим, мы объявляем двумерный массив в C следующим образом:

int arr[3][3]={10, 20, 30, 40, 50, 60, 70, 80, 90};

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

enter image description here

Теперь я написал следующий код для проверки этой теории:

#include <stdio.h>

main()
{
    int arr[3][3]={10, 20, 30, 40, 50, 60, 70, 80, 90};
    printf("      arr==%d\n", arr);
    printf("  &arr[0]==%d\n", &arr[0]);
    printf("   arr[0]==%d\n", arr[0]);
    printf("&arr[0][0]=%d\n", &arr[0][0]);
    printf(" arr[0][0]=%d\n", arr[0][0]);
}
/*
Output:
========
      arr ==1245028
  &arr[0] ==1245028
   arr[0] ==1245028
&arr[0][0]==1245028
 arr[0][0]==10
Press any key to continue...
*/

Почему первые 4 выхода одинаковые?

Ответы [ 4 ]

13 голосов
/ 13 июля 2011

Смотрите мой вопрос здесь.

Это не тот способ, которым вы получаете доступ к информации о двумерных массивах. На самом деле вы можете думать о них как о 1-й, где вы умножаете и добавляете индексы особым образом.

, например

int x[10] = {0,1,2,3,4,5,6,7,8,9};
int y[2][5] = {{0,1,2,3,4},{5,6,7,8,9}};

Они точно отформатированы в памяти и выглядят так:

|0|1|2|3|4|5|6|7|8|9|

Таким образом, чтобы получить элемент 8, вы можете запросить x[8] или y[1][3].

Для второго способа вы можете думать об этом как (1 * 5) + 3.

Вот почему ваши первые 4 были одинаковыми. У вас есть:

  • arr: это адрес начала массива
  • arr[0]: это адрес начала первого подмассива, который совпадает с началом всего массива
  • &arr[0][0]: это адрес первого элемента первого подмассива, а также начало всего массива
  • arr[0][0]: это значение, хранящееся в первом элементе первого подмассива.
8 голосов
/ 13 июля 2011

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

Многомерный массив - это просто обычный плоскиймассив (в памяти) с дополнительным синтетическим сахаром для доступа.Таким образом, хотя можно получить указатель из arr [i], нет дополнительной «переменной», чтобы просто сохранить это, как это происходит в вашем изображении.

Чтобы исправить изображение, удалите части с помощьюarr[0], arr[1]... и измените значение arr на 1245039 (аналогично & arr [0] [0]).

0 голосов
/ 13 июля 2011

ну, насколько я помню, в C ++ (и я думаю, что C, хотя это не моя сильная сторона), 2D-массив, объявленный как Values[][], обычно (не знаю, если всегда) реализован как массив C- массивы стилей. однако, когда вы объявляете их в стеке (например, в локальной переменной), я считаю, что форматирование памяти отличается.

так, когда вы объявляете локальную переменную, все раскладывается , как если бы это был просто 1d массив, и вы получаете такие вещи, которые вы можете фактически привести к указателю, а затем получить доступ как 1D массив. (!) Однако, он по-прежнему распознается так же, как обычный 2D-массив в пределах области объявления, и, возможно, если вы передадите параметр, который объявлен с нотацией [].

но если вы выделите одну из них в куче (например, глобальную или статическую или через новую), история будет другой. теперь память распределяется как фактический массив массивов, и поэтому фактические результаты областей памяти, которые вы индексируете, если вы преобразуете в одномерный массив и индекс, теперь вместо этого будут указателями.

Я подтвердил свой отзыв, выполнив следующее: я создал int HeapArray[3][3]; как глобальный и int StackArray[3][3]; как локальный (оба с инициализаторами { { 10, 20, 30 }, {40, 50, 60}, {70, 80, 90 } }). внутри своей функции я приводил их обоих к указателю типа int, int* ptrHeapArray = (int*)HeapArray; и int* ptrStackArray = (int*)StackArray;, а затем просматривал возвращаемое значение 0-го элемента каждого.

[править: упс, я их перевернул; исправлено сейчас]

ptrStackArray[0] было равно 10

ptrHeapArray[0] был равен указателю на int [3];

так что я думаю, что мой ограниченный отзыв точен. :) надеюсь, это поможет!

0 голосов
/ 13 июля 2011

Первые четыре выхода одинаковы для получения адреса первого элемента в массиве, т.е. & arr [0] [0]. Последний вывод - это его содержимое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...