本文主要介绍 C 语言二维数组中的行指针及列指针。学习笔记,仅供参考,如有错误,敬请指出。
一.行指针
在说行指针之前,先看几种指针类型(以int为例):
int* a;//a是指向整形的指针;
int* a[5];//一维指针数组(这里存放着5个指向整形的指针),a指向第一个元素的地址,a+1指向第二个......(a[5]是一个指针数组);
int (*a)[5];//指向数组(这里每个一维数组含5个元素)的指针,a是第一个一维数组的首元素地址,a+1指向第二个一维数组的首元素地址......(a是数组指针);
int (*a)();//a是指向函数的指针(函数指针);
int *a();//函数的返回类型是int *,a只是一个函数名;
常用的一维数组,如:
int a[5];
//a是一个指向非常量的常量指针,即a本身的值不能变如a=a+1就出错,但是a指向的地址的值可以变如*a=1123,此处a数据类型即是int * const;
//a的值是该数组第一个元素的地址,即a=&a[0];
//*a即第一个元素的值;
常用的二维数组,如:
int a[3][5];
//此处,a也是一个指向非常量的常量指针,如果要说什么才是行指针?那么这里的a便是!
写法 | 解释 | 指针类型 |
a+0或&a[0] | 指向第1个一维数组的地址(指向第1行) | 行指针 |
a+1或&a[1] | 指向第2个一维数组的地址(指向第2行) | 行指针 |
a+2或&a[2] | 指向第3个一维数组的地址(指向第3行) | 行指针 |
行指针是指向数组的指针,即上面几种指针类型中的 int (*a)[5];所以,当二维数组要被当做参数进行传递时,可以这样声明:
void funcByRowPtr(int (*p)[5],const int row);
或者
void funcByRowPtr(int p[][5],const int row);
附上测试代码:
#include <stdio.h>
int main()
{
void funcByRowPtr(int (*rowPtr)[5],const int row);
void printArray(const int * const colPtr,const int row,const int col);
int example[3][5]={{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15}};
funcByRowPtr(example,3);
printArray(*example,3,5);
return 0;
}
void funcByRowPtr(int (*rowPtr)[5],const int row)
{
int i=0,j=0;
for(;i<row;i++)
{
for(j=0;j<5;j++)
*(*(rowPtr+i)+j)=1;//或者写成 rowPtr[i][j]=1;
}
}
void printArray(const int * const colPtr,const int row,const int col)
{
int i=0,j=0;
for(i=0;i<row*col;i++)
{
if(j!=col-1)
{
j++;
printf("%d,",*(colPtr+i));
}
else
{
j=0;
printf("%d\n",*(colPtr+i));
}
}
printf("-------------------\n");
}
结果:
可以看到,上述函数:
void (int (*p)[5],const int row)或者void (intp[][5],const int row)
的声明方法都不具有可复用性(列数固定),为了使代码具有可复用行,可以考虑使用列指针。
二.列指针对于一个二维数组:
int a[3][5];
前面已经知道,a即是它的行指针,a+0表示第1行的地址,a+1表示第2行地址…
或者可以说成&a[0]表示第1行的地址,&a[1]表示第2行的地址…
那么a[0]+0,a[0]+1…就表示第1行第1列的地址,第1行第2列地址…
a[1]+0,a[1]+1就表示第2行第1列地址,第2行第2列地址…
写法 | 解释 | 指针类型 |
a[0]+0或&a[0][0] | 指向第1行第1列的地址 | 列指针 |
a[0]+1或&a[0][1] | 指向第1行第2列的地址 | 列指针 |
a[1]+0或&a[1][0] | 指向第2行第1列的地址 | 列指针 |
a[1]+1或&a[1][1] | 指向第2行第2列的地址 | 列指针 |
像上面的a[row]+col即列指针,列指针经过一次解引用就可以转化成二维数组中实际的值,列指针也是指向非常量的常量指针。
所以如果用列指针进行函数传参,可以直接声明如下:
void funcByColPtr(int * const colPtr,const int row,const int col);
附上测试代码:
#include <stdio.h>
int main()
{
void funcByColPtr(int * const colPtr,const int row,const int col);
void printArray(const int * const colPtr,const int row,const int col);
int example[3][5]={{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15}};
funcByColPtr(*example,3,5);
printArray(*example,3,5);
return 0;
}
void funcByColPtr(int * const colPtr,const int row,const int col)
{
int i=0;
for(;i<row*col;i++)
{
*(colPtr+i)=2;//这里是考虑到二维数组本质上也是按顺序排列的
}
}
void printArray(const int * const colPtr,const int row,const int col)
{
int i=0,j=0;
for(i=0;i<row*col;i++)
{
if(j!=col-1)
{
j++;
printf("%d,",*(colPtr+i));
}
else
{
j=0;
printf("%d\n",*(colPtr+i));
}
}
printf("-------------------\n");
}
结果:
综上所述:对行指针解引用,可以得到列指针,对列指针解引用,可以得到具体的元素值:
但是这并不表示行指针可以作为二级指针进行函数传参!
以下是将行指针作为二级指针的实参进行传递,导致编译错误的代码:
int main()
{
void wrongFunc(int ** rowPtr,const int row,const int col);
void printArray(const int * const colPtr,const int row,const int col);
int example[3][5]={{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15}};
wrongFunc(example,3,5);
printArray(*example,3,5);
return 0;
}
void wrongFunc(int ** rowPtr,const int row,const int col)
{
int i=0,j=0;
for(;i<row;i++)
{
for(j=0;j<col;j++)
{
*(*(rowPtr+i)+j)=3;
}
}
}
void printArray(const int * const colPtr,const int row,const int col)
{
int i=0,j=0;
for(i=0;i<row*col;i++)
{
if(j!=col-1)
{
j++;
printf("%d,",*(colPtr+i));
}
else
{
j=0;
printf("%d\n",*(colPtr+i));
}
}
printf("-------------------\n");
}
编译时,提示:
warning: passing arg 1 of `wrongFunc' from incompatible pointer type
原因是函数的第一个参数类型是int **,而实际接收到的参数却是:
int(*)[5];这是两种不同类型的指针类型!