单指针数组和双指针数组之间的区别
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);
单指针数组和双指针数组之间的区别
您可以在代码中看到差异:
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[0]
in main
指向,并且当i
为非零时,其长度为 n
小于 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] = 新 int[n];
而
国际A[10][20]
这是一个静态数组,将具有连续的内存分配。
这就是你创建矩阵的方式。没有理由假设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
。
静态数组隐式分配整个矩阵分配,这就是您的代码适用于它们的原因。
你在建模中使用了两个相互冲突的实现矩阵:在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++程序员会使用新的数组,除非在非常特殊的情况下;一有时想知道为什么它甚至在语言中。
您还会注意到,我已经重载了 ()
运算符索引。 您不能为 []
提供两个索引,这是该问题的解决方案之一。 或者 operator[]
将采用单个索引,并返回一个代理对象,该对象也将采用单个索引。 虽然这是我更喜欢的解决方案,它更复杂。
- 指向指向字符数组的指针数组的指针
- 通过指向指针数组的指针访问子类的属性
- C++,指针数组,指向双链表中的条目
- 在C++中,如何初始化指向wchar_t*的指针数组(生成wchar_t**)
- C++从函数指针数组调用函数
- 关于指向指针数组的指针
- 将返回值存储在函数指针数组的指针中是如何工作的?
- 将链表转换为指针数组时出错
- C++ 对象指针数组的复制构造函数
- C++ - 循环访问指针数组会导致错误
- 删除指针数组 (C++) 中的元素
- 如何循环访问 cpp 中的函数返回的字符指针数组
- 将函数指针数组中的函数指针作为模板参数传递
- Google Or-Tools Glop:如何创建指向 const 对象的指针数组?
- 具有推导参数的模板函数指针数组变量
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- C++指针数组到字符数组中的特定位置
- 如何在C++中复制指针数组的数据
- 初始化类中的指针数组,并在另一个类中检索它
- 尽管直接设置了指针数组,但仍为空