C/C++中的二维数组,以及多维数组及其指针

数组是编程语言中常见的数据类型,有必要二维以及多维数组,以及对应的指针,做一个梳理,便于以后查询。

首先你要区分不同的指针,尤其是二级指针与二维数组的行指针,二级指针与指针数组。。
学习编程,最好结合计算机内存一起理解。还是先从最基本的开始。

之前写过一篇二维数组的博客,参考:
https://blog.csdn.net/edward_zcl/article/details/89100600

C语言中的二维数组

1.二维数组的定义和引用

一. 数据类型 数组名[常量表达式1][常量表达式2];

(1)假如有个二维数组array[n][m],则行下标的取值范围0~n-1

(2)列下标的取值范围0~m-1

(3)二维数组的最大下标元素是array[n-1][m-1];

假如有一个数组array[3][4];则其下标变量为 array[0][0],array[0][1],array[0][2],array[0][3],array[1][0],array[1][1],array[1][2],array[1][3],array[2][0],array[2][1],array[2][2],array[2][3]

二.二维数组的引用

数组名[下标][下标];

array[1][2]

2.二维数组初始化

(1)可以将所有数据写在一个大括号内,按照数组元素排序对元素赋值。int array[2][2]={1,2,3,4};

(2)在为所有元素赋初值时,也可以省略行下标,但是不能省略列下标。int array[][3]={1,2,3,4,5,6};

(3)也可以分行给数组元素赋值。 int a[2][3]={{1,2,3},{4,5,6}}; a[0][0]=1;a[0][1]=2;a[0][2]=3…

在分行赋值时,可以只对部分元素赋值。int a[2][3]={{1,2},{4,5}};a[0][0]=1;a[0][1]=2;a[0][2]=0;a[1][0]=4;a[1][1]=5;a[1][2]=0;

(4)二维数组也可以直接对数组元素赋值。int a[2][3]; a[0][0]=1;

#include<stdio.h>
/*任意输入一个三行三列的二维数组,求对角元素之和*/
int main()
{
  int a[3][3];/*定义一个三行三列的数组*/
  
  int i,j,sum=0; /*定义循环控制变量好保存数据变量sum*/
  printf("please input:\n"); /*利用循环数组对数组元素进行输入*/

   for(i=0;i<3;i++)
   {
       for(j=0;j<3;j++)
       {
         scanf("%d",&a[i][j]);
       }
   }

/*利用循环数组对对角线对其求和*/
      for(i=0;i<3;i++)
   {
       for(j=0;j<3;j++)
       {
           if(i==j)
           {
           
            sum=sum+a[i][j];
           }
       }
   }

      printf("the result is : %d\n",sum); /*输出最后的结果*/
  return 0;


}

3.二维数组应用(索引)

#include<stdio.h>

int main()
{
    int a[2][3],b[3][2]; /*定义两个数组*/
    int max,min;/*表示最大值和最小值*/
    int h,l,i,j;/*用于循环控制*/
    for(i=0;i<2;i++)  /*通过键盘为数组元素赋值*/
    {
        for(j=0;j<3;j++)
        {
           printf("a[%d][%d]=",i,j);
           scanf("%d",&a[i][j]);
        }
    }

    printf("输出二维数组:\n");
    for(i=0;i<2;i++)
    {
        for(j=0;j<3;j++)
        {
        printf("%d\t",a[i][j]);/*使元素分行显示*/
        }
        printf("\n");
    }
    /*求数组中最大元素及其下标*/

    max=a[0][0];
    h=0;
    l=0;

    for(i=0;i<2;i++)
    {
        for(j=0;j<3;j++)
        {
           if(max<a[i][j])
           {
             max=a[i][j];

             h=i;
             l=j;
           }
        }
    
    }

    printf("数组中最大元素是:\n");

    printf("max:a[%d][%d]=%d\n",h,l,max);
    /*求数组中最小元素及其下标*/

    min=a[0][0];

    h=0;
    l=0;
    for(i=0;i<2;i++)
    {
       for(j=0;j<3;j++)
       {
          if(min>a[i][j])
          {
            min=a[i][j];
            h=i;
            l=j;
          }
       }
    }


    printf("数组中最小元素是:\n");
    printf("min:a[%d][%d]=%d\n",h,l,min);
    /*将数组a转换后存入数组b中*/
    for(i=0;i<2;i++)
    {
        for(j=0;j<3;j++)
        {
          b[j][i]=a[i][j];
        }
    }

    printf("输出转换后的二维数组:\n");

    for(i=0;i<3;i++)
    {
      for(j=0;j<2;j++)
      {
      
      printf("%d\t",b[i][j]);
      }
       printf("\n");   /*使元素分行显示*/
    }
  return 0;
}



