адрес в динамическом двумерном массиве в c ++

Я могу создать двумерный массив на C ++ следующим образом. Но у меня проблемы с пониманием адресации памяти.

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

#include <cstdio>
#include <iostream>

using namespace std;

#define rowSize 3
#define colSize 4


int main(){
    int ** p;

    p = new int*[rowSize];

    for(int i = 0; i < rowSize; i++){
        p[i]= new int[colSize];
    }

    printf("the size of int**: %d\n", sizeof(int**));
    printf("the size of int*: %d\n", sizeof(int*));
    printf("the size of int: %d\n\n", sizeof(int));



    printf("%d %d", p[0], p[1]);
    return 0;
}

Я использовал компилятор gcc версии 4.7.1 (tdm-1) и запускал свою программу на моем 10-64-битном компьютере с Windows.

Вот пример вывода:

размер int **: 4

размер int *: 4

размер int: 4

8135000 8135024

Итак, вот два моих вопроса:

  1. Почему адреса отличаются на 24 вместо 16 (= 4 * 4)? Размер int равен 4, а в строке 4 столбца. Так разве они не должны отличаться на 16? Я знаю о заполнении байтов в структуре в C ++. Что-то подобное является причиной этого?

  2. Я попытался изменить colSize на 5:

    #define colSize 5, перекомпилировал и снова запустил программу.

    Пример вывода:

the size of int**: 4

the size of int*: 4

the size of int: 4


7151960 7151992

На этот раз адреса различаются на 32. Если бы причиной было заполнение байтов, для 5 столбцов потребовалось бы 5 * 4 = 20 байтов. В этом случае будет достаточно заполнения в 4 байта, и в этом случае адреса должны отличаться на 24.

Так почему же в данном случае они отличаются на 32?


person Ahsan Tarique    schedule 28.04.2016    source источник
comment
Какие ответы вы ожидаете? Объясняете детали реализации gcc? Или, как сформулирован вопрос, это подразумеваемые детали, которые не гарантированы, вам не следует делать прогнозов относительно них; но если вам нужно полагаться на X и Y, используйте это .... хватит?   -  person VolkerK    schedule 28.04.2016
comment
Попробуйте то же самое с реальным двумерным массивом: int p [3] [4];   -  person Bob__    schedule 28.04.2016
comment
Да, тогда их разницу можно посчитать. Но меня больше интересовало, возвращает ли new int[colSize] адрес в каком-то шаблоне.   -  person Ahsan Tarique    schedule 28.04.2016


Ответы (3)


  1. Результат операций выделения памяти выровнен по alignof(std::max_align_t). В вашем случае alignof(std::max_align_t) вероятно 8.
  2. В большинстве реализаций есть невидимое количество sizeof(std::max_align_t) байтов, выделенное рядом с массивом для некоторой внутренней бухгалтерии. В вашем случае, вероятно, размер 8.

Итак, в первом случае: 4 * 4 + 8 = 24, уже кратное 8.
Во втором: 4 * 5 + 8 = 28, округленное до ближайшего умножения 8 = 32.

Компилятор не обязан возвращать увеличивающийся адрес или следовать некоторому шаблону. Так уж вышло, что в вашем случае это сделать проще всего.

person Revolver_Ocelot    schedule 28.04.2016
comment
Я использовал printf("%d", size_t); и получил 4 на выходе. Но спасибо, мне было любопытно, когда я каждый раз обнаруживал одну и ту же разницу. - person Ahsan Tarique; 28.04.2016
comment
@AhsanTarique слегка поправил мой ответ, чтобы быть более точным. Я забыл, что size_t не является максимальным типом aligment для 32-битных машин - person Revolver_Ocelot; 28.04.2016

Адреса в ваших p[i] ячейках arryas определяются оператором new

p [i] = новый int [colSize];

Этот оператор может возвращать любой адрес из кучи, и это не зависит от размеров массивов.

Вы можете создать один большой одномерный массив (как это делает компилятор array[][]) и сопоставить два измерения с одним измерением.

int* arr2d = new int[colSize*rowSize];
//Retrieve value from Row3 Col2
int nRow3Col2 = arr2d[2 + 3 * colSize];
person Dmitriy Zapevalov    schedule 28.04.2016
comment
Кажется, что они различаются одинаковой длиной при каждом запуске (хотя адреса меняются). Поэтому я подумал, что вместо случайных адресов может быть шаблон. - person Ahsan Tarique; 28.04.2016
comment
Это зависит от реализации оператора new (который, кстати, может быть перегружен). В любом случае адреса не гарантируются. Также попробуйте скомпилировать в режиме Release и обратите внимание на разницу. - person Dmitriy Zapevalov; 28.04.2016
comment
Боюсь, я не понял, что вы сказали о режиме Release. Я попытался погуглить и нашел это в одном из результатов. ссылка Стоит ли мне попробовать метод, на который дан ответ в вопросе? - person Ahsan Tarique; 28.04.2016
comment
Вы обязательно должны попытаться понять это. Это наиболее простой и компактный способ хранения квадратных 2D-массивов. Более важный вопрос - использовать его или нет. Это зависит от вашей конкретной задачи. Узнайте больше о различных типах массивов. - person Dmitriy Zapevalov; 28.04.2016

Вы пишете не на C ++, а на C. Поскольку вы отметили это как C ++, я предполагаю, что вам нужен C ++ ...

Современный C ++ использует RAII и значительно упрощает работу с помощью стандартных контейнеров библиотеки. Хотя я понимаю, что на самом деле это не ответ на ваш вопрос, я предлагаю вам переписать код:

#include <vector>
#include <cstdio>
int main()
{
   int rowsize = ...;
   int colsize = ...;

// allocating
   std::vector<std::vector<int>> vec(rowsize);
   for( auto e: vec )
      e.resize(colsize);

// filling with values
   vec.at(row).at(col) = 123;
// printing values
   std::cout << vec.at(row).at(col) << std::endl;
}
person kebs    schedule 28.04.2016