动态创建⼆维vector数组C和C++及指针与引⽤的区别
⼆维vector
vector<vector <int> > ivec(m ,vector<int>(n));    //m*n的⼆维vector
动态创建m*n的⼆维vector
⽅法⼀:
vector<vector <int> > ivec;
for(int i=0;i<m;i++) ivec[i].resize(n);
⽅法⼆:
vector<vector <int> > ivec;
动态创建⼆维数组a[m][n]
C语⾔版:
#include<malloc.h>
int **a=(int **)malloc(m*sizeof(int *));
for(int i=0;i<m;i++)
a[i]=(int *)malloc(n*sizeof(int));
C++版:
int **a=new int*[m];
for(int i=0;i<m;i++) a[i]=new int[n];
初始化⼆维数组
vector<vector <int> > ivec(m ,vector<int>(n,0));    //m*n的⼆维vector,所有元素为0
C++中⽤new动态创建⼆维数组的格式⼀般是这样:
TYPE (*p)[N] = new TYPE [][N];
其中,TYPE是某种类型,N是⼆维数组的列数。采⽤这种格式,列数必须指出,⽽⾏数⽆需指定。在这⾥,p的类型是TYPE*[N],即是指向⼀个有N列元素数组的指针。还有⼀种⽅法,可以不指定数组的列数:
int **p;
p = new int*[10];    //注意,int*[10]表⽰⼀个有10个元素的指针数组
for (int i = 0; i != 10; ++i)
{
p[i] = new int[5];
}
这⾥是将p作为⼀个指向指针的指针,它指向⼀个包含10个元素的指针数组,并且每个元素指向⼀个有5
个元素的数组,这样就构建了⼀个10⾏5列的数组。
当数组使⽤完毕,释放空间的代码是:
resize函数c++for(int i = 0; i != 5; i++)
{
delete[] p[i];
}
delete[] p;
处理⼆维数组,可以⽤降维或是⼆维法。
降维法是⽤⼀位数组来接受⼆维数组,将⼆维元素的⾸地址&a[0][0]作为参数,传递给函数,函数⽤int *接受。
⼆维法就直接⽤⼆维数组来接受,但是需要指定列数。
如要想创建⼀个[m][n]的⼆维数组。
下⾯为通过动态创建⼀个指针数组的⽅法来动态创建⼆维数组的⽅法。
C版本:
double **data;
data = (double **)malloc(m*sizeof(double *));
for(int j=0;j<m;j++)
{
data[j] = (double*)malloc(n*sizeof(double));  //这个指针数组的每个指针元素⼜指向⼀个数组。
}
for (int i=0;i<m;i++)
{
for (int j=0;j<n;j++)
{
data[i][j]=i*n+j;//初始化数组元素
}
}
for (i=0;i<m;i++)
{
free(data[i]); //先撤销指针元素所指向的数组
}
free(data);
C++版本:
double **data;
data = new double*[m]; //设置⾏或直接double **data=new double*[m]; ⼀个指针指向⼀个指针数组。
for(int j=0;j<m;j++)
{
data[j] = new double[n];        //这个指针数组的每个指针元素⼜指向⼀个数组。
}
for (int i=0;i<m;i++)
{
for (int j=0;j<n;j++)
{
data[i][j]=i*n+j;//初始化数组元素
}
}
for (i=0;i<m;i++)
{
delete[] data[i]; //先撤销指针元素所指向的数组
}
delete[] data;
这种⽅法是通过先动态创建⼀个指针数组,然后为指针数组的每个元素再动态指向⼀个数组的办法来完成的。其创建过程与销毁过程两样重要。在销毁的过程,先销毁指针数组每个元素指向的数组,然后再销毁这个指针数组。
1.使⽤数组指针,分配⼀个指针数组,将其⾸地址保存在b中,然后再为指针数组的每个元素分配⼀个数组
int **b=new int*[row];      //分配⼀个指针数组,将其⾸地址保存在b中
for(i=0;i<row;i++)            //为指针数组的每个元素分配⼀个数组
b[i]=new int[col];
该⽅法定义的动态⼆维数组的释放需先释放指针数组的每个元素指向的数组,然后再释放该指针数组:
for(i=0;i<row;i++)
{
delete [col]b[i];
b[i]=NULL;
}
delete [row]b;
b=NULL;
int _tmain(int argc, _TCHAR* argv[])
{
int row,column;
cin>>row>>column;
//⽅法⼀
//申请空间
int ** a = new int *[row];
for(int i = 0;i < row;i++)
a[i] = new int[column];
//使⽤空间
for(int j = 0;j < row;j++)
for(int k = 0;k< column;k++)
a[j][k] = rand()%100;
for(int j = 0;j < row;j++)
{
cout<<endl;
for(int k = 0;k< column;k++)
{
a[j][k] = rand()%100;
cout<<a[j][k]<<"";
}
}
//释放空间
for(int i = 0;i < row;i++)
{
delete a[i];
a[i] = NULL;
}
delete [row]a;
a = NULL;
return0;
}
⽤vector
int _tmain(int argc, _TCHAR* argv[])
{
int row,column;
cin>>row>>column;
//⽅法⼆
//申请空间
vector<vector<int> > a(row,vector<int>(column));
//使⽤空间
for(int j = 0;j < row;j++)
for(int k = 0;k< column;k++)
a[j][k] = rand()%100;
for(int j = 0;j < row;j++)
{
cout<<endl;
for(int k = 0;k< column;k++)
{
a[j][k] = rand()%100;
cout<<a[j][k]<<"";
}
}
return0;
}
⾸先,要认识到在任何情况下都不能⽤指向空值的引⽤。⼀个引⽤必须总是指向某些对象。因此如果你
使⽤⼀个变量并让它指向⼀个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向⼀个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引⽤。
char *pc = 0; // 设置指针为空值
char& rc = *pc; // 让引⽤指向空值
  这是⾮常有害的,毫⽆疑问。结果将是不确定的(编译器能产⽣⼀些输出,导致任何事情都有可能发⽣),应该躲开写出这样代码的⼈除⾮他们同意改正错误。如果你担⼼这样的代码会出现在你的软件⾥,那么你最好完全避免使⽤引⽤,要不然就去让更优秀的程序员去做。我们以后将忽略⼀个引⽤指向空值的可能性。
  因为引⽤肯定会指向⼀个对象,在C⾥,引⽤应被初始化。
string& rs; // 错误,引⽤必须被初始化
string s("xyzzy");
string& rs = s; // 正确,rs指向s
  指针没有这样的限制。
string *ps; // 未初始化的指针
// 合法但危险
  不存在指向空值的引⽤这个事实意味着使⽤引⽤的代码效率⽐使⽤指针的要⾼。因为在使⽤引⽤之前不需要测试它的合法性。
void printDouble(const double& rd)
{
cout << rd; // 不需要测试rd,它
} // 肯定指向⼀个double值
  相反,指针则应该总是被测试,防⽌其为空:
void printDouble(const double *pd)
{
if (pd) { // 检查是否为NULL
cout << *pd;
}
}
  指针与引⽤的另⼀个重要的不同是指针可以被重新赋值以指向另⼀个不同的对象。但是引⽤则总是指向在初始化时被指定的对象,以后不能改变。
string s1("Nancy");
string s2("Clancy");
string& rs = s1; // rs 引⽤ s1
string *ps = &s1; // ps 指向 s1
rs = s2; // rs 仍旧引⽤s1,
// 但是 s1的值现在是
// "Clancy"
ps = &s2; // ps 现在指向 s2;
// s1 没有改变
  总的来说,在以下情况下你应该使⽤指针,⼀是你考虑到存在不指向任何对象的可能(在这种情况下,你能够设置指针为空),⼆是你需要能够在不同的时刻指向不同的对象(在这种情况下,你能改变指针的指向)。如果总是指向⼀个对象并且⼀旦指向⼀个对象后就不会改变指向,那么你应该使⽤引⽤。
  还有⼀种情况,就是当你重载某个操作符时,你应该使⽤引⽤。最普通的例⼦是操作符[]。这个操作符典型的⽤法是返回⼀个⽬标对象,其能被赋值。
vector v(10); // 建⽴整形向量(vector),⼤⼩为10;
// 向量是⼀个在标准C库中的⼀个模板
v[5] = 10; // 这个被赋值的⽬标对象就是操作符[]返回的值
  如果操作符[]返回⼀个指针,那么后⼀个语句就得这样写:
*v[5] = 10;
  但是这样会使得v看上去象是⼀个向量指针。因此你会选择让操作符返回⼀个引⽤。
  当你知道你必须指向⼀个对象并且不想改变其指向时,或者在重载操作符并为防⽌不必要的语义误解时,你不应该使⽤指针。⽽在除此之外的其他情况下,则应使⽤指针。