C программирование макета памяти 2D массива - PullRequest
2 голосов
/ 17 марта 2020

Рассмотрим код c, приведенный ниже.

#include <stdio.h>
int main(){
   unsigned int x[4][3] = {{1, 2, 3}, {4, 5, 6},
                       {7, 8, 9}, {10, 11, 12}};
   printf("%u, %u, %u", x+3, *(x+3), *(x+2)+3);
   printf("\n%u, %u, %u", x,&x,*x);
   return 0;
}

Теперь каждый оператор printf печатает те же значения, как указано ниже.

6356724, 6356724, 6356724
6356688, 6356688, 6356688
Process returned 0 (0x0)   execution time : 0.128 s
Press any key to continue.

Я хотел знать, как результат одинаков в каждом printf утверждении. Это мое понимание структуры памяти 2-D массива. 2-D array memory layout

Теперь я считаю, что x + 3 относится к базовому адресу (размер x + 3 * требуется для арифметики указателя c) = 24 и * (x +3) = * (24) = 2036, но это не тот случай, когда первый оператор printf печатает 2036, 2036 2036. Я хотел визуально понять, как именно организован 2-D массив.

Ответы [ 2 ]

4 голосов
/ 17 марта 2020

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

Почему x, &x и *x напечатаны одинаково? Это связано с тем, что сам массив, его первый элемент (и если это двумерный массив, первый элемент его первого элемента, который сам по себе является одномерным массивом), имеют одинаковый адрес.

Итак:

  • &x - указатель на массив
  • x - сам массив, который распадается на указатель его первого элемента
  • *x - это первый элемент массива, который сам является массивом (1, 2, 3}, поэтому он распадается на указатель его первого элемента

Все эти указатели имеют разные типы, но указывают на один и тот же адрес.

То же самое происходит с x+3 и *(x+3). Сначала x затухает до указателя, затем выполняется арифметика указателя c. Скажите y = x + 3, поэтому y и *y указывают на тот же адрес, что и x и * x` (см. Выше).

А как насчет *(x+2)+3? Ну, *(x + 2) сам по себе является массивом из 3 элементов. Таким образом, *(x+2)+3 указывает на один элемент после конца массива *(x + 2). Этот несуществующий элемент имеет, тем не менее, адрес , и он совпадает с адресом первого элемента массива *(x + 3), поскольку *(x + 2) и *(x + 3) расположены рядом друг с другом. в массиве x.

2 голосов
/ 17 марта 2020

Я попытаюсь объяснить с точки зрения непрофессионала.

Предположим, что базовый адрес равен 3000, и предположим, что целое число занимает 4 байта.

Учитывая ваш 2-D массив, вот как мы визуализируем 2-D массив в памяти:

         0                       1                2
     --------------------------------------------------
  0 |   1                |    2           |   3          |
    | 3000/3001/3002/3003| 3004/05/06/07  | 3008/09/10/11|
    |___________________ |________________|______________|                      
  1 |    4               |    5           |   6          |
    |   3012             |    3016        |   3020       |
    |____________________|________________|______________|                      
  2 |    7               |    8           |   9          |
    |    3024            |    3028        |   3032       |
    |____________________|________________|______________|                      
  3 |     10             |   11           |   12         |
    |    3036            |   3040         |   3044       |
    |                    |                |              |
    ------------------------------------------------------

Теперь вы должны знать, как на самом деле хранится 2-D массив, как 1- Массив D в памяти:

index    0       1       2      3     4      5     6      7      8      9      10    11  

        ---------------------------------------------------------------------------------
       |  1   |  2   |  3   |  4   |  5   | 6   |  7   |  8   |  9   |  10  |  11 |  12  |       
       |      |      |      |      |      |     |      |      |      |      |     |      |
add.   |3000__|_3004_|_3008_|_3012_|_3016_|_3020|3024__|_3028_|3032__|_3036_|_3040|3044_ |

Теперь ваш код говорит:

printf("%u, %u, %u", x+3, *(x+3), *(x+2)+3);

(i) x + 3

Здесь x - ваш базовый адрес, который равен 3000 (предполагается), а +3 означает 3-й ряд. Поскольку после этого ничего нет, т. Е. Х + 3, мы узнаем адрес первого элемента 3-й строки.

= 3000 + 36 = 3036

(см. Первую визуализацию 2D-массива, которую мы видим)

(ii) * (x + 3)

Это то же самое, что и x + 3, то есть мы должны найти адрес первого элемента третьей строки. Я говорю первый элемент, потому что если что-то было упомянуто после * (x + 3) + «что-то», тогда мы были бы заинтересованы в его поиске.

= 3000 + 36 = 3036.

(см. Первую визуализацию 2D-массива, которую мы видим)

(iii) * (x + 2) + 3

Просто для понимания , давайте разберем это на две части.

Во-первых, * (x + 2): как мы видели в двух предыдущих частях, * (x + 2) говорит, что «я начал с базового адреса, теперь дайте мне адрес первого элемент 2-й строки. Итак, мы достигаем элемента со значением 7 и адресом 3024 . (см. визуализацию 2D-массива, которую мы видим, первую)

Во-вторых, +3 как в * (x + 2) +3 означает, что, поскольку мы достигли элемента со значением 7 и адресом 3024, теперь видит / переходит к третьему элементу после элемента со значением 7 и адресом 3024 (где мы сейчас находимся). Итак, мы перемещаем прошедшие / просвечивающие элементы со значениями 8 и 9 с адресами 3028 и 3032 соответственно и достигаем / приземляемся на элементе со значением 10 и адресом

= 3000 + 36 = 3036

(см. Первую визуализацию 2D-массива, которую мы видим)



Для вашего второго кода:

 printf("\n%u, %u, %u", x,&x,*x);

I go с @ n. «Местоимениями» m. ответ.

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