c语言中二维数组的指针如何表示 C语言中二维数组行指针是什么

作者&投稿:轩战 (若有异议请与网页底部的电邮联系)
比如定义一个int型的二维数组,如下:
int **p;
或者
int p[MAX_ROW][MAX_LINE];
不同的是前者定义了一个int型二维数组的指针,编写器知道该指针的移动方式以int为单位,但此时该指针为NULL,即没有与内存中的物理单元进行对应。使用指针前需要用malloc()为该指针分配一段内存空间,内存空间的大小在malloc()的参数中指定,系统会为该指针分配一段空闲内存供该指针使用。或者将你的程序中其他int类型的指针赋值给该指针使其映射到内存物理单元。在程序结束或不在需要使用该指针时需要使用free()将该指针所映射内存释放。
后者在定义时为该指针分配了MAX_ROW*MAX_LINE个int大小的空间映射到内存,之后就可以直接使用了。

给你一个例子吧
#include <stdlib.h>
int ** array = malloc( N * sizeof(int *) ); //二维数组指针
array[0] = malloc( M * sizeof(int) );
for (int k=1;k<N;k++)
array[k] = array[0]+M*k; //可以当数组用

二维数组和指针

⑴ 用指针表示二维数组元素。

要用指针处理二维数组,首先要解决从存储的角度对二维数组的认识问题。
一个二维数组在计算机中存储时,是按行存储的,即先存储第一行的元素,再存储第二行的元素。
当把每一行看作一个整体,即作为一个大的数组元素时,原来的二维数组也就变成一个一维数组了。而每个大数组元素对应原来二维数组中的一行,称为行数组元素,显然每个行数组元素都是一个一维数组。
下面讨论二维数组元素和指针之间的对应关系,清楚了二者之间的关系,就能用指针处理二维数组了。
设p是指向二维数组a[M][N]的指针变量,若有:p=a[0]; 则p+j将指向a[0]数组中的元素a[0][j]。
由于a[0]、a[1]┅a[M-1]等各个行数组依次连续存储,则对于a数组中的任一元素a[i][j],指针的一般形式如下:p+i*N+j用"*"运算符表示为:*( p+i*N+j)同样,a[i][j]也可使用指针下标法表示,如下:p[i*N+j]

例如,有如下定义:
int a[3][4]={{10,20,30,40,},{50,60,70,80},{90,91,92,93}};
则数组a有3个元素,分别为a[0]、a[1]、a[2]。而每个元素都是一个一维数组,各包含4个元素,如a[1]的4个元素是a[1][0]、a[1][1]、a[1]2]、a[1][3]。
若有:
int *p=a[0];
则数组a的元素a[1][2]对应的指针为:p+1*4+2
元素a[1][2]也就可以表示为:*( p+1*4+2)
用下标表示法,a[1][2]表示为:p[1*4+2]
特别说明:
对上述二维数组a,虽然a[0]、a都是数组首地址,但二者指向的对象不同。

a[0]是一维数组的名字,它指向的是一维数组a[0]的首元素a[0][0],对其进行“*”运算,得到的是一维数组元素a[0][0]的值,即*a[0]与a[0][0]是同一个值。
而a是一个二维数组的名字,它指向的是二维数组a的首元素a[0],对a进行“*”运算,得到的是一维数组a[0]的首地址,即*a与a[0]是同一个值。它的指针移动单位是“行”,所以a+i指向的是第i个行数组,即指向a[i]。
当用int *p;定义指针p时,p的指向是一个int型数据,而不是一个地址,因此,用a[0]对p赋值是正确的,而用a对p赋值是错误的。这一点请务必注意。

示例:

#include <stdio.h>

int main()
{

int a[3][4]={{3,17,8,11},{66,7,8,19},{12,88,7,16}};
int *p=a[0],max,i,j,row,col;
max=a[0][0];

row=col=0;

for(i=0;i<3;i++)
for(j=0;j<4;j++)
if(*(p+i*4+j)>max)
{
max=*(p+i*4+j);
row=i;
col=j;
}
printf("a[%d][%d]=%d\n",row,col,max);
printf("address of a is:%x\n", (unsigned int)a);
printf("address of a[0] is:%x\n", (unsigned int)a[0]);
printf("address of a[0][0] is:%x\n\n", (unsigned int)&a[0][0]);
printf("address of (a+1) is:%x\n", (unsigned int)(a+1));
printf("address of (a[0]+1) is:%x\n", (unsigned int)(a[0]+1));
printf("address of (a[0][0]+1) is:%x\n", (unsigned int)(&a[0][0]+1));

return 0;
}

运行结果:

a[2][1]=88
address of a is:bfdc0368
address of a[0] is:bfdc0368
address of a[0][0] is:bfdc0368

address of (a+1) is:bfdc0378
address of (a[0]+1) is:bfdc036c
address of (a[0][0]+1) is:bfdc036c
从结果看出,a,a[0],a[0][0]是同一个地址,

⑵ 用二维数组名作地址表示数组元素。

另外,由上述说明,还可以得到二维数组元素的一种表示方法:
对于二维数组a,其a[0]数组由a指向,a[1]数组则由a+1指向,a[2]数组由a+2指向,以此类推。因此,*a与a[0]等价、*(a+1)与a[1]等价、*(a+2)与a[2]等价,┅,即对于a[i]数组,由*(a+i)指向。由此,对于数组元素a[i][j],用数组名a的表示形式为:*(*(a+i)+j)指向该元素的指针为:*(a+i)+j数组名虽然是数组的地址,但它和指向数组的指针变量不完全相同。指针变量的值可以改变,即它可以随时指向不同的数组或同类型变量,而数组名自它定义时起就确定下来,不能通过赋值的方式使该数组名指向另外一个数组。
示例:

求二维数组元素的最大值。

该问题只需对数组元素遍历,即可求解。因此,可以通过顺序移动数组指针的方法实现。
main()
{

int a[3][4]={{3,17,8,11},{66,7,8,19},{12,88,7,16}};
int *p,max;
for(p=a[0],max=*p;p<a[0]+12;p++)
if(*p>max)
max=*p;
printf("MAX=%d/n",max);

}
执行结果:
MAX=88
这个程序的主要算法都是在for语句中实现的:p是一个int型指针变量;p=a[0]是置数组的首元素地址为指针初值;max=*p将数组的首元素值a[0][0]作为最大值初值;p<a[0]+12是将指针的变化范围限制在12个元素的位置内;p++使得每比较一个元素后,指针后移一个元素位置。
示例:

求二维数组元素的最大值,并确定最大值元素所在的行和列。
本例较之上例有更进一步的要求,需要在比较的过程中,把较大值元素的位置记录下来,显然仅用上述指针移动方法是不行的,需要使用能提供行列数据的指针表示方法。
main()
{

int a[3][4]={{3,17,8,11},{66,7,8,19},{12,88,7,16}};
int *p=a[0],max,i,j,row,col;
max=a[0][0];

row=col=0;

for(i=0;i<3;i++)
for(j=0;j<4;j++)
if(*(p+i*4+j)>max)
{
max=*(p+i*4+j);
row=i;
col=j;
}
printf("a[%d][%d]=%d/n",row,col,max);

}
程序运行结果:
a[2][1]=88

⑶ 行数组指针

对于指针,不管有多复杂,按照以下原则进行分析:
从变量名处起,根据运算符优先级结合,一步一步分析。

在上面的说明中已经知道,二维数组名是指向行的,它不能对如下说明的指针变量p直接赋值:
int a[3][4]={{10,11,12,13},{20,21,22,23},{30,31,32,33}},*p;其原因就是p与a的对象性质不同,或者说二者不是同一级指针。C语言可以通过定义行数组指针的方法,使得一个指针变量与二维数组名具有相同的性质。

行数组指针的定义方法如下:
数据类型 (*指针变量名)[二维数组列数];

例如,对上述a数组,行数组指针定义如下:
int (*p)[4];它表示,数组*p有4个int型元素,分别为(*p)[0]、(*p)[1]、(*p)[2]、(*p)[3] ,亦即p指向的是有4个int型元素的一维数组,即p为行指针。
(按照指针的分析原则进行分析:p先与*结合,说明p是一个指针,然后与[]结合,说明指针指向的内容是含4个元素的数组,然后与int结合,说明数组中的元素为int类型。所以p是一个指向含4个int类型元素的数组的指针。)此时,可用如下方式对指针p赋值:p=a;为做对比,比较一下如下指针:int *p[4];
(按照指针的分析原则进行分析:p先与[]结合,说明p是一个数组,然后与*结合,说明数组的元素为指针,然后与int结合,说明指针指向的是int类型的变量。所以p是一个含4个元素的指向int类型变量的指针组成的数组。)

此外二维数组不可以用int**类型直接赋值访问

小的示例程序:
#include <cstdio>
#include <cstring>
using namespace std;

int a[3][4];

int main(){
memset(a, -1, sizeof(a));
int i;
for( i = 0; i < 3; i++){
printf("&a[i][0] = %d\n", &a[i][0]);
printf("a + i = %d; *(a + i) = %d;\n", a + i, *( a + i));
printf("a[i] = %d; &a[i] = %d;\n", a[i], &a[i]);
printf("\n");
}
}

这段示例程序在我本地上运行的结果为:
&a[i][0] = 4214816
a + i = 4214816; *(a + i) = 4214816;
a[i] = 4214816; &a[i] = 4214816;

&a[i][0] = 4214832
a + i = 4214832; *(a + i) = 4214832;
a[i] = 4214832; &a[i] = 4214832;

&a[i][0] = 4214848
a + i = 4214848; *(a + i) = 4214848;
a[i] = 4214848; &a[i] = 4214848;

我想看到这个运行结果,你已经有所了解了,下面我再详细说一下:
指针量a作为一个二维数组的指针量,其本质是一个“指向指针的指针”(为了方便,下面称其为双重指针),或者你可以理解为a为int**类型的指针量。当a做加减运算时,得到的结果仍然是一个“双重指针”,即a + i是一个双重指针,它是一个指向了原数组第i行的起始位置的双重指针。
而*(a + i)原来的双重指针解引用后得到的一个指针变量,他是一个指向了原数组第i行的起始位置的“单重指针”。
可以看出,a + i和*(a + i)尽管数据类型不同(前者为双重指针,后者为单重指针),但是他们指向同一块内存地址,因此作为指针量,他们的值是相等的。注意,仅仅是说,他们的值在数学上是相等的,并非说“他们是等价的”。
你的第二个问题亦是同理:
首先,[]作为C语言的操作符,本身即具有“解引用”的语义。明白的说,就是a[i]与*(a + i)是完全等价的,而&a[i]即等价于a + i。由于易知a + i和*(a + i)在数值上相当,那么进行等价带花可以知道,&a[i]和a[i]在数值上相等。当然,此处仍非等价关系。
至于指向行的指针,所指的就是指向行首位置的指针量。
至于你的最后一个问题,正如我刚才一直强调的那样,等号两端仅仅是数值上的相等,而非等价关系,因此无法按照你所设想的方式进行归纳推导。
另外,虚机团上产品团购,超级便宜

C语言如何定义指针指向字符型二维数组~

使用指针变量访问二维数组的任意一个元素的方法:
1.使用列指针:定义一个列指针p,让它指向二维数组的第0个元素
int a[3][4];
int *p;
p=&a[0][0];
//因为a[0]是第0行的数组名,所以p=&a[0][0]相当于p=a[0],因为a[i][j]前面共有i*4+j个元素
该二维数组的任意i行j列元素可表示为*(p+i*4+j)。
2.使用行指针:定义一个行指针p,让它指向二维数组的第0行
int a[3][4];
int (*p)[4];
p=a; //也可以为p=&a[0];
其中* ( *(p+i)+j)表示任意一个i行j列的元素。

扩展资料:
数组的使用规则:
1.可以只给部分元素赋初值。当{ }中值的个数少于元素个数时,只给前面部分元素赋值。例如:static int a[10]={0,1,2,3,4};表示只给a[0]~a[4]5个元素赋值,而后5个元素自动赋0值。
2.只能给元素逐个赋值,不能给数组整体赋值。例如给十个元素全部赋1值,只能写为:static int a[10]={1,1,1,1,1,1,1,1,1,1};而不能写为:static int a[10]=1;请注意:在C、C#语言中是这样,但并非在所有涉及数组的地方都这样,数据库是从1开始。
3.如不给可初始化的数组赋初值,则全部元素均为0值。
4.如给全部元素赋值,则在数组说明中, 可以不给出数组元素的个数。例如:static int a[5]={1,2,3,4,5};可写为:static int a[]={1,2,3,4,5};动态赋值可以在程序执行过程中,对数组作动态赋值。这时可用循环语句配合scanf函数逐个对数组元素赋值。
参考资料:
百度百科-数组

先从存储的角度对二维数组作一个全面的了解。二维数组在内存中的存储,是按照先行后列依次存放的。从内存的角度看,可以这样说,二维数组其实就是一个一维数组,在内存中没有二维的概念。如果把二维数组的每一行看成一个整体,即看成一个数组中的一个元素,那么整个二维数组就是一个一维数组,它以每一行作为它的元素,这个应该很好理解。
第一,来详细介绍二维数组与指针的关系。-
首先定义个二维数组 array[3][4],p 为指向数组的指针。
若p=array[0],此时p指向的是二维数组第一行的首地址,则 p+i 将指向array[0]数组中的元素array[0][i]。由以上所介绍的二维数组在内存中的存储方式可知,对数组中的任一元素array[i][j] ,其指针的形式为:p+i*N+j (N为每一行的长度)。 元素相应的指针表示法为:*(p+i*N+j) ,下标表示法为:p[i*N+j] 。
For Example:
array[4][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12}};
int * p=array[0];
数组array有四个元素,分别为array[0],array[1],array[2],array[3],每个元素为包含3个元素的一维数组,
如array[0]的3个元素为 array[0][0],array[0][1],array[0][2]。
元素array[2][2]对应指针为:array+2*3+2,
指针表示法为:*(array+2*3+2) ,
下标表示法为:array[2*3+2] 。
特别注意:虽然 array[0] 与 array 都是数组首地址,但两者指向的对象不同,这点要非常明确。array[0] 是一维数组的名字,它指向的是一维数组array[0]的首地址,所以 *array[0]与array[0][0]为同个值。而 array 是二维数组的名字,它指向的是所属元素的首地址,其每个元素为一个行数组。它是以‘行’来作为指针移动单位的,如array+i 指向的是第 i 行。对 array 进行 * 运算,得到的是一维数组 array[0] 的首地址,所以 *array 与 array[0] 为同个值。如果定义 int* p,p为指int类型的指针,指向int 类型,而不是地址。故以下操作 :p=array[0] (正确) ,p=array (错误) 。这点要非常注意。
第二,看看如何用数组名作地址表示其中元素。
对二维数组array ,array[0] 由 array指向,故*array 与array[0] 是相同的,依次类推可得 array[i] 由array+i 指向,*(array+i) 与array[i]是相同的。 因此,对于数组元素 array[i][j] ,用数组名表示为 *(*(array+i)+j) ,指向该元素的指针为 *(array+i)+j 。
注意:数组名虽然是地址,但与指向数组的指针性质不同。指针变量可以随时改变其所指向对象,而数组名不可以,一旦被定义,就不能通过赋值使其指向另外一个数组,但是在Java中则可以。
第三,顺便了解一下不太常用的‘行数组指针’。
对于二维数组array[4][3],与int* p 。二维数组名array 不能直接赋值给p。原因前面已讲过,两只的对象性质不同。 在C语言中,可以通过定义一个行数组指针,使得这个指针与二维数组名具有同样的性质,实现它们之间可以直接赋值。行数组指针定义如下:
int (*p)[3]; 它表示,数组 *p 具有三个int类型元素,分别为 (*p)[0] , (*p)[1] , (*p)[2] ,即 p指向的是具有三个int类型的一维数组,也就是说,p为行指针。此时,以下运算 p=array 是正确的。
第四,二维数组作为函数参数。
二维数组作为函数参数一般有两种方式:(1) void func(int **array){...} (2) void func(int array[ ][N])
注意第二种方式一定要指明二维数组的列数
当二维数组名作为函数实参时,对应的形参必须是一个行指针变量。
和一维数组一样,数组名传送给变量的是一个地址值,因此,对应的形参也必须是一个类型相同的指针变量,在函数中引用的将是主函数中的数组元素,系统只为形参开辟一个存放地址的存储单元,而不可能在调用函数时为形参开辟一系列存放数组的存储单元。
int main()
double a[3][4];
……
fun(a);
……
fun(double (*a)[n])
……

二维数组如何用指针表示
答:二维数组用指针表示有两种方式:一、动态数组方式。完全由动态数据构成二维数组。如M行N列的数组,先分配M个一维指针空间,然后在每个一维指针上分配N个元素的空间,即成为动态二维数组。和普通数组不同,这种动态二维数组的各行之间地址并不连续。参考代码:include<stdlib.h>int **create(int m, int ...

c语言中二维数组的指针如何表示
答:int p[MAX_ROW][MAX_LINE];不同的是前者定义了一个int型二维数组的指针,编写器知道该指针的移动方式以int为单位,但此时该指针为NULL,即没有与内存中的物理单元进行对应。使用指针前需要用malloc()为该指针分配一段内存空间,内存空间的大小在malloc()的参数中指定,系统会为该指针分配一段空闲内存...

求C语言高手指点:请问如何指针定义二维数组?? 请用 **p ,(*P...
答:用p3来表示一维数组的各元素,只需要将用p1表示的数组元素*(p1+i)中的p1换成*p3即可,表示为*(*p3+i)。同样,对二维数组b来说,b[i]表示第i行首地址,将其传递给指针变量p2,使其指向该行。该行的元素用p2表示为*(p2+i)。若作p3=&p2,则表示p3指向p2,用p3表示的二维数组第i行元素为:*(*p3+i)。这...

二维数组的指针,某一行的指针,某一元素的指针各代表什么含义?
答:因此,二维数组指针就是行指针.2)int 单个int类型元素的指针,也可以作为一维数组的指针,同样原因:数据宽度一致,都是4字节.因此a[0]表示数组首行,而行数据是个int型的一维数组,因此其类型为 int *,所以可以直接赋值.同样 a[0][0]表示数组首行首元素,因此取地址后也可以直接赋值给int *类型指针.最后...

C语言 二维数组 指针
答:a+2是指向第三行的,二维数组可以看作是以行为数组名的一维数组比如 int a[2][2]数组名是a[2]在这里*(a+2)代表的是第三行首元素的地址,然后加1的话就是第3行第二元素的地址了。所以*(*(a+2)+1)代表a[2][1]

C语言程序设计中"二维数组中元素指针的表示"的例题,求详解
答:⑴ 用指针表示二维数组元素。要用指针处理二维数组,首先要解决从存储的角度对二维数组的认识问题。一个二维数组在计算机中存储时,是按行存储的,即先存储第一行的元素,再存储第二行的元素。当把每一行看作一个整体,即作为一个大的数组元素时,原来的二维数组也就变成一个一维数组了。而每个大数组...

c++中二维数组的指针如何定义?
答:二维数组的指针就是指针的指针,比如一个int型二维数组:int array[2][3];指向它的指针就可以定义成:int **p;如何使用这个指针呢,就和使用普通二维数组一样,比如第一行第二个元素:p[0][1]

C语言中如何用指针运算符来表示一个二维数组的元素及地址?
答:二维指针,就是说第一维是指针,第二维还是指针;拿*(*(a+i)+j)来说:a是数组的首地址吧,然后+i,就是说a地址向后偏移i位。就是a+i的地址了,注意,这里a+i只是地址,用*符号取出该地址的数据,就是*(a+i),这里*(a+i)就是第一维指针,它指的是地址,不是数据。而且后面的*(a+i...

c语言用二维数组名引用元素的指针表示方法:
答:二维数组名a是一个指向指针的指针。也是一个指针数组名,它含3个元素,a[0]a[1],a[2]。虽然a存储的地址是该数组首元素的地址,但它指向的并不是一个变量,而是一个指针。应为a是一个指向指针的指针,它指向的是和自己存储的地址相同的指针,即a[0],a[0]是第一行一维数组的指针,可以指向...

c++中怎么通过指向二维数组的指针给二维数组赋值
答:2. 二级指针 指向指针的指针称为二级指针,即二级指针不是指向一个普通变量,而是指向一个指针。如int **p,*p并不表示一个变量的值,而是另一个指针。二、二级指针指向二维数组 int a[3][4];此时的a即是一个二级指针,*a指向二维数组的首地址(也是a[0]的首地址),*(a+1)指向a[1]的首...