指针对指针的动态二维数组
Posted
技术标签:
【中文标题】指针对指针的动态二维数组【英文标题】:Pointer-to-pointer dynamic two-dimensional array 【发布时间】:2013-04-06 18:40:03 【问题描述】:这个网站上的第一个计时器,所以这里..
我是 C++ 的新手,目前正在阅读 D.S. Malik 的《使用 C++ 第二版的数据结构》一书。
在书中 Malik 提供了两种创建动态二维数组的方法。 在第一种方法中,您将变量声明为指针数组,其中每个指针都是整数类型。例如。
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;
【问题讨论】:
我不确定这个问题是否会改变,如果你把它变成一维的。int board[4]
与 int *board = new int[4]
。你会同意吗?它可能会改善您的答案。
其实用int *board[4]
已经不是二维数组的动态分配了,是4个指针数组的静态分配。
@JBL:小心地把static这个词抛在脑后。你说得对,静态分配是正确的,但是使用了自动存储持续时间,这可能会让人感到困惑。无论如何,我相信“动态数组”一词首先指的是它不仅仅是一个血腥的int board[4][4]
,即它不一定是矩形的。
见***.com/a/936709/3241228 这个答案的第二部分可能是最简洁有效的解决方案(恕我直言)。
哪个更快?我猜是第一个(因为它是静态的)
【参考方案1】:
第一种方法不能用于创建动态二维数组,因为这样做:
int *board[4];
您实际上分配了一个包含 4 个指针的数组,指向 int
在堆栈上。因此,如果您现在用动态数组填充这 4 个指针中的每一个:
for (int i = 0; i < 4; ++i)
board[i] = new int[10];
您最终得到的是一个具有 静态 行数(在本例中为 4)和 动态 列数(在本例中为 10)的二维数组。所以它不是完全动态的,因为当你在堆栈上分配一个数组时,你应该指定一个常量大小,即在compile-时间。 动态数组之所以称为动态,是因为它的大小在编译时不需要知道,而是可以由运行时。
再一次,当你这样做时:
int *board[4];
或:
const int x = 4; // <--- `const` qualifier is absolutely needed in this case!
int *board[x];
您提供一个在 编译时 已知的常量(在本例中为 4 或 x
),以便编译器现在可以为您的数组预分配此内存,当你的程序加载到内存中时,它已经拥有board
数组的内存量,这就是为什么它被称为静态,即因为大小是硬编码 和 不能动态更改(在运行时)。
另一方面,当你这样做时:
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 上- 您计算机上运行的所有程序可以分配事先未知(在编译时)供个人使用的内存区域。
因此,要真正创建动态二维数组,您必须使用第二种方法:
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
我们刚刚创建了一个 10 x 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;
【讨论】:
第一种方法即使使用变量来确定数组大小也行不通? //int *board[x];使用变量后,您将不再有静态的行数,然后最终得到一个动态的二维数组,对吧?抱歉,如果这看起来很愚蠢,但我正在努力理解你在告诉我的内容。 这就是我所怀疑的。通过假设,您正在犯 C++ 新手中最常见的错误。我也是新手的时候自己做的,所以没问题。如果x
不是const
,您不能执行int *board[x];
,即在编译时再次知道。自己试试,你会得到编译错误。另外,我已经扩展了我的答案,请阅读它,并尝试再次理解。有问题再问。
实际上,不,您很可能不会收到编译错误。一些工具链支持非标准扩展以使其有效。 (不过,这并不是一个好主意。)
@Lightness Races in Orbit - 是的,这就是我对此感到如此困惑的原因。我正在使用带有 GCC 的代码块,它通过某种扩展来支持它。标准不允许,所以我会坚持指针指向指针路。
@Alexander Shukaev 但是如果我们需要二维数组指针指向一个需要构造函数的类的对象列表?怎么可能做到这一点?对象必须是这样的:TEdit bucket3 = new TEdit(this);
但是我们如何才能获得带有这种对象的**数组? bucket3 = new TEdit[5](this); bucket3 = new TEdit(this)[5]; // both statements gives error
Cpp delphi 最好用俄语。【参考方案2】:
你对第二种方法的描述只给你一个一维数组:
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 个int
s 数组。
所以现在我们将其与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>>
,将其初始化为适当的大小。
【讨论】:
大部分我已经知道了。我只想知道使用的两种方法是否有任何真正的区别。我在编辑中发布了一些代码,以帮助您更好地理解。 @user2280041:您为什么不阅读 sftrabbit 精心制作的答案?他花了一些时间来做。我引用:The major difference is that when you use an array like this, the number of "rows" must be known at compile-time.
他继续研究其他差异,您可能会觉得有趣。【参考方案3】:
在这两种情况下,您的内部维度都可以动态指定(即取自变量),但区别在于外部维度。
这道题基本等同于:
int* x = new int[4];
比int x[4]
“更好”吗?
答案是:“否,除非您需要动态选择该数组维度。”
【讨论】:
【参考方案4】:此代码运行良好,对外部库的要求很少,并展示了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
。准系统,但足以展示如何使用简单的多维数组。
【讨论】:
注意:这里不讨论删除数组,因此不讨论如何清理指针指向的内存。其他答案已经解决了这个问题。【参考方案5】:这样就可以了
-
我使用过运算符重载
重载的分配
重载的复制构造函数
/*
* Soumil Nitin SHah
* Github: https://github.com/soumilshah1995
*/
#include <iostream>
using namespace std;
class Matrix
public:
/*
* Declare the Row and Column
*
*/
int r_size;
int c_size;
int **arr;
public:
/*
* Constructor and Destructor
*/
Matrix(int r_size, int c_size):r_sizer_size,c_sizec_size
arr = new int*[r_size];
// This Creates a 2-D Pointers
for (int i=0 ;i < r_size; i++)
arr[i] = new int[c_size];
// Initialize all the Vector to 0 initially
for (int row=0; row<r_size; row ++)
for (int column=0; column < c_size; column ++)
arr[row][column] = 0;
std::cout << "Constructor -- creating Array Size ::" << r_size << " " << c_size << endl;
~Matrix()
std::cout << "Destructpr -- Deleting Array Size ::" << r_size <<" " << c_size << endl;
Matrix(const Matrix &source):Matrix(source.r_size, source.c_size)
for (int row=0; row<source.r_size; row ++)
for (int column=0; column < source.c_size; column ++)
arr[row][column] = source.arr[row][column];
cout << "Copy Constructor " << endl;
public:
/*
* Operator Overloading
*/
friend std::ostream &operator<<(std::ostream &os, Matrix & rhs)
int rowCounter = 0;
int columnCOUNTER = 0;
int globalCounter = 0;
for (int row =0; row < rhs.r_size; row ++)
for (int column=0; column < rhs.c_size ; column++)
globalCounter = globalCounter + 1;
rowCounter = rowCounter + 1;
os << "Total There are " << globalCounter << " Elements" << endl;
os << "Array Elements are as follow -------" << endl;
os << "\n";
for (int row =0; row < rhs.r_size; row ++)
for (int column=0; column < rhs.c_size ; column++)
os << rhs.arr[row][column] << " ";
os <<"\n";
return os;
void operator()(int row, int column , int Data)
arr[row][column] = Data;
int &operator()(int row, int column)
return arr[row][column];
Matrix &operator=(Matrix &rhs)
cout << "Assingment Operator called " << endl;cout <<"\n";
if(this == &rhs)
return *this;
else
delete [] arr;
arr = new int*[r_size];
// This Creates a 2-D Pointers
for (int i=0 ;i < r_size; i++)
arr[i] = new int[c_size];
// Initialize all the Vector to 0 initially
for (int row=0; row<r_size; row ++)
for (int column=0; column < c_size; column ++)
arr[row][column] = rhs.arr[row][column];
return *this;
;
int main()
Matrix m1(3,3); // Initialize Matrix 3x3
cout << m1;cout << "\n";
m1(0,0,1);
m1(0,1,2);
m1(0,2,3);
m1(1,0,4);
m1(1,1,5);
m1(1,2,6);
m1(2,0,7);
m1(2,1,8);
m1(2,2,9);
cout << m1;cout <<"\n"; // print Matrix
cout << "Element at Position (1,2) : " << m1(1,2) << endl;
Matrix m2(3,3);
m2 = m1;
cout << m2;cout <<"\n";
print(m2);
return 0;
【讨论】:
以上是关于指针对指针的动态二维数组的主要内容,如果未能解决你的问题,请参考以下文章