• C语言详解系列——数组详解,一维数组、二维数组


    一维数组

    一维数组的创建

    我们说,数组就是储存同一类型元素的的集合,那么数组到底改如果创建呢?

    type_t arr_name [const_n]
    type_t :数组元素的类型
    const_n:是一个常量表达式,用来指定数组的大小
    arr_name:是数组名

    我们在代码中演示如何创建数组

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

    这行代码int arr[3] = { 1,2,3 };·实现了一个含有三个元素的整形数组的创建,之后我们通过循环,遍历了数组元素,获取到了数组当中存储的三个元素。那么我们数组的创建中,在[]里面可不可以使用变量呢?

    在这里插入图片描述
    我们创建一个变量n将3赋值给他,并且将这个变量用于创建数组,我们发现编译器提示我们应输入常量表达式,因为数组的创建,在C99标准之前,[]中要使用一个常量,在C99标准之后支持了可变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化。

    可变长数组
    不是说数组的长度可以任意变化,而是在数组创建之前可以根据用户的输入与需求改变数组创建时的长度。当数组创建完成后,长度不可在变。

    数组的初始化

    数组初始化是指,在创建数组的同时给数组的内容一些合理的初始值

    int main()
    
    {
    	int arr[10] = {1};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    通过调试我们发现,我们将数组中第一个元素初始化为1,剩下9个元素,编译器默认初始化为0,我们称这样的初始化为不完全初始化。还有很多初始化方式例如:
    int arr[] = {1,2,3,4}这样不指定数组的大小,数组的大小就由初始化的内容来决定
    值得我们注意的是

    int main()
    {
    	char arr1[] = "abc";
    	char arr2[] = { 'a','b','c' };
    	printf("%d\n",sizeof(arr1));
    	printf("%d\n", sizeof(arr2));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    我们发现数组当中初始化同样都是给了abc三个字符为什么数组的长度不一样呢?原因是char arr1[] = "abc";这样初始化数组时"abc"这样的字符串有结束标志\0,也被算做数组的元素初始化了。

    一维数组的使用

    对于数组的使用我们可以使用[],下标引用操作符。我们可以使用他来遍历数组,实现我们需要的一些功能。

    int main()
    {
    	int arr[10] = { 0 };//数组的不完全初始化
       //计算数组的元素个数
    	int sz = sizeof(arr) / sizeof(arr[0]);
    	//对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
    	int i = 0;
    
    	for (i = 0; i < 10; i++)
    	{
    		arr[i] = i;
    	}
    	//输出数组的内容
    	for (i = 0; i < 10; ++i)
    	{
    		printf("%d ", arr[i]);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    我们可以计算数组的长度,遍历输出数组,获取数组当中任意一个元素。
    在数组使用时我们需要注意的就是

    1.数组是使用小标访问的,下标是从0开始的。
    2.数组的大小可以通过计算得到

    一维数组在内存当中的存储

    int main()
    {
    	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    	int sz = sizeof(arr) / sizeof(arr[0]);
    
    	int i = 0;
    	for (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

    在这里插入图片描述
    我们通过代码获取到了数组中每个元素的地址,通过观察我们发现,数组元素的地址,随着数组元素的下标增长而增长,我们得出结论数组在内存当中是连续存放的。随着数组下标的增长,地址也由低到高变化。

    二维数组

    二维数组的创建

    二维数组的创建其实和一维数组的创建本质上差不多,只是因为是二维数组所以多了一个行的概念

    int main()
    {
    	int arr[2][3] = { 0 };
    }
    
    • 1
    • 2
    • 3
    • 4

    这样我们就创建一个2行3列的二维数组。

    二维数组的初始化

    其实二维数组的初始化,与一维数组本质也相同,我们只需要把每一行上的代码看作一个一维数组就可以了。

    int main()
    {
    	int arr[3][4] = { 1,2,3,4,5 };
    	int arr[3][4] = { {1, 2, 3}, { 4,5 }};
    	int arr[][4] = { {2,3},{4,5} };//二维数组如果有初始化,行可以省略,列不能省略
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如上图代码,我们可以进行对二维数组的初始化,在{}中的{}用于区分每一行,还有需要注意的地方就是在二维数组中,如果初始化,是可以省略行的,但是列不能初始化

    二维数组的使用

    同样与一维数组一样,通过使用[]获取下标的方式,看代码

    int main()
    {
    	int i = 0;
    	int arr[2][2] = {0};
    	for (i = 0; i < 2; i++)
    	{
    		int j = 0;
    		for (j = 0; j < 2; j++)
    		{
    			scanf("%d", &arr[i][j]);
    		}
    	}
    
    	for (i = 0; i < 2; i++)
    	{
    		int j = 0;
    		for (j = 0; j < 2; j++)
    		{
    			printf("%d", arr[i][j]);
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述
    我们首先创建一个2行2列的二维数组,之后遍历数组进行赋值,再次遍历数组输出。是不是大致的用法与一维数组相同。

    二维数组在内存中的存储

    我们说二维数组在创建、初始化、使用等方面都跟一维数组极其相同,但是一个是一维数组一个是二维的,在储存这方面应该有所不同吧,事实是否是这样的呢?我们在代码中寻找答案:

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

    在这里插入图片描述
    我们通过遍历数组,打印了二维数组中每个元素的地址发现,其实二维数组在内存当中也是连续储存的。每一行的最末尾的元素与下一行第一个元素的地址相邻,地址也是随着数组元素下标的增大而增大的,这样看来,在内存中的存储方式还是与一维数组相同。

    数组的越界访问

    数组的下标是有范围限制的,数组的下标规定,从0开始,如果有n个元素,那么最后一个元素的下标就是n-1。
    如果我们访问时下标小于0或者大于n-1,那么就是数组的越界访问了,超出了数组合法空间的访问
    例如:

    int main()
    {
    	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    	int i = 0;
    	for (i = 0; i <= 10; i++)
    	{
    		printf("%d", arr[i]);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    当i = 10的时候我们就说,越界访问了,二维数组跟一维数组有同样的越界问题。

    数组作为函数参数

    冒泡排序

    
    void bubble_sort(int arr[])
    {
    	int i = 0;
    	int sz = sizeof(arr) / sizeof(arr[0]);
    	for (i = 0; i < sz - 1; i++)
    	{
    		int j = 0;
    		for (j = 0; j < sz - i - 1; j++)
    		{
    			if (arr[j] > arr[j + 1])
    			{
    				int tmp = arr[j];
    				arr[j] = arr[j + 1];
    				arr[j + 1] = tmp;
    			}
    		}
    	}
    
    }
    
    int main()
    {
    	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
    	int i = 0;
    
    	bubble_sort(arr);
    
    	for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
    	{
    		printf("%d ", arr[i]);
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    我们使用冒泡排序实现升序排列,原理就是将数组中的元素,依次与他相邻的元素进行比较,如果前面的元素大于与他相邻的后方元素,那么就让这两个元素交换,将数值大的元素向后放,依次进行,实现我们的需求。我们执行我们的代码发现
    在这里插入图片描述
    只有前两个元素进行了交换,之后的元素没有变化这是为什么呢?我们通过调试发现
    在这里插入图片描述
    本来应该有10个元素的数组,通过计算竟然算出的数组长度为2,这是为什么呢?原来当数组元素作为参数时,传递是数组的首地址,而并非整个数组。所以数组名字的本质其实是数组的首地址
    注:

    1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
    2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。

    所以我们对代码进行更改,我们将数组长度在主函数中算好,传递给自定义函数使用,就可以解决我们的问题。

    void bubble_sort(int arr[],int sz)
    {
    	int i = 0;
    	for (i = 0; i < sz - 1; i++)
    	{
    		int j = 0;
    		for (j = 0; j < sz - i - 1; j++)
    		{
    			if (arr[j] > arr[j + 1])
    			{
    				int tmp = arr[j];
    				arr[j] = arr[j + 1];
    				arr[j + 1] = tmp;
    			}
    		}
    	}
    
    }
    
    int main()
    {
    	int arr[] = { 10,9,8,7,6,5,4,3,2,1 };
    	int i = 0;
    	int sz = sizeof(arr) / sizeof(arr[0]);
    	bubble_sort(arr,sz);
    
    	for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
    	{
    		printf("%d ", arr[i]);
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述
    这样我们就实现了我们的需求,好了以上就是关于数组的一些知识点。

  • 相关阅读:
    牛客小白月赛52 E 分组求对数和(容斥定理+二分)
    C#代码审计实战+前置知识
    Web前端系列技术之JavaScript基础(从入门开始)⑤
    RocketMQ核心知识原理
    Linux设置开机自启动奇安信可信浏览器,并配置默认页面
    shell并发遍历目录并对文件进行处理
    使用Packet Tracer 6.0 做关于公司局域网仿真与设计课设的心得
    合宙Air724UG LuatOS-Air LVGL API控件-加载器(Spinner)
    StreamAPI的使用
    C++ map和set
  • 原文地址:https://blog.csdn.net/weixin_64182409/article/details/126024439