用指针访问二维数组

文章目录

前言

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

用指针访问二位数组

例: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;
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)都是等价的

指向字符串的二维数组

char *str[3]={ "Red","Green","Blue"};//方括号的优先级要高于"*"优先级
//意思是str是具有三个元素的数组,数组里面存储的是指向字符的指针

《用指针访问二维数组》

实例:学生成绩

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

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

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

思路:

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

65707060
80879081
909910098

当编写函数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两个常量,这样的程序具有良好的灵活性。

    原文作者:宗谷.
    原文地址: https://blog.csdn.net/Zonggu/article/details/124051465
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