繁体   English   中英

单指针和双指针数组之间的区别

[英]Difference between single-pointer and double-pointer arrays

下面的代码显示动态分配的数组的地址。 当新行开始时,打印的地址会稍有不同。 如果我使用静态数组,则地址完全相同,并且数组元素将一个接一个地移动。 什么原因?

void func(int* a, int** b)
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            cout << &a[i * n + j]<< " " << &b[i][j]<< endl;
        }
        cout << endl;
    }
}

int main()
{
    int** a;
    a = new int*[n];
    for (int i = 0; i < n; i++)
    {
        a[i] = new int[n];
    }
    func(a[0], a);

这就是您创建矩阵的方式。 没有理由假定a[0] + 1 * n + j等于a[1] + j a[0]a[1]独立分配。

这是一次获取整个矩阵的方法。

int** a = new int*[n]; // allocate the row indexes
a[0] = new int[n * n]; // allocate the entire matrix
for (int i = 1; i < n; i++)
{
    a[i] = a[0] + i * n; // assign the row indexes. NOTE: a[0] is already assigned.
}

使用此分配, a[0] + 1 * n + j等于a[1] + j


静态数组隐式分配整个矩阵分配,这就是为什么您的代码对其有效的原因。

单指针和双指针数组之间的区别

您可以在代码中看到区别:

int** a;         // a is a pointer of type int**
a = new int*[n]; // a points to an array of pointers of type int*

和:

for (int i = 0; i < n; i++)
{
    a[i] = new int[n]; // a[i] points to an array of ints

你有它。

当新行开始时,打印的地址会稍有不同。 如果我使用静态数组,则地址完全相同,并且数组元素将一个接一个地移动。

大概是在谈论静态数组数组,并将其与您拥有的指针数组进行比较。

数组的元素在内存中连续分配。 对于静态数组数组,外部数组的元素是静态数组,它们连续存储在内存中。 对于指针数组,外部数组的元素是指针,它们也连续存储在内存中。 另一方面,您动态分配的int数组不存储在外部数组中。 它们的存储位置是实现定义的,通常与保存指针的数组的位置无关。

也:

cout << &a[i * n + j]<< " " << &b[i][j]<< endl;

在这里,您正在访问参数a所指向的数组的边界之外,参数a所指向的数组在maina[0]指向,并且长度为n ,当i为非零值时,该长度小于i * n + j 结果是技术上未定义的行为,并且打印的地址绝对不是您分配的数组元素的绝对值。

Code below prints addresses of dynamically allocated array. 
Printed addresses become slightly different, when new line starts. If
I use static array, addresses are exactly the same, and array elements
are going one after another. What's the reason?

原因是以下调用将在每次调用时生成一个新地址,并且不能保证该地址是连续的。 a [i] = new int [n];

而,

整数a [10] [20]

这是一个静态数组,将具有连续的内存分配。

在矩阵建模中,您使用了两种相互矛盾的实现方式:在main ,您使用的是数组数组,每一行都位于单独的内存中; func ,假设rows * columns元素的平面数组单一,将两个索引映射为一个。 您必须选择一个。

当然,在C ++中,您将编写一个Matrix类来封装此选择。 例如,如果您想要单个平面数组(通常更可取),则可以编写以下内容:

class Matrix
{
    int myRowCount;
    int myColumnCount;
    std::vector<int> myData;
public:
    Matrix( int rows, int columns )
        : myRowCount( rows )
        , myColumnCount( columns )
        , myData( rows * columns )
    {
    }

    int& operator()( int row, int column )
    {
        assert( row >= 0 && row < myRowCount
                && column >= 0 && column < myColumnCount );
        return myData[row * myColumnCount + column];
    }

    int const& operator()( int row, int column ) const
    {
        assert( row >= 0 && row < myRowCount
                && column >= 0 && column < myColumnCount );
        return myData[row * myColumnCount + column];
    }
};

您会注意到,我使用了std::vector而不是自己进行任何动态分配。 在这种情况下,差异并不大,但是在实践中,除了非常例外的情况外,没有经验的C ++程序员会使用new数组。 有时有人想知道为什么它甚至在语言中也是如此。

您还将注意到,我已经重载了()运算符以进行索引。 您不能为[]提供两个索引,这是该问题的解决方案之一。 另外, operator[]将采用单个索引,并返回一个代理对象,该对象也将采用单个索引。 虽然这是我更喜欢的解决方案,但它更加复杂。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM