C++中动态二维数组中的地址

Posted

技术标签:

【中文标题】C++中动态二维数组中的地址【英文标题】:address in dynamic two dimensional array in c++ 【发布时间】:2016-04-28 07:23:16 【问题描述】:

我可以通过以下方式在 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) 编译器并在我的 windows 10-64 位机器上运行我的程序。

这是一个示例输出:

int**的大小:4

int*的大小:4

int的大小:4

8135000 8135024

所以,这是我的两个问题:

    为什么地址相差 24 而不是 16 (= 4*4) ? int 的大小为 4,一行有 4 列。那么它们不应该相差16吗? 我知道 C++ 结构中的字节填充。是这样的原因吗?

    我尝试将 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?

【问题讨论】:

您期望得到什么样的答案?解释 gcc 的实现细节?或者“问题的提出方式是那些不确定的 impl.details,你不应该对它们做出预测;但是如果你必须依赖 X 和 Y,使用这个......”就足够了吗?跨度> 用真正的二维数组试试同样的方法:int p[3][4]; 是的,那么可以计算它们的差异。但我更感兴趣的是了解new int[colSize] 是否以某种模式返回地址。 【参考方案1】:
    内存分配操作的结果是alignof(std::max_align_t)-aligned。在您的情况下,alignof(std::max_align_t) 可能是 8。 在大多数实现中,在数组旁边分配了不可见数量的sizeof(std::max_align_t) 字节用于一些内部记账。在您的情况下,它的大小可能为 8。

所以在第一种情况下:4*4 + 8 = 24,已经是 8 的倍数。 第二个:4*5 + 8 = 28,四舍五入到最接近的 8 = 32 的乘积。

编译器没有义务返回递增的地址或遵循某种模式。碰巧在你的情况下这是最容易做的事情。

【讨论】:

我使用了printf("%d", size_t); 并在输出中得到了 4。但是谢谢,每次都发现相同的差异后我很好奇。 @AhsanTarique 稍微修正了我的答案以更准确。我忘了 size_t 不是 32 位机器的最大对齐类型【参考方案2】:

p[i] arryas 单元格中的地址由 new 运算符定义

p[i]= new int[colSize];

此运算符可以从堆中返回任何地址,这与数组大小无关。

您可以创建一个大的一维数组(正如编译器所做的array[][])并将二维映射到一维。

int* arr2d = new int[colSize*rowSize];
//Retrieve value from Row3 Col2
int nRow3Col2 = arr2d[2 + 3 * colSize];

【讨论】:

它们似乎在每次运行时都相差相同的长度(尽管地址有所不同)。所以我认为可能有一种模式,而不是随机的地址。 这取决于new 运算符实现(顺便说一句,可以重载)。无论如何地址都不能保证。也尝试在Release模式下编译,观察差异。 恐怕我没听懂你说的发布模式。我试图用谷歌搜索它,并在其中一个结果中找到了它。 link我应该尝试问题中回答的方法吗? 您当然应该尝试理解它。它是存储方形二维数组的最简单和紧凑的方式。更重要的问题是你是否应该使用它。这取决于您的特定任务。阅读有关不同类型数组的更多信息。【参考方案3】:

您不是在编写 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;

【讨论】:

以上是关于C++中动态二维数组中的地址的主要内容,如果未能解决你的问题,请参考以下文章

C++建立动态二维数组

利用c++中的vector创建动态二维数组

c++中的new()申请二维数组

指向 C++ 中动态分配的二维数组中的一行的指针

在 C++ 中初始化动态二维数组

如何使用 C++ 中的指针动态分配和解除分配二维数组?