• 理解透C语言一维数组,二维数组这一篇就够啦!


    前言
    💖作者龟龟不断向前
    简介宁愿做一只不停跑的慢乌龟,也不想当一只三分钟热度的兔子。
    👻专栏C++初阶知识点

    👻工具分享

    1. 刷题: 牛客网 leetcode
    2. 笔记软件:有道云笔记
    3. 画图软件:Xmind(思维导图) diagrams(流程图)

    在这里插入图片描述

    如果觉得文章对你有帮助的话,还请点赞,关注,收藏支持博主🙊,如有不足还请指点,博主及时改正

    数组

    1.一维数组的创建和初始化

    1.1一维数组的创建

      数组:一组相同类型元素的集合。跟数学中的集合是类似的。

    创建方式:

    type_t   arr_name   [const_n];
    
    //type_t 是指数组的元素类型
    
    //const_n 是一个常量表达式,用来指定数组的大小
    
    • 1
    • 2
    • 3
    • 4
    • 5

     

    1.2初始化举例

    举例

    int main()
    {
    	int arr1[10];//10个元素的数组,元素未初始化,元素值是随机值
        
    	int arr2[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//10个元素的数组,元素完全初始化
        
    	int arr3[10] = { 1, 2, 3 };//10个元素的数组,数组部分初始化,未指定的部分元素默认是0
        
    	int arr4[] = { 1, 2, 3 };//编译器帮你计算出元素个数为3
    
    	//定义数组时,vs下--元素个数只能是常量表达式
    	int count = 10;
    	//int arr5[count];//error
    
    	double darr[10];//double类型的数组,有10个元素
        
    	float farr[10];//float类型的数组,有10个元素
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

     

    int arr1[10];的效果,元素为随机值与函数栈帧有关:

    在这里插入图片描述

     

    int arr3[10] = { 1, 2, 3 };的效果

    在这里插入图片描述

     

    int arr4[] = { 1, 2, 3 };的效果,编译器帮你计算出元素个数

    在这里插入图片描述

     

      所以大家创建数组根据自己的需求来,如果想让编译器帮你计算出元素个数,初始化要明确,如果想全部初始化为0,就要把元素个数指明清楚,这样的代码int arr[] = {0}可是达不到想要的效果哒

     

    1.3C99变长数组

        变长数组:可以使用变量来定义数组的大小,即数组大小可以自己输入,但是变长数组不允许初始化。

      其中vs编译器不支持C99变长数组,下面的代码我们放在linuxgcc编译器下面跑,给大家展示以下效果。

     

    #include
    
    int main()
    {
      int n = 0;
      
      printf("你想定义的数组的元素个数:\n");
      scanf("%d",&n);
    
      int arr[n];//变长数组不允许初始化
    
      for(int i = 0;i<n;++i)
      {
        arr[i] = i+1;
        printf("%d ",arr[i]);
      }
      printf("\n");
      return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

     

    在这里插入图片描述

     

     

    2.一维数组的使用

    咱们使用数组的初衷就是存储一类类型相同,元素个数较多的数,那么这些元素该如何区使用呢?如何访问这些数组元素呢?

    操作符[]会:下标引用操作符 --> 数组访问的操作符

    举例

    #include
    
    int main()
    {
    	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        
    	int sz = sizeof(arr) / sizeof(arr[0]);
        
    	for (int i = 0; i < sz; ++i)
    	{
    		printf("%d ", arr[i]);
    	}
        
    	printf("\n");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    解释

    1. 计算数组元素个数

      其中数组大小 = 元素大小 * 元素个数

      –>元素个数 = 数组大小/元素个数 使用操作符sizeof()即可求出数组大小和元素大小

    2. 下标访问

      下标是从0开始的,例如第1个元素的下标是0,第n个元素的下标是n-1

      方式: 数组名 [下标] : 下标所对应的元素

      这也非常完美地和我么之前建议的左闭右开结合在了一起,访问元素会比较方便

      arr数组中的几号元素NO.1NO.2NO.3NO.4NO.5NO.6NO.7NO.8NO.9NO.10
      元素值12345678910
      下标0123456789

    在这里插入图片描述

     

    ps:大家不要把定义数组时的[]和下标访问的[]给弄混了

    其中:

    定义数组时的[] – [元素个数] – 只能是常量表达式(VS)

    访问元素时[] – [下标] – 可以是变量

    访问元素一次只能访问一个

     

    3.一维数组在内存中的存储方式

      咱们就拿下述代码举例

    #include
    
    int main()
    {
    	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    	int sz = sizeof(arr) / sizeof(arr[0]);
    	for (int i = 0; i < sz; ++i)
    	{
    		printf("%d ", arr[i]);
    	}
    	printf("\n");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

      F10调式程序,打开内存窗口

    在这里插入图片描述

      可以发现,下标越小的元素,地址越小,小标越大的元素地址越大。即数组在内存上是一个顺序存储的结构。也就是说如果我们得到了第一个元素的地址,以及数组的元素个数,是否就能得到所有的元素了呢?— 正确的

     

    #include
    
    int main()
    {
    	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3 };
    	int sz = sizeof(arr) / sizeof(arr[0]);
    	
    	int *pa = &arr[0];
    	for (int i = 0; i < sz; ++i)
    	{
    		printf("%d ", *(pa + i));
    	}
    	printf("\n");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

      上述代码同样也可以达到访问元素的效果。

    在这里插入图片描述

     

    4.数组名是什么?

    4.1数组名的意义

    在这里插入图片描述

      一个队伍总有它的的队头队尾,在数组中当中,数组名也是起着队头的作用,数组名–首元素的地址

    int arr[10];,arr与&arr[0]在数值上是一样的。如下

    #include
    
    int main()
    {
    	int arr[10] = { 0 };
    	int sz = sizeof(arr) / sizeof(arr[0]);
    
    	printf("arr:%p\n", arr);
    
    	for (int i = 0; i < sz; ++i)
    	{
    		printf("&arr[%d]:%p\n", i, &arr[i]);
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    ps:数组名是常量地址,是不允许被修改的,允许被修改的是,数组里面的元素
     
    在这里插入图片描述

     

    4.2数组名的两个例外意义

      数组名有两个特殊情况,在这两种特殊情况下,数组名不表示首元素地址的意思

    • sizeof(arr)

      这个计算的是整个数组的大小 = 元素大小 * 元素个数

      而不是一个 指针大小 – 4

    • &arr

      这个表示整个数组的地址

     

    解释整个数组的地址的概念:

    #include
    
    int main()
    {
    	int arr[10] = { 0 };
    	printf("arr:%p\n", arr);
    	printf("&arr[0]:%p\n", &arr[0]);
    	printf("&arr:%p\n", &arr);
    
    	printf("\n");
    
    	printf("arr+1:%p\n", arr+1);
    	printf("&arr[0]+1:%p\n", &arr[0]+1);
    	printf("&arr+1:%p\n", &arr+1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

     

    在这里插入图片描述

      我们观察到,首元素地址和整个数组的地址在数值上是相同的,但是在+1上的效果是不同的,首元素地址+1跨过了4个字节(一个元素的大小),整个数组地址+1跨过了40个字节(整个数组的大小)

     

    5.二维数组的创建和初始化

      但从理解上去看二维数组,顾名思义:二维数组,二维–面,二维数组是一个有行有列的数组。

    那么我们在创建时就要指明:要创建一个几行几列的数组呢?

    #include
    
    int main()
    {
    	int arr1[3][3];//3行3列的数组,元素未初始化
        
    	int arr2[4][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 ,6};//4行4列的数组,全部初始化
        
    	int arr3[4][4] = { 1, 2, 3 };//4行4列的数组 -- 部分初始化,其他部分未0
        
    	int arr4[3][3] = { { 1, 2 }, { 2 }, { 3 } }; //3行3列数组 -- 指明行数初始化,第一行初始化未1 2 0,第二行初始化为2 0 0,第三行初始化为3 0 0
        
    	int arr5[][4] = { { 1 }, { 2 }, { 3 }, { 4 } };//省略行数初始化,编译器会帮你计算出有几行
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

     

    int arr1[3][3];的效果。

      大家可以从数学集合的角度去理解,二维数组 – 集合里面放了集合

    在这里插入图片描述

     

    int arr2[4][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 ,6};的效果

     第一行放满放第二行,第二行放满放第三行…。

    在这里插入图片描述

     

    int arr3[4][4] = { 1, 2, 3 };

    在这里插入图片描述

     

    int arr4[3][3] = { { 1, 2 }, { 2 }, { 3 } };的效果:-- 指定行初始化

    在这里插入图片描述

     

    int arr5[][4] = { { 1 }, { 2 }, { 3 }, { 4 } };的效果

    行可以省略,编译器会帮你计算,但是列是不可以省略的

    在这里插入图片描述

     

    6.二维数组的使用

    如何取出二维数组当中的元素呢,很明显要想在二维数组当中确定一个元素的位置,

    需要两个下标,1 – 行标 2 – 列表

    即访问方式: 数组名 [行下标] [列下标]

    #include
    
    int main()
    {
    	int arr[3][3] = { { 1, 2, 3 }, { 4, 5, 6,}, { 7, 8, 9 } };
    	for (int i = 0; i < 3; ++i)
    	{
    		for (int j = 0; j < 3; ++j)
    		{
    			printf("%d ", arr[i][j]);
    		}
    		printf("\n");
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

     

    7.二维数组在内存中的存储方式

      我们将每个元素的值拿出来打印一下,看看他们之间是什么样的关系。

    #include
    
    int main()
    {
    	int arr[3][3] = { 0 };
    	for (int i = 0; i < 3; ++i)
    	{
    		for (int j = 0; j < 3; ++j)
    		{
    			printf("&arr[%d][%d]:%p\n", i,j,&arr[i][j]);
    		}
    		printf("\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

     

    在这里插入图片描述

      大家注意不仅仅是圈起来的元素之间相差4,行与行之间的间隔也是4

    图解

    在这里插入图片描述

     

      也就可以理解成,C语言的这个二维数组,其中就是一个一维数组的乔装打扮,在一维数组里面放了几个一维数组,从而伪装成二维数组的样子。事实上还是一维的。物理上:还是顺序存储的。

      既然如此,我们也可以通过首元素地址和元素个数,来推出所有元素的位置了

    #include
    
    int main()
    {
    	int arr[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    
    	int *pa = &arr[0][0];
    	for (int i = 0; i < 9; ++i)
    	{
    		printf("%d ", *(pa + i));
    	}
    	printf("\n");
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

     

    8.浅浅理解二维数组的数组名

      即使二维数组物理上是顺序存储的,但是我们使用逻辑结构去理解也没有影响,int arr[4] [4]的二维数组,其中arr[0]–第一行的数组名,结构:二维数组中arr[i]–第i行的数组名–第i行的首元素地址

     

    9.数组的类型

    我们介绍过C语言的数据类型,有int,double,char……等等,但是数组的类型不是这些

    int a;–a的类型是int

    double d;–d的类型是double

    …………去掉数组名剩下的东西就是类型名(一般情况)

    类似的:

    int arr[10]– 去掉数组名arr,类型:int [10]

    int arr[10] [10]–去掉数组名,类型:int [10][]10

     

     并且我们可以使用sizeof来计算一下这个类型大小

    #include
    
    int main()
    {
    	printf("%d\n", sizeof(int [10]));
    	printf("%d\n", sizeof(int[10][10]));
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述
    本篇文章就讲到这里啦,咱们下期见,拜!

    在这里插入图片描述

  • 相关阅读:
    04-递归练习题
    腾讯mini项目-【指标监控服务重构-会议记录】2023-07-21
    A-Level Biology 真题及解析(2)
    TCP 三次握手和四次挥手机制,TCP为什么要三次握手和四次挥手,TCP 连接建立失败处理机制
    R语言用标准最小二乘OLS,广义相加模型GAM ,样条函数进行逻辑回归LOGISTIC分类...
    React如何实现国际化?
    【博学谷学习记录】超强总结,用心分享|Shell字符串
    华为ensp nat转换实验
    windows10搭建llama大模型
    redisson中的分布式锁
  • 原文地址:https://blog.csdn.net/m0_64361907/article/details/127788379