以下参考自:https://blog.csdn.net/qq_21808961/article/details/78213326

C语言 通过指针访问一维数组,二维数组,三维数组。

/**
通过指针来访问一维数组,二维数组,多维数组
*/
 
#include<stdio.h>
const int COLS=3;
const int COUNT=4;
//通过一级指针,计算偏移量来遍历一维数组
void printSingleDimensionalArray(int *data,int data_len);
//通过一级指针,计算偏移量来遍历二维数组:
void printDoubleDimensionalArray(int *array,int rows,int cols);
//通过一级指针,计算偏移量来遍历三维数组:
void printThreeDimensionalArray(int *array_3,int rows,int cols,int count);
//使用指向二维数组的指针来遍历三维数组
void printThreeDimensionalArray2(int (*p)[COLS][COUNT],int rows);
 
void main()
{
    int data[]={1,2,3,4,5,6,7,8,9};
    int data_len=sizeof(data)/sizeof(data[0]);
    printf("data[6]=%d\n",*(data+6));//7
    printf("一维数组data:\n");
    printSingleDimensionalArray(data,data_len);
    int array[2][3]={{1,2,3},{4,5,6}};
    printf("二维数组array:\n");
    printDoubleDimensionalArray(array,2,3);
    int count=0;
    int array_3[2][3][4];
    int i,j,k;
    for(i=0;i<2;i++)
    {
        for(j=0;j<3;j++)
        {
            for(k=0;k<4;k++)
            {
 
                array_3[i][j][k]=count++;
            }
 
        }
    }
    printf("三维数组array_3:\n");
    printThreeDimensionalArray(array_3,2,3,4);
    //三维数组的初始化
    int array_33[2][3][4]=
    {
        {
            {1,2,3,4},
            {5,6,7,8},
            {9,10,11,12},
        },
        {
            {13,14,15,16},
            {17,18,19,20},
            {21,22,23,24},
        }
    };
    printf("三维数组array_33:\n");
    printThreeDimensionalArray(array_33,2,3,4);
    printf("三维数组array_33:\n");
    printThreeDimensionalArray2(array_33,2);
}
//通过一级指针,计算偏移量来遍历一维数组
void printSingleDimensionalArray(int *data,int data_len)
{
    int i;
    for(i=0;i<data_len;i++)
        printf("%4d",*(data+i));//7
    printf("\n");
}
//通过一级指针,计算偏移量来遍历二维数组:
void printDoubleDimensionalArray(int *array,int rows,int cols)
{
    int i,j;
    for(i=0;i<rows;i++)
    {
        for(j=0;j<cols;j++)
        {//通过一位指针,计算偏移量来遍历二维数组:
            printf("%4d",*(array+i*cols+j));
        }
        printf("\n");
    }
}
//通过一级指针,计算偏移量来遍历三维数组:
void printThreeDimensionalArray(int *array_3,int rows,int cols,int count)
{
    int i,j,k;
    for(i=0;i<rows;i++)
    {
        printf("{\n");
        for(j=0;j<cols;j++)
        {
            for(k=0;k<count;k++)
            {
 
//                array[i][j][k]=count++;
//                printf("%4d",array_3[i][j][k]);
                printf("%4d",*(array_3+i*3*4+j*4+k));
            }
            printf("\n");
        }
        printf("}\n");
    }
}
//使用指向二维数组的指针来遍历三维数组
void printThreeDimensionalArray2(int (*p)[COLS][COUNT],int rows)
{
    int i,j,k;
    for(i=0;i<rows;i++)
    {
        printf("{\n");
        for(j=0;j<COLS;j++)
        {
            for(k=0;k<COUNT;k++)
            {
 
//                array[i][j][k]=count++;
                printf("%4d",p[i][j][k]);
//                printf("%4d",*(array_3+i*3*4+j*4+k));
            }
            printf("\n");
        }
        printf("}\n");
    }

}

结果:

data[6]=7
一维数组data:
   1   2   3   4   5   6   7   8   9
二维数组array:
   1   2   3
   4   5   6
