функция — C ++ многомерный массив и указатели на таблицу указателей

Вот эта вещь.
Я могу полностью понять концепцию многомерного массива (давайте на некоторое время рассмотрим 2D), созданного указателем на массив с указателями и так далее …

Мы делаем что-то вроде этого:

// we can use dynamically defined size n and m
int n = 3, m = 5 ;
int **T = new int *[n];
for (int i = 0 ; i < n ; ++i)
T[i] = new int[m];

То, что мы получили, это:
(Проверь если я здесь)

  • 3 блока памяти по 5 штук, размещенных где-то в памяти
  • Один дополнительный блок памяти того же размера, что и количество блоков в целых числах (число строк). Этот блок представляет собой массив указателей (обычно 4 байта для указателя типа int) на эти строки int.
  • Больше всего нас интересует — это тип T (** T) — указатель на указатель.
    Это именно указатель на массив указателей, потому что в C ++ массив на самом деле является указателем, указывающим на блок памяти, поэтому t [] или t [0] означает * t, а t [x] означает * (t + Икс).

Теперь проблема в том, когда мы делаем что-то вроде этого:

int n = 3, m = 5 ;
int T[n][m] ;

То, что у нас есть, это не то, что мы могли бы делать, что я показывал раньше.
Мы получаем что-то странное. Что такое Т? При печати T мы получаем то же значение, что и T [0].
Похоже, мы зарезервировали блок размером n * m без дополнительного массива указателей на строки.

У меня вопрос: запоминает ли компилятор размерность массива и количество строк и столбцов? И когда спрашивает T [i] [j], он фактически запрашивает * (T + i * n + j), так что этот n где-то хранится?
Проблема в том, что мы пытаемся передать эту вещь (T) в функцию. Я не знаю почему, но если n и m были константами, то можно передать T в качестве указателя на этот массив для работы, как в этой программе:

#include <stdio.h>
const int n = 3, m = 4 ; // this is constant!
void add_5(int K[][m])
{
for (int i = 0 ; i < n ; ++i)
for (int j = 0 ; j < m ; j++)
K[i][j] += 5 ;
}
int main()
{
// n x m array the most straight forward method
int T[n][m] ;
for (int i = 0 ; i < n ; ++i)
for (int j = 0 ; j < m ; ++j)
T[i][j] = i*m + j ;

for (int i = 0 ; i < n ; ++i)
{
for (int j = 0 ; j < m ; j++)
printf("%d ",T[i][j]) ;
printf("\n") ;
}
printf("\n") ;

// adding 5 to all cells
add_5(T) ;
printf("it worked!!\n") ;

for (int i = 0 ; i < n ; ++i)
{
for (int j = 0 ; j < m ; j++)
printf("%d ",T[i][j]) ;
printf("\n") ;
}

int ss ;
scanf("%d",&ss) ;
}

Но если n и m не постоянны, мы не можем.
Поэтому мне нужно передать динамически созданный указатель многомерного массива в функцию без выделения памяти для этого вручную.
Как это сделать?

0

Решение

в C ++ массив фактически является указателем, указывающим на блок памяти

Точно нет. Массив полностью отделен от указателя. Причина, по которой у вас может возникнуть эта путаница, заключается в стандартном преобразовании, называемом преобразованием массива в указатель. Рассматривать:

int arr[10];

Переменная arr обозначает массив. Это не указатель вообще. Так уж сложилось, что во многих случаях имя массива будет преобразовано в указатель на его первый элемент. То есть преобразование превращает его в int*,

int T[n][m] ;

В этом случае, T это «массив n массив m ints «. Вы упомянули, что печать как T а также T[0] дать тот же результат, и это связано с преобразованием массива в указатель.

  1. Выражение T может быть преобразован в указатель на первый элемент; то есть int (*)[m], потому что первый элемент T сам по себе массив с m элементы.

  2. Выражение T[0] может быть преобразован в указатель на первый элемент первого подмассива. Таким образом, вы получаете указатель на элемент T[0][0] типа int*,

Эти указатели содержат один и тот же адрес из-за способа размещения массива в памяти. Адрес, с которого начинается массив, совпадает с адресом первого элемента этого массива. Однако указатели не ведут себя одинаково. Если вы увеличиваете указатель в результате T, вы двигаетесь к следующему подмассиву. Если вы увеличиваете указатель в результате T[0]переходите к следующему int,

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

  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 │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘

Принимая во внимание, что если вы динамически распределяете трехмерный массив размером 3 на 3:

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

компилятор запоминает размерность массива и количество строк и столбцов?

Да, если у вас есть переменная с типом массива, размер массива является частью этого типа. Компилятор всегда знает тип переменной.

И когда спрашивает T [i] [j], он фактически запрашивает * (T + i * n + j), так что этот n где-то хранится?

Выражение T[i][j] эквивалентно *(*(T + i) + j), Давайте поймем, что это делает. Во-первых, преобразование массива в указатель подвергается T, давая int (*)[m], Затем мы добавим i к этому, чтобы двигаться вперед, чтобы указать на iподмассив Это тогда разыменовывается, чтобы получить subarray. Затем этот подмассив также подвергается преобразованию массива в указатель, давая int*, Затем вы добавляете j к этому, чтобы получить указатель на jго int объект в этом подмассиве. Это разыменовано, чтобы дать это int,

Проблема в том, что мы пытаемся передать эту вещь (T) в функцию. Я не знаю почему, но если n и m были константами, то можно передать T в качестве указателя на этот массив для работы

Это на самом деле ложь. Вы не передаете 2D-массив в функцию. На самом деле, нет такой вещи как аргумент типа массива. Ваш аргумент int K[][m] на самом деле эквивалентно int (*K)[m], То есть все аргументы типа массива преобразуются в указатели.

Поэтому, когда вы вызываете эту функцию с add_5(T)вы не передаете массив, обозначенный T, T на самом деле проходит преобразование массива в указатель, чтобы дать вам int (*)[m] а также этот указатель передается в функцию.

5

Другие решения

Вот пример 2d динамического массива:

const int Mapsize = n

int** GameField2 = 0;

GameField2 = new int*[Mapsize];                 // memory alocation
for(int i = 0; i < Mapsize; i++)
GameField2[i] = new int[Mapsize];

for(int j = 0; j < Mapsize; j++)
for(int i = 0; i < Mapsize; i++)
GameField2[i][j] = 0;

если вы хотите работать с этим массивом в любой функции, просто передайте указатель следующим образом:

int Whatver(int** GameField)
{
GameField[a][b]=x;
}
0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector