用指针访问二维数组

前言
如何理解二维数组?我们以二维的方式理解二维数组,他在存储时却是一维的。

用指针访问二位数组
例:int a[3] [4] = {1,3,5,7,9,11,13,15,17,19,21,23};

a[0] [0]    a[0] [1]    a[0] [2]    a[0] [3]
a[1] [0]    a[1] [1]    a[1] [2]    a[1] [3]
a[2] [0]    a[2] [1]    a[2] [2]    a[2] [3]
我们想象的二维数组的存储方式:3行4列

a[0] [0]
a[0] [1]
a[0] [2]
a[0] [3]
a[1] [0]
a[1] [1]
a[1] [2]
a[1] [3]
a[2] [0]
a[2] [1]
a[2] [2]
a[2] [3]
我们认为前四个是一个以a[0]为数组名的一位数组,共有四个int元素

中间四个是名为a[1]的一维数组

最后四个是名为a[2]的一维数组

 

 通过指针访问二维数组的不同形式

 

*a和a 是两个完全不同的概念:

a看待这个数组认为这个数组是一维数组,它自身加一会转向下一个一维数组即a+1

*a指向的是每个元素都是整数的一维数组所以就认为 *a+0 指向的就是整数,加一就是下一个整数

为什么不能用*p=a

int x,*p;
double y,*q;
p=&x;
q=&y;
p=q;//是错的
//p是指向四个字节为存储单元的地址
//q是指向八个字节为存储单元的地址
//两者不可以等价

二维数组元素的访问的四种方式:

1、通过下标访问数组元素

int a[3][4];
for (int i=0; i<3; i++)
    for (int j=0; j<4; j++)
        a[i][j] = i+j;

2、通过数组首地址访问数组元素
对于二维数组元素a[i] [j], “【】”实际上是变址运算符,即将元素a[i] [j]的存储地址转换为a[i] + j。

3、通过指针访问数组元素(以一维数组的角度“看待”二维数组”)

int a[3][4];
int *p=&a[0][0];
for (int i=0; i<3; i++)
    for(int j=0; j<4; j++)
        *(p++) = i+j;        //相当于*p=i+j;p++;


在这里,指针p被定义为:“指向int的指针”,也就是说:p指针“认为”它指向的是一个一维数组,每个元素都是int型的,共有12个元素。

4、通过指针访问数组(以二维数组的角度“看待”数组)

int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int (*p)[4];        
/*
对p指针的理解:
*p声明了p的指针。
p是指向什么的指针呢?
指向了一个包含了4个整数的一维数组
*/
p=a;
for(int i=0; i<3;i++)
    for (int j=0;j < 4;j++)
        *(*(p+i)+j)=i+j;

指针这样定义之后,==指针p将以和数组a完全相同的“视角”去看待二维数组。==也就是说,a可以怎么使用,p也可以同样怎么使用

//例如:此处*(*(p+i)+j)替换为p[i][j],a[i][j],*(*(a+i)+j)都是等价的
1
指向字符串的二维数组
char *str[3]={"Red","Green","Blue"};//方括号的优先级要高于"*"优先级
//意思是str是具有三个元素的数组,数组里面存储的是指向字符的指针

实例:学生成绩
score数组中存放了3个学生4们功课的成绩

通过调用average函数计算所有学生所有成绩的平均值

通过调用search函数显示第n个学生4门功课的成绩。

思路:

需要定义一个二维数组score,每行存储一个学生的4们功课的成绩。有3行,则存储了3个学生的成绩。

65    70    70    60
80    87    90    81
90    99    100    98
当编写函数average计算所有学生成绩平均值的时候,可以用一维数组的角度去看待这个score数组,也就是说,“认为”这个数组有12个成绩,直接求和,在计算平均分就行了

当编写函数search显示第n个学生的4门功课的时候,则使用二维数组的角度去看待这个score数组,也就是说,“认为”这个数组有3行,每行4个元素

void average(float *p,int n)
{
    //以一维数组的方式看待学生成绩
    float *p_end;
    float sum=0,aver;
    p_end=p+n;
    for ( ; p<p_end;p++)
        sum=sum+(*p);
    aver=sum/n;
    printf("平均成绩为:%5.1f\n",aver);
}
void search(float (*p)[4],int n)//可以写成 float p[][4]
{
    //以二维数组的方式看待学生成绩,视角与score相同
    int i;
    printf("第%d个学生的成绩为: ",n);
    for (i=0;i<4;i++)
        printf("%5.1f",*(*(p+n)+i));  //可以替换成p[n][i]
}

int main()
{
    float score[3][4]={
   
   {65,67,70,60},{80,87,90,81},{90,99,100,98}};
    average(&score[0][0],12);        //可以替换成score[0],*(score+0)
    search(score,2);
    return 0;
}


思考 (如果看不懂,请回退往前再看)
(1)同是给函数传递score二维数组,为什么average函数和search函数传参时采用了不同的方式?

average(&score[0][0],12);        //可以替换成score[0],*(score+0)
search(score,2);                //显示第二个学生的成绩


二维数组作为函数的参数
1、以一维数组的角度“看待”二维数组

 

 2、以二维数组的角度“看待”一维数组

 

课后练习
题目描述:写一个inverse函数,此函数的功能是:将一个 3*4 的二维数组中的值按逆序重新存放。

程序运行结果范例

请输入 3*4 的二维数组:

1 2 3 4

5 6 7 8

9 10 11 12

逆序存放后的结果为:

12 11 10 9

8 7 6 5

4 3 2 1

提示:

这个程序有多种实现思路,尝试使用两种方法实现

答案
方法一:用二维数组的方式看待程序:

 

void inverse(int a[][N],int b[][N])
{
    int i,j;
    for (i=0;i<M;i++)
        for (j=0;j<N;j++)
            b[M-i-1][N-j-1]=a[i][j]
}

int main()
{
    int a[M][N],b[M][N];
    int i,j;
    printf("请输入 %d*%d 的二维数组:\n",M,N);
    for (i=0;i<M;i++)
        for (j=0;j<N;j++)
            scanf("%d",&a[i][j]);
    inverse(a,b);
    printf("逆序存放后的结果为:\n");
    for (i=0;i<M;i++)
    {
        for (j=0;j<N;j++)
            printf("%d\t",b[i][j]);
    }
}

方法二: 用一维数组的方式看待程序: 

 

void swap(int *p1,int *p2)
{
    int tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}

//以 int *a 这样的方式传参,使得在子程序中以一维的方式看待数组,
//也就是说,把数组看成了一个具有 M*N 个元素的,每个元素都是 int 的数组
void inverse(int *a,int n)
{
    int *p,*q;
    for (p=a,q=a+n-1;p<=q;p++,q--)
    {
        swap(p,q);
    }
}

int main()
{
    int a[M][N];
    int i,j;
    printf("请输入 %d * %d 的二维数组: \n");
    for (i=0;i<M;i++)
        for (j=0;j<M;j++)
            scanf("%d",&a[i][j]);
    inverse(&a[0][0],M*N);
    printf("逆序存放后的结果为: \n");
    for (i=0;i<M;i++)
    {
        for (j=0;j<N;j++)
            printf("%d\t",a[i][j]);
    	printf("\n");
    }
    return 0;
}

程序用到了M,N两个常量,这样的程序具有良好的灵活性。 

————————————————
版权声明:本文为CSDN博主「宗谷.」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Zonggu/article/details/124051465

猜你喜欢

转载自blog.csdn.net/modi000/article/details/131916851