三维数组array_3:
{
   0   1   2   3
   4   5   6   7
   8   9  10  11
}
{
  12  13  14  15
  16  17  18  19
  20  21  22  23
}
三维数组array_33:
{
   1   2   3   4
   5   6   7   8
   9  10  11  12
}
{
  13  14  15  16
  17  18  19  20
  21  22  23  24
}
三维数组array_33:
{
   1   2   3   4
   5   6   7   8
   9  10  11  12
}
{
  13  14  15  16
  17  18  19  20
  21  22  23  24
}

Process returned 2 (0x2)   execution time : 0.312 s
Press any key to continue.

讲真,他这个讲的其实挺好,但是确实错的。。运行了会报错。。可能是c++标准不同,或者是他代码写露了什么。。

但是为了简便,或者想使用多级指针的时候怎么办。或者想使用计算机内存更大的静态栈区,而不是常用的数据区,你就需要更深一步了解了。

比如:

定义二维指针数组与定义一维指针数组差不多,只是矩阵的维度增加了一维而已。

下面通过具体的实例来说明如何定义一个二维数组

int *p[2][3];  // 定义一个二维数组,只是定义,并没有分配地址空间
int i,j;  // 数组的行数和列数
// 下面的2个for循环是用来对二维指针数组进行初始化的,也即分配地址。如果不进行初始化操作,就会使指针变为野指针(即指向不明)。
for(i=0; i<2; i++)
    for(j=0; j<3; j++)
        p[i][j] = (int *)malloc(sizeof(int));
*p[0][1] = 2; // 对指针数组中指针所指向的内存单元进行赋值操作
printf("%d\n", *p[0][1]);  // 输出结果

也有人说,指针就是数组,其实这个是可以正确理解的。一个二维数组的数组名就代表一个二级指针,可以用指针来操作二维数组,这是到处都找的到的可以这样:

int **p=NULL;
int a[i][j];
p=a;
a[i][j]=*(*(p+i)+j);
动态定义一个二维数组:
需要用两次循环,free的时候也是得用循环;

先给出结论:第一种是对的,第二种是错的,一定要记住,二级指针是二级指针,但是关于二维数组,有专门定义的数组指针,等级一样,但是使用不同,那个叫二维数组的行指针,参考:
https://blog.csdn.net/edward_zcl/article/details/89100600
https://www.cnblogs.com/zou107/p/4909847.html (行指针三维形式)

实际上这里应该这样描述:
有两种方式(假设数组是a[3][4]):
一、一个一个的取元素

int a[3][4]; int *p; p=a[0];

则将指针指向了数组a的第一个元素
二、一行一行的取元素

int a[3][4];
int (*p)[4];
p=a;

则创建了一个指向包含4个元素的指针,它可以一次指向数组的一行”

更高维形式:

int array[2][2]={{1,2},{3,4}};
int* p[2][2];//here...
int (*p)[2][2];

实际上用不完。。

或者你再看一个例子:
问题描述:怎么让一个二维指针指向一个二维数组
如: **p=a[M][N]

二级指针的原理
它是指向内存地址的地址,简单说就是取两次地址,一维数组,二维数组它们的元素都对应拥有一个暂时分配的内存地址,就是说只需要一个一级指针就可以完成取址,如果你用一个二级指针去取址是会取到乱值,如果是系统的地址系统就会崩溃(我就是试过用指针把编译器搞崩溃了),我下面例子说明一下:
一级指针取址:

char a[10];
char *p;
p=a/*将a[10]首地址赋值给一级指针*/
scanf("%s",p)/*编译系统会移动自动指针*/
char a[10][10];
char *p;
p=a[0]/*将a[10][10]首地址赋值给一级指针*/
scanf("%s",p)/*编译系统会移动自动指针*/

二级指针:

char *a[]={"12","34","56"};/*定义一个指针数组*/
char **p;/*二级指针*/
p=a;
printf("%s",*p);/*输出12*/

C语言严格区分字符串数组与字符数组,实际上一个字符串就等价于一个一维字符数组,并且结尾以/0结束,给出的也是字符串首地址,%s输出会直接全部输出,直到/0结束。
参考:https://blog.csdn.net/lemon_jay/article/details/82917000

这里我解释一下,定义一个指针数组,就是数组里面又有地址,你仔细看看,数组有地址,指针数组里面的字符串如(“12”)也是有地址的,这样就需要用一个二级指针指向它了,就是二级寻址,这是*p就不再是元素,就变成字符串"12"的首地址,由于系统自动移动指针,所以就输出12
呵呵,如果你明白,那么三级指针也是同样道理,定义一个指向指针的指针数组,用一个
三级指针实现三级寻址,就是找三次地址,这里我就不举例了,怕你不明白了,呵呵……你现在明白了吗?

另外,这是通过以为的形式访问高维数组,这个才是对的。。
实现代码:

int a[m][n];
int *p = &a[0][0];

通过p[i*n+j]访问a[i][j]
在C语言和C++语言中,数组元素全为指针的数组称为指针数组。
一维指针数组的定义形式为:“类型名 *数组标识符[数组长度]”。
例如,一个一维指针数组的定义:int *ptr_array[10]。

这个人就更加高级,采取了取巧的方法,这种方式避免的类型兼容。

#define N 2
typedef char T_Array[N][N];
T_Array aa;
T_Array * p = &aa;



不止我一个人发现了这个问题,比如:https://blog.csdn.net/Bennett2251/article/details/74854406
果然谭浩强那本C语言的书某些知识点是错误的,今天在用代码实现的时候发现了错误。比如如何用指针变量引用二维数组,书中写的是定义指针变量和定义一维的时候一样,只是引用的时候不同而已,但实际去写代码的时候是错误的。举例引用二维整形数组。
int a[col]; //定义一个row行col列的二维数组
int (*p)[col]; //定义引用二维数组的指针变量,p为指针变量名,col为二维数组的列大小(书中写的是int *p 即可,但是实际上是错误的)
p=a; //让指针变量指向二维数组
((p+i)+j) //引用二维数组中的i行j列的元素
这只是我发现书中的某一个错误点,希望其他学习者在学习的时候能够注意。




最后,给出一个通用的,最适合处理大型的,多维的数组数据的方法。
请教在C语言中如何定义三维动态数组?

和二维类似, 只不过再多一层。 比如三维int 数组, 定义动态3 4 5

那么代码可以是:

int *** a;
int i,j;
a=(int***)malloc(sizeof(int **)*3);
for(i = 0; i < 3; i ++)
{
    a[i] = (int **) malloc(sizeof(int *) *4);
    for(j = 0; j < 4; j ++)
        a[i][j] = (int *)malloc(sizeof(int)*5);
}

这样得到的a
类似于int aa[3][4][5];

又或者:用C语言怎么实现三维以上动态数组
和二维类似 一层层申请就好。

以下是一个三维的例子

int i,j,k;
int m,n,p;
int ***a;
scanf("%d%d%d",&m,&n,&p);//make a array[m][n][p]
a=(int***)malloc(sizeof(int **) * m);
for(i = 0; i < m ; i ++)
{
    a[i] = (int **)malloc(sizeof(int*)*n);
    for(j = 0; j < n; j ++)
    {
        a[i][j] = (int *)malloc(sizeof(int) *p);
        for(k = 0; k < p; k ++)
            scanf("%d",&a[i][j][k]);
    }
}

又比如:
用C语言,动态三维数组
编写一个函数CreateGrid(int m, int n, int t),用来创建一个动态的三维数组,其中m、n、t分别表示该数组每一维的长度。要求整个数组的存储空间都是用用C语言的库函数malloc函数动态申请的。另外编写一个FreeGrid函数,用来释放这个三维数组。

1、先说二维,可以这么理解:int n[3]有3个int那么,int m[5][3]有5个int[3]赋值时:n[1]=3把3给1号m[4]={5,9,4}m[4]是个int[3]类型,这么赋值,也就是这么赋值:m[4]的[0]是5:m[4][0]=5m[4][1]=9m[4][2]=4懂了吗?三维甚至更多维大同小异,比如int k[4][5][3]有4个int[5][3]

2、例程:

int*** CreateGrid(int m,int n,int t)
{
    int*** tt = NULL; 
    tt = (int***)malloc(sizeof(int)*m);
    for(int i=0;i<m;i++)
    {
        tt[i] = (int**)malloc(sizeof(int)*n);;
        for (int k=0;k<n;k++)
        {
            tt[i][k] = (int*)malloc(sizeof(int)*t);
        }
    }
    return tt;
}
void FreeGrid(int*** tt,int m,int n,int t)
{
    if(tt != NULL)
    {
        for(int i=0;i<m;i++)
        {
            for (int j=0;j<n;j++)
                                                    {
                free((tt[i][j]));
            }
            free(tt[i]);
        }
        free(tt);
        tt = NULL;
    }
}

或者这样写:

   int*** CreateGrid(int m,int n,int t)
    {
    int*** tt = NULL;
    tt = (int***)malloc(sizeof(int)*m);
    for(int i=0;i<m;i++)
    {
    tt[i] = (int**)malloc(sizeof(int)*n);;
    for (int k=0;k<n;k++)
    {
    tt[i][k] = (int*)malloc(sizeof(int)*t);
    }
    }
    return tt;
    }
    void FreeGrid(int*** tt,int m,int n,int t)
    {
    if(tt != NULL)
    {
    for(int i=0;i<m;i++)
    {
    for (int j=0;j<n;j++)
    {
    free((tt[i][j]));
    }
    free(tt[i]);
    }
    free(tt);
    tt = NULL;
    }
    }

又或者这样写:

#include <stdlib.h>
int *** CreateGrid(unsigned m, unsigned n, unsigned t);/*创建整形三维数组*/
void FreeGrid(int *** c1,unsigned m,unsigned n);/*释放整形三维数组*/
static void free1(int *** c1,unsigned n);
static void free2(int *** c1,unsigned m,unsigned n,unsigned k);
int *** CreateGrid(unsigned m, unsigned n, unsigned t)/*创建整形三维数组*/
{
int ***c1;
int i,j;
c1=( int ***)malloc(sizeof( int **) * m);/*分配第一维*/
if(!c1)/*第一维分配失败*/
return (int ***)NULL;
for(i=0;i!=m;++i)/*分配第二维*/
{
c1[i]=(int **)malloc(sizeof(int*) *n);
if(!c1[i])
break;
}
if(i!=m)/*第二维分配失败,释放以前分配到的内存*/
{
free1(c1,i);
return (int ***)NULL;
}
for(i=0;i!=m;++i)/*分配第三维*/
{
for(j=0;j!=n;++j)
{
c1[i][j]=(int *)malloc(sizeof(int) * t);
if(!c1[i][j])
break;
}
if(j!=n)
break;
}
if(j!=n)/*第三维分配失败,释放以前分配到的内存*/
{
free2(c1,m,n,j);
return (int ***)NULL;
}
return c1;
}
static void free1(int *** c1,unsigned m)/*释放前m个指针*/
{
int i;
for(i=0;i!=m;++i)
free(c1[i]);
free(c1);
}
static void free2(int *** c1,unsigned m,unsigned n,unsigned k)
{
int i,j;
for(i=0;i!=m;++i)
for(j=0;j!=n;++j)
free(c1[i][j]);
for(i=0;i!=k;++i)
free(c1[m][i]);
free1(c1,m);
}
void FreeGrid(int *** c1,unsigned m,unsigned n)/*释放内存*/
{
free2(c1,m,n,0);
}

最笨的办法是采用C自带的数组类型,但是可能会遇到内存不足的问题,而且它的访问,讲真不是那直观。
如某人说:推荐定义一个一维数组,按三维结构进行存储

int limit[20][2]={{3,8}, {4,9}, {5,0}, {1,6}, {2,7},
{2,7}, {3,8}, {4,9}, {5,0}, {1,6},
{1,6}, {2,7}, {3,8}, {4,9}, {5,0},
{1,6}, {2,7}, {3,8}, {4,9}, {5,0}};


int limit[4][5][2]={ {{3,8}, {4,9}, {5,0}, {1,6}, {2,7}},
{{2,7}, {3,8}, {4,9}, {5,0}, {1,6}},
{{1,6}, {2,7}, {3,8}, {4,9}, {5,0}},
{{1,6}, {2,7}, {3,8}, {4,9}, {5,0}} };

注意:c语言的数组是连续存储的,而且有自己的默认值,程序存储区,数据存储区,常量存储区,静态与动态内存,自己的初始化数据格式。

如果想从内存的角度理解多维数组,多级指针,可以参见:
https://blog.csdn.net/zjy900507/article/details/80858800
https://www.zhihu.com/question/50738576?sort=created
https://www.cnblogs.com/hwli/p/10745446.html
http://c.biancheng.net/view/227.html
https://blog.csdn.net/theusProme/article/details/55656806
https://blog.csdn.net/mytzs123/article/details/77916958

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值