您的位置 首页 软件

多维数组与指针

在C语言中数组和指针之间存在一些千丝万缕的联系,搞不清楚的情况下非常容易出错,在前一段时间我写过关于数组和指针的分析,但是还是

C言语中数组和指针之间存在一些千丝万缕的联络,搞不清楚的状况下十分简略犯错,在前一段时间我写过关于数组和指针的剖析,可是仍是存在许多不清楚的问题,特别是当呈现一些杂乱的问题时,这种状况愈加的杂乱。看了许多网友的博客,可是发现一些问题,做一下扼要的总结吧。

多维数组的数组名并不是许多网友描绘的多级指针,我仅以二维数组作为研讨目标,进行必定的剖析。

二维数组int A[M][N],能够以为是存在M个元素的数组,且每一个元素都是长度为N的int型数组,这样就能比较明晰的了解了数组。数组名在许多状况下转换为指针,且数组名是数组首个元素的指针,这是十分重要的概念,搞清楚了这个概念也就能够剖析其他多维的数组状况啦。

关于上面的数组A[M][N],数组名A实质上指向数组的首个元素的指针,也便是说这时的数组名A蜕变为一个指针,指向的类型为int[N],即指向的是一个数组,而不是一个简略的值,那么对数组名进行解引证*A,便是得到这个一维数组(这是指针解引证的界说,就好像 int *p = &a, *p 实质上是指a是一个道理),相当于得到了一维数组名,即*A实质上是一个数组,(*A)能够看做这个数组的数组名,这和int a[N]是相同的道理,即:a = *A。相同依据数组名是指向数组的首个元素的指针,能够将*A也能够被看做为指针,但此刻的指针指向的是数组A[0]的首个元素,也便是指向了A[0][0],也便是说*(*A)便是A[0][0]。由此可知,二维数组并不是简略的指向指针的指针,而是每一次解引证对应的都是不同的指针类型。

关于多维的数组,假定存在int B[N][M][S]这个三维的数组,那么数组名B是一个指针,其指向的类型是int[M][S]。*B也是指针,可是其指向的类型是int[S]。**B相同也是指针,可是指向的类型是int型。更多维的数组也能够选用相似办法的剖析。所以说并不能说是多维数组的数组名多级指针,由于多维数组对数组名的解引证操作都得到了一个不同巨细的数组空间的指针,并不是指向单一元素的指针。

由上面的剖析可知,二维数组名A是一个指向一维数组的指针,指针的加法是指在当时地址上加上类型的长度,得到指向的新地址,这儿的类型便是数组int[N]。因而A+i实质上是指向二维数组的第i个元素,也便是第i个一维数组。对A+i解引证*(A+i)即得到一个数组A[i],*(A+i)便是这个数组的数组名(这样说或许不合适,可是便利了解),一起依据数组名便是指向这个数组的首个元素的地址,可知*(A+i)实质上仍是一个指针,可是这个指针指向的是A[i][0]这个元素。

下面总结一下二维数组中的一些定论:
a :指向一维数组的指针。a -> a[0]

*a :得到一维数组a[0],能够为(*a)是一维数组的数组名,而(*a)-> a[0][0]。

*a+j :指向a[0][j]的指针,(*a)可视为一个一维数组名。

a+i :数组a[i]的指针,也便是说a+i->a[i]。

*(a+i): 得到一维数组a[i],其间*(a+i)能够视为数组名。*(a+i)指向了a[i]的首个元素,即:*(a+i)->a[i][0]。

*(a+i)+j :得到数组*(a+i)的第j个元素的指针,即:*(a+i)+j -> a[i][j]。

*(*(a+i)+j) :便是得到a[i][j]。

我之前一向将二维数组看做指向指针的指针,现在想起来是不合适的,假定存在一个指向指针的指针int **p。假如另p = A,一般对p的操作都会导致一些过错,由于p是一个指向指针的指针,那么p++实质上仅仅增加了4个字节,而A+1则增加了N*sizeof(int)。两者之间并不是等价的联络,因而指向指针的指针并不能表征二维数组。

假如指向指针的指针a和二维数组名是等价的,那么下面的程序必定能够完成数组元素的打印,可是十分不幸,下面的函数会产生段过错即拜访了不合法的内存空间。

int print_array(int **a, int row, int col)
{
int i = 0 , j = 0;
for(i = 0; i < row; ++ i)
{
for(j = 0; j < col; ++ j)
printf(“%d “,a[i][j]);
printf(“”);
}
}

扼要的阐明一下,为什么会产生段过错吧,由于a是一个指向指针的指针,那么a[i]则是一个指针,他指向一个数据空间,由于数组名实际上对应一个地址,这个地址和&A等都是相同的,a[i]实质上是便是数组中的一个元素,可是其间的内容也是一个指针,这时候再次解引证就很有或许导致内存不合法拜访,产生段过错。比方A[2][3]={{1,2,3},{4,5,6}}。调用函数print_array(A,2,3)时,由于A实质上是一个地址,由于数组的特殊性,具有&A,A,A+0,&A[0][0]等对应的值是相同的。a = A,实质上a便是一个地址。这个地址便是数组的开始方位。a中的内容实质上便是数组的元素,因而对数组进行一次解引证(*a)得到的实质上便是数组的一个元素,也便是1,可是a是指向指针的指针,内容1也是一个地址,对地址1的拜访必定产生过错,由于地址1处是归于内核,不能直接进行拜访,产生了段过错。这也便是为什么说二维数组和指向指针的指针之间并不是等价的。

可是依据上面的剖析,咱们知道二维数组的数组名指明晰数组的方位,这时候直接对方位进行拜访就能够得到数组的元素。一起咱们知道a++指向的地址刚好便是a+4。刚好也便是数组的下一个元素。因而咱们能够选用解一次引证的办法完成数据的拜访。因而上面的代码能够修正如下,这种办法是运用了指针加法的一些特性,也便是指向指针的指针的增加巨细便是巨细等于4,可是这种办法只能针对类型巨细为4的数组问题,其他的类型不能运用。

int print_array(int **a, int row, int col)
{
int i = 0 , j = 0;
for(i = 0; i < row; ++ i)
{
for(j = 0; j < col; ++ j)
printf(“%d “,*(a+i+j));
printf(“”);
}
}

字符串数组是比较常用的,字符串数组界说如下:

char *str[]={
“One”,
“Two”,
“Three”,
“Four”
};

字符串数组答应呈现锯齿形的数组,也便是说各个字符串的长度能够是不相同的,咱们知道字符串数组实质上是一个指针数组,和二维数组之间存在必定的不同,并不是同一种类型的问题,指针数组能够转换为指向指针的指针的问题。
咱们常见的主函数main的两种种界说办法为:

int main(int argc, char *argv[])
int main(int argc, char **argv)

这两种界说办法使得许多的初学者以为二维数组和指向指针的指针有必定的联络,特别是第2种写法存在很大的误导性,实质上字符串数组和二维数组之间存在很大的不同,所以不能作为一类问题来评论。

二维数组作为函数的形参时也是一个应该留意的问题。咱们现已知道二维数组不是指向指针的指针这个定论。那么假如需求传递一个二维数组时又该怎么处理呢?咱们知道数组名是一个指向数组的指针,将参数设置为这种方法即可:

int print_array(int (*p)[N],int row, int col);
int print_array(int a[M][N],int row, int col);

上面的两种界说办法是比较常见的,当然也能够选用指向指针的指针这种办法,这种办法一般在动态分配二维数组的状况下运用。这时候的动态分配的二维数组和咱们当时评论的二维数组存在不同,更像是字符串指针数组问题。

/*C++*/
void array_create(int **array, int row, int col)
{
int i = 0, j = 0;

array = new int *[row];

for(i = 0; i < row; ++ i)
{
array[i] = new int[col];
}
}

其间array首要分配行,然后走中保存了指针变量,这样就完成了二维数组的动态分配,这时候的二维数组不再是线性表,这是需求留意的。在C言语中也能够直接创立线性表,即选用一维数组拜访。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/ruanjian/317749.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部