C|二维数组与一维指针、指针数组、数组指针的关系

我们知道,对于一维数组,其数组名可以理解为一个特殊指针,具有常量的性质,使用sizeof可以求得数组的长度,而当作为函数参数时,就退化为一个指针,此时sizeof不再能求得数组的长度了。

一维数组名可以直接赋给一个一级指针,如:

int arr[5];
int* p = a;

二维数组呢,可以理解为数组的数组,但二维数组名通常不能直接赋值给一个二级指针,通常通过数组指针或指针数组或降维来处理:

#define ROW 5
#define COL 3
int test()
{
    int a[ROW][COL];
    int(*ap)[COL] = a;
    int* pa[ROW];
    for(int i=0; i<ROW; i++)
        pa[i] = a[i];
    int* p = (int*)a;
    int* p2 = &a[0][0];
    int** pp = (int**)a; // 没什么意义   
}

以下是应用实例:

#include <iostream>
using namespace std;
#define ROW 5
#define COL 3
int main()
{
    int a[][COL]={ 
            {80,75,92},
            {61,65,71},
            {59,63,70},
            {85,87,90},
            {76,77,85} };
    int i,j;

    cout<<"用数组指针处理:"<<endl;
    int(*ap)[COL] = a;
    //int(*ap)[COL] = &a[0];
    for(i = 0;i < ROW;i++)
    {
        for(j = 0;j < COL;j++)
        {
            printf("%d ", *(*(ap+i)+j));
        }
        cout<<endl;
    }
    
    cout<<"用指针数组处理:"<<endl;
    int* pa[ROW];
    for(i=0; i<ROW; i++)
        pa[i] = a[i];
    for(i = 0; i< ROW; i++)
    {
        for(j = 0;j < COL;j++)
        {
            printf("%d ", *(pa[i]+j));
        }
        cout<<endl;
    }


    cout<<"用一级指针处理:\n";
    //int* p = (int*)a;
    int* p = &a[0][0];
    int** pp = (int**)a; // 没意义
    
    for(i = 0;i < ROW;i++)
    {
        for(j = 0;j < COL;j++) // 以下两种方式都可以
        {
            printf("%d ", p[i*COL+j]);
            //printf("%d ", *(p+i)+j);
        }
        cout<<endl;
    }
    while(1);
    return 0;
}

1 用数组指针处理二维数组

对于二维数组,在C语句中,是按照一维的方式在内存单元中连续存储的,并且是按照行、列的方式存储的。

第一维的下标决定了行元素的起始地址。

第二维的下标决定了数组元素的内存单元相对于行起始地址的偏移量。

所以,*(a[i]+j))相当于a[i][j]。

所以,可以用指针指向二维数组的一行(一个一维数组),然后可以进行行偏移,在此基础上进行列偏移。

    int(*ap)[COL] = a;
    //int(*ap)[COL] = &a[0];
    for(i = 0;i < ROW;i++)
    {
        for(j = 0;j < COL;j++)
        {
            printf("%d ", *(*(ap+i)+j));
        }
        cout<<endl;
    }    

让ap指向一个数组,这个数组有COL个元素,而ap+1进行的地址偏移是整个数组的地址偏移,相当于偏移COL个元素,可以理解为一行的偏移。

还可以使用&a[0]作为右值:

int(*ap)[COL] = &a[0];

二维数组中的int a[0]可以视为包含了COL个变量的一维数组,可以将a[0]视为一种特殊的类型int a[3],这时再进行变形,&a[0]相当于int(*)[COL],与ap的类型刚好一致。

同样,可以使用一个指针数组来申请一个动态的二维数组:

#include <stdio.h>
#include <stdlib.h>

#define N    3
#define M    4

void main()
{
    int (*a)[N];
    int i,j;

    if((a=(int(*)[N])malloc(N*M*sizeof(int)))==NULL)
    {
        printf("分配失败!");
        exit(0);
    }
    printf("当以4X3二维数组方式引用创建的动态数组时\n");
    for(i=0;i<M;i++)
    {
        for(j=0;j<N;j++)
        {
            a[i][j]=i*N+j+1;
            printf("a[%d][%d]=%d\t",i,j,a[i][j]);
        }
        printf("\n");
    }
    printf("当以3X4二维数组方式引用创建的动态数组时\n");
    for(i=0;i<N;i++)
    {
        for(j=0;j<M;j++)
        {
            a[i][j]=i*M+j+1;
            printf("a[%d][%d]=%d\t",i,j,a[i][j]);
        }
        printf("\n");
    }
    free(a);
    while(1);
    return ;
}

2 用指针数组处理二维数组

定义一个指针数组,数组元素是指针,数组元素的指针再指向一个一维数组:

    int* pa[ROW];
    for(i=0; i<ROW; i++)
        pa[i] = a[i];
    for(i = 0; i< ROW; i++)
    {
        for(j = 0;j < COL;j++)
        {
            printf("%d ", *(pa[i]+j));
        }
        cout<<endl;
    }

也可以用指针数组来定义一个动态的二维数组:

#include <stdio.h>
#include <stdlib.h>

#define N    3
#define M    4

void main()
{
    int *a[N];
    int i,j;

    for(i=0;i<3;i++)
    {
        if((a[i]=(int*)malloc(M*sizeof(int)))==NULL)
        {
            printf("分配失败!");
            exit(0);
        }
    }

    for(i=0;i<N;i++)
    {
        for(j=0;j<M;j++)
        {
            a[i][j]=i*M+j+1;
            printf("a[%d][%d]=%d\t",i,j,a[i][j]);
        }
        printf("\n");
    }
    
    for(i=0;i<N;i++)
        free(a[i]);
    while(1);
    return ;
}

3 用一级指针处理二维数组

用一个一级指针指向二维数组的首元素,因为二维数组是连续存储的,所以可以依次处理偏移的每一个内存单元。

    //int* p = (int*)a;
    int* p = &a[0][0];

一般不用一个二级指针来处理二维数组,但可以用一个二级指针来申请一个二维动态数组:

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    int n1,n2; 
    int **arr,i,j; 
    printf("请输入所要创建的动态数组的第一维长度:");
    scanf("%d",&n1);
    printf("请输入所要创建的动态数组的第二维长度:");
    scanf("%d",&n2); 

    if((arr=(int**)malloc(n1*sizeof(int*)))==NULL)//第一维的创建 
    {
        printf("分配内存空间失败!\n");
        return 0;
    }

    for(i=0;i<n1; i++) 
    { 
        if((arr[i]=(int*)malloc(n2* sizeof(int)))==NULL)//第二维的创建 
        {
            printf("分配内存空间失败!\n");
            return 0;
        }
    }
    for(i=0;i<n1;i++)
    {
        for(j=0;j<n2;j++) 
        { 
            arr[i][j]=i*n2+j+1; 
            printf("%d\t",arr[i][j]); 
        } 
        printf("\n");
    }
    for(i=0;i<n1;i++) 
    { 
        free(arr[i]);//释放第二维 
    } 
    free(arr);//释放第一维
    while(1);
    return 0; 
}

如果想使用一个二维数组做函数参数,也可以以上面同样的思路进行处理,细节请见:

C|二维数组做函数参数的5种方式

-End-

举报
评论 0