it-swarm.com.ru

Указатель на указатель динамический двумерный массив

Первый таймер на этом сайте, так что здесь идет ..

Я новичок в C++, и в настоящее время я работаю над книгой "Структуры данных с использованием C++ 2nd ed, D.S. Malik". 

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

int *board[4];

..и затем используйте цикл for для создания «столбцов», используя массив указателей в качестве «строк».

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

int **board;
board = new int* [10]; 

и т.п.

У меня такой вопрос: какой метод лучше? Метод ** проще для меня визуализировать, но первый метод можно использовать почти таким же образом. Оба способа могут быть использованы для создания динамических двумерных массивов. 

Правка: не было достаточно ясно с вышеупомянутым постом. Вот код, который я пробовал:

int row, col;

cout << "Enter row size:";
cin >> row;
cout << "\ncol:";
cin >> col;

int *p_board[row];
for (int i=0; i < row; i++)
    p_board[i] = new int[col];

for (int i=0; i < row; i++)
{
    for (int j=0; j < col; j++)
    {
        p_board[i][j] = j;
        cout << p_board[i][j] << " ";
    }
    cout << endl;
}
cout << endl << endl;

int **p_p_board;
p_p_board = new int* [row];
for (int i=0; i < row; i++)
    p_p_board[i] = new int[col];

for (int i=0; i < row; i++)
{
    for (int j=0; j < col; j++)
    {
        p_p_board[i][j] = j;
        cout << p_p_board[i][j] << " ";
    }
    cout << endl;
}
20
user2280041

Первый метод не может быть использован для создания dynamic 2D-массивов, потому что:

int *board[4];

вы по существу выделили массив из 4 указателей на intв стеке. Поэтому, если вы теперь заполните каждый из этих 4 указателей динамическим массивом:

for (int i = 0; i < 4; ++i) {
  board[i] = new int[10];
}

в итоге получается двухмерный массив с количеством строк static (в данном случае 4) и числом столбцов dynamic (в данном случае 10). Так что это не полностью динамический, потому что когда вы выделяете массив в стеке, вы должны указывать постоянный размер, то есть известный в время компиляции. Массив Dynamic называется dynamic, поскольку его размер не обязательно должен быть известен в compile-time, а скорее может быть определен некоторой переменной в runtime.

Еще раз, когда вы делаете:

int *board[4];

или же:

const int x = 4; // <--- `const` qualifier is absolutely needed in this case!
int *board[x];

вы предоставляете константу, известную в compile-time (в данном случае 4 или x), так что теперь компилятор может предварительно выделить эту память для вашего массива, а когда ваша программа загружается в память, она будет уже есть этот объем памяти для массива board, поэтому он называется static, т. е. потому что размер hard-кодирован и не может быть изменен динамически (во время выполнения).

С другой стороны, когда вы делаете:

int **board;
board = new int*[10];

или же:

int x = 10; // <--- Notice that it does not have to be `const` anymore!
int **board;
board = new int*[x];

компилятор не знает, сколько памяти потребуется массиву board, и поэтому он ничего не предварительно выделяет. Но когда вы запустите вашу программу, размер массива будет определяться значением переменной x (во время выполнения), а соответствующее пространство для массива board будет выделяться в так называемой heap - области памяти, где все программы, работающие на вашем компьютере, могут заранее выделить unknown (во время компиляции) объем памяти для личного использования.

В результате, чтобы по-настоящему создать динамический 2D-массив, вы должны использовать второй метод:

int **board;
board = new int*[10]; // dynamic array (size 10) of pointers to int

for (int i = 0; i < 10; ++i) {
  board[i] = new int[10];
  // each i-th pointer is now pointing to dynamic array (size 10) of actual int values
}

Мы только что создали квадратный 2D-массив с размерами 10 на 10. Чтобы обойти это и заполнить его фактическими значениями, например 1, мы могли бы использовать вложенные циклы:

for (int i = 0; i < 10; ++i) {   // for each row
  for (int j = 0; j < 10; ++j) { // for each column
    board[i][j] = 1;
  }
}
39
Alexander Shukaev

То, что вы описываете для второго метода, дает только одномерный массив:

int *board = new int[10];

Это просто выделяет массив из 10 элементов. Возможно, вы имели в виду что-то вроде этого:

int **board = new int*[4];
for (int i = 0; i < 4; i++) {
  board[i] = new int[10];
}

В этом случае мы выделяем 4 int*s и затем устанавливаем каждый из них на динамически распределенный массив из 10 ints.

Итак, теперь мы сравниваем это с int* board[4];. Основное отличие состоит в том, что когда вы используете такой массив, количество «строк» ​​должно быть известно во время компиляции. Это потому, что массивы должны иметь фиксированные размеры во время компиляции. У вас также может возникнуть проблема, если вы хотите вернуть этот массив int*s, так как массив будет уничтожен в конце своей области видимости.

Метод динамического размещения строк и столбцов требует более сложных мер для предотвращения утечек памяти. Вы должны освободить память следующим образом:

for (int i = 0; i < 4; i++) {
  delete[] board[i];
}
delete[] board;

Я должен рекомендовать вместо этого использовать стандартный контейнер. Вы можете использовать std::array<int, std::array<int, 10> 4> или, возможно, std::vector<std::vector<int>>, который вы инициализируете до соответствующего размера.

5
Joseph Mansfield

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

Этот вопрос в основном эквивалентен следующему:

int* x = new int[4]; "лучше", чем int x[4]?

Ответ: « нет , если вам не нужно динамически выбирать размерность этого массива».

1
Lightness Races in Orbit

Этот код хорошо работает с очень немногими требованиями к внешним библиотекам и показывает основное использование int **array.

Этот ответ показывает, что каждый массив имеет динамический размер, а также как назначить листовой массив с динамическим размером в массив с динамическими размерами.

Эта программа принимает аргументы от STDIN в следующем формате:

2 2   
3 1 5 4
5 1 2 8 9 3
0 1
1 3

Код для программы ниже ...

#include <iostream>

int main()
{
    int **array_of_arrays;

    int num_arrays, num_queries;
    num_arrays = num_queries = 0;
    std::cin >> num_arrays >> num_queries;
    //std::cout << num_arrays << " " << num_queries;

    //Process the Arrays
    array_of_arrays = new int*[num_arrays];
    int size_current_array = 0;

    for (int i = 0; i < num_arrays; i++)
    {
        std::cin >> size_current_array;
        int *tmp_array = new int[size_current_array];
        for (int j = 0; j < size_current_array; j++)
        {
            int tmp = 0;
            std::cin >> tmp;
            tmp_array[j] = tmp;
        }
        array_of_arrays[i] = tmp_array;
    }


    //Process the Queries
    int x, y;
    x = y = 0;
    for (int q = 0; q < num_queries; q++)
    {
        std::cin >> x >> y;
        //std::cout << "Current x & y: " << x << ", " << y << "\n";
        std::cout << array_of_arrays[x][y] << "\n";
    }

    return 0;
}

Это очень простая реализация int main и опирается исключительно на std::cin и std::cout. Barebones, но достаточно хорош, чтобы показать, как работать с простыми многомерными массивами.

0
Andrew