缘起:由学堂在线-清华大学《程序设计基础》-第5章第1题需要的输入输出格式引起。
正确的代码:(由QQ群“C/C++、MFC讨论群”来自浙江的S1xe在我错误的代码基础上改写)
#include <iostream>
using namespace std;
int main() {
int N = 1;
cin >> N;
int *len = new int[N];
int **array = new int *[N];
for (int i = 0; i < N; i++) {
cin >> len[i];
array[i] = new int[len[i]];
for (int j = 0; j < len[i]; j++)
cin >> array[i][j];
}
cout << endl;
for (int i = 0; i < N; i++) {
cout << len[i] << ' ';
for (int j = 0; j < len[i]; j++)
cout << array[i][j] << ' ';
cout << endl;
}
for (int i = 0; i < N; i++)
delete[] array[i];
delete[] array;
delete[] len;
return 0;
}
正确的测试结果:
错误的代码:
#include <iostream>
using namespace std;
int main()
{
int N; //设置需要输入的行数N,也是二维数组第一维的下标
int n; //设置二维数组第二维的下标
int length;
cin >> N; //给行数N赋值
int **array = new int *[N]; //设置一个N行的二维数组,每一行的首地址是*array[i]
for(int i = 0; i < N; i++) //针对已输入的行数N,设置循环结构输入各行的数据
{
cin >> array[i][0]; //每一行的第一个元素确定本行后面的列数
n = array[i][0]; //给每行除首元素所在列以外的列数n赋值
length = n + 1;
array[i] = new int[length]; //给二维数组每一行的length个元素分配动态空间
//**********************************************************
//主要错误就在这里:在给array的元素已经赋值的情况下,又调用new给array分配长度空间,这是逻辑上相矛盾的
//**********************************************************
for(int j = 1; j < length; j++) //每行正式输入的第一个元素直到最后一个元素
cin >> array[i][j];
}
cout << endl;
for(int i = 0; i < N; i++)
{
n = array[i][0];
length = n + 1;
for(int j = 1; j < length; j++)
cout << array[i][j] << ' ';
cout << endl;
} //测试代码,看能否正常输出
for(int i = 0; i < N; i++)
delete[] array[i]; //深度内存释放,对每个单元里指针指向的内存都要释放
delete[] array; //最后释放整个二维数组
return 0;
}
错误的测试结果:
之前错误的测试结果已经丢失了,上述二图是参照正确的代码的结构,修改了我的代码以后的运行结果,程序居然崩溃退出!我找了一天都没有找到确凿的原因,但是我猜想:应该是在运行过程中,变量出现了干涉,尤其是与new运算符分配的动态空间出错有关。必须用一个单独的数组来存储每行的第一个元素,不能放在第一个元素然后再用它确定后面的元素个数。这可能违反了编译器的编译顺序,也许逻辑上解释得通,但是编译上行不通,有bug。
PS:刚刚翻了翻群聊记录,S1xe说:“你的代码我看了一遍,主要问题其实在于你的第二层所谓new是错误的,最好把长度信息用另一处来存储”。
启示与经验:编程序要思路清晰、条理分明,不要试图为了减少变量的数量而绕来绕去、玩复杂的技巧——对于初学者,复杂的技巧很可能会玩砸!清晰、明了、简洁——这是编程的三大精华经验!就像下围棋,AlphaGo可以想到所有的可能,我们人类则不可能,也不需要。同样,编程序,我们不可能做到空间绝对最小、时间绝对最少,我们首先要做到正确,那么就要参照这三大经验——清晰、明了、简洁!