• 数组(1)


    目录

    • 一维数组的创建和初始化
    • 一维数组的使用
    • 一维数组在内存中的存储
    • 二维数组的创建和初始化
    • 二维数组的使用
    • 二维数组在内存中的存储
    • 数组越界
    • 数组作为函数参数
    • 三子棋
    • 扫雷游戏

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

    1.1 一维数组的创建

    数组是一组相同类型元素的集合。
    数组的创建方式:

    type_t arr_name [const_n];

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

    数组创建的实例:

    int main()
    {
    	int arr1[10];
    	int count = 10;
    	int arr2[count];//常量表达式才可以
    	//VS2019 VS2022 这样的IDE 不支持C99 中的变长数组
    	
    	//C99 标准之前 数组的大小只能是常量表达式
    	//C99 标准中引入了:变长数组的概念,使得数组在创建的时候可以使用变量,但是这样的数组不能初始化
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    //gcc中就支持变长数组
    #include 
    
    int main()
    {
    	int n = 0;
    	scanf("%d", &n);
    	int arr[n];//局部的变量,这些局部的变量或者数组是存放在栈区,存放在栈区上的数组,如果不初始化的话,默认是随机值
    	int i = 0;
    
    	for (i = 0; i < n; i++)
    	{
    		arr[i] = i;
    	}
    
    	for (i = 0; i < n; i++)
    	{
    		printf("%d\n", 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

    1.2 一维数组的初始化

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

    int main()
    {
    	//int arr1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//完全初始化
    	//int arr2[10] = { 1, 2, 3 };//不完全初始化,剩余的元素默认都是0
    	//int arr3[10] = { 0 };//不完全初始化,剩余的元素默认都是0
    	//int arr4[] = { 0 };//省略数组的大小,数组必须初始化,数组的大小是根据初始化的内容来确定
    	//int arr5[] = { 1, 2, 3 };
    	//int arr6[];//err
    
    	char arr1[] = "abc";
    	char arr2[] = { 'a', 'b', 'c' };
    	char arr3[] = { 'a', 98, 'c' };
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2. 一维数组的使用

    对于数组的使用我们之前介绍了一个操作符: [] (下标引用操作符),它其实就是数组访问的操作符。

    #include 
    
    int main()
    {
    	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    	//              0  1  2  3  4  5  6  7  8  9
    	//printf("%d\n", arr[5]);//[] 下标引用操作符
    	//printf("%d\n", arr[0]);//[] 下标引用操作符
    	int i = 0;
    	int sz = sizeof(arr) / sizeof(arr[0]);//10
    
    	for (i = 0; i < sz; 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
    #include 
    
    int main()
    {
    	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    	//              0  1  2  3  4  5  6  7  8  9
    	//printf("%d\n", arr[5]);//[] 下标引用操作符
    	//printf("%d\n", arr[0]);//[] 下标引用操作符
    	int i = 0;
    	int sz = sizeof(arr) / sizeof(arr[0]);//10
    
    	for (i = 0; i < sz; i += 2)
    	{
    		printf("%d ", arr[i]);
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    #include 
    
    int main()
    {
    	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    	//              0  1  2  3  4  5  6  7  8  9
    	//printf("%d\n", arr[5]);//[] 下标引用操作符
    	//printf("%d\n", arr[0]);//[] 下标引用操作符
    	int i = 0;
    	int sz = sizeof(arr) / sizeof(arr[0]);//10
    
    	for (i = sz - 1; i >= 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
    #include 
    
    int main()
    {
    	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    	//              0  1  2  3  4  5  6  7  8  9
    	//printf("%d\n", arr[5]);//[] 下标引用操作符
    	//printf("%d\n", arr[0]);//[] 下标引用操作符
    	int i = 0;;
    	int sz = sizeof(arr) / sizeof(arr[0]);//10
    
    	for (i = 0; i < sz; i++)
    	{
    		scanf("%d", &arr[i]);
    	}
    
    	for (i = 0; i < sz; 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

    总结:

    1. 数组是使用下标来访问的,下标是从0开始。
    2. 数组的大小可以通过计算得到。
    #include 
    
    int main()
    
    {
    	int arr[10] = { 0 };//10 * 4
    	printf("%d\n", sizeof(arr));//40 - 计算的是数组的总大小,单位是字节
    	printf("%d\n", sizeof(arr[0]));//4
    	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数的方法
    	printf("%d\n", sz);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

    //%p  --  是用来打印地址的
    #include 
    
    int main()
    {
    	int arr[10] = { 1, 2, 3, 4, 5 };
    	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
    • 13
    • 14
    • 15
    • 16

    一维数组在内存中的存储
    仔细观察输出的结果,我们知道,随着数组下标的增长,元素的地址也在有规律的递增。由此可以得出结论:一维数组在内存中是连续存放的
    一维数组在内存中连续存放

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

    4.1 二维数组的创建

    int main()
    {
    	//数组的创建
    	int arr[4][5];
    	char ch[3][8];
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.2 二维数组的初始化

    int main()
    {
    	//数组的初始化
    	int arr[4][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7},{5,6,7,8,9} };
    	int arr2[4][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7,5,6,7,8,9 };
    	//二维数组即使初始化了的
    	//行是可以省略的,但是列是不能省略的
    	int arr3[][5] = { {1,2,3}, {2,3,4}, {3,4,5,6,7}, {5,6,7,8,9} };
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    5. 二维数组的使用

    二维数组的使用也是通过下标的方式。

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

    6. 二维数组在内存中的存储

    #include 
    
    int main()
    {
    	int arr[4][5] = { 0 };
    	int i = 0;
    	//行号
    	for (i = 0; i < 4; i++)
    	{
    		int j = 0;
    		
    		for (j = 0; j < 5; 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
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    二维数组在内存中的存储
    通过结果我们可以分析到,其实二维数组在内存中也是连续存储的
    二维数组在内存中连续存放
    注:

    //假想是:1 2 3 4 5
    //       2 3 4 5 6
    //       3 4 5 6 7
    //       5 6 7 8 9
    //实际上:连续存放的
    
    //1. 二维数组是【一维数组】的数组
    //                元素
    //
    //2. 可以这样理解: 类比一维数组 int arr[10]  arr[j];//0~9   -->  arr[0][j]中arr[0]是数组名 j是下标
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    7. 数组越界

    • 数组的下标是有范围限制的:数组的下标规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1;所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。
    • C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以程序员写代码时,最好自己做越界的检查。
    #include 
    
    int main()
    {
    	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    	int i = 0;
    	//0~10
    	//越界访问
    	//
    	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

    注: 二维数组的行和列也可能存在越界。

    8. 数组作为函数参数

    往往我们在写代码的时候,会将数组作为参数传给函数,比如:要实现一个冒泡排序(这里要讲算法思想)函数,将一个整形数组排序。


    首先,来看一下不用函数的写法:

    //输入10个整数,对这组数进行排序
    //排序有很多的方法
    //1. 冒泡排序
    //2. 选择排序
    //3. 插入排序
    //4. 快速排序
    // ....
    
    #include 
    
    int main()
    {
    	int arr[10] = { 0 };
    	//输入
    	int i = 0;
    	int sz = sizeof(arr) / sizeof(arr[0]);
    
    	for (i = 0; i < sz; i++)
    	{
    		scanf("%d", &arr[i]);
    	}
    
    	//冒泡排序 - 升序
    	//冒泡排序 - 两两相邻的元素进行比较
    	//一趟冒泡排序让一个值来到最终应该出现的位置上
    	//1. 确定冒泡排序的趟数
    	//2. 一趟冒泡排序的实现
    
    	//趟数
    	for (i = 0; i < sz - 1; i++)
    	{
    		int j = 0;
    		//一趟内部比较的对数
    		for (j = 0; j < (sz-1-i); j++)
    		{
    
    			if (arr[j] > arr[j + 1])
    			{
    				//交换
    				int tmp = arr[j];
    				arr[j] = arr[j + 1];
    				arr[j + 1] = tmp;
    			}
    
    		}
    
    	}
    
    	for (i = 0; i < sz; 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    接着,我们运用函数来实现:

    #include 
    
    void bubble_sort(int arr[10], int sz)//这里的arr的本质是指针
    {
    	//           4       /        4      = 1
    	//int sz = sizeof(arr) / sizeof(arr[0]);//sz=1
    	int i = 0;
    
    	for (i = 0; i < sz - 1; i++)
    	{
    		int j = 0;
    		//一趟内部比较的对数
    		for (j = 0; j < (sz-1-i); j++)
    		{
    
    			if (arr[j] > arr[j + 1])
    			{
    				//交换
    				int tmp = arr[j];
    				arr[j] = arr[j + 1];
    				arr[j + 1] = tmp;
    			}
    
    		}
    
    	}
    
    }
    
    //void bubble_sort(int *arr, int sz)//这里的arr的本质是指针
    //{
    //	//           4       /        4      = 1
    //	//int sz = sizeof(arr) / sizeof(arr[0]);//sz=1
    //	int i = 0;
    //
    //	for (i = 0; i < sz - 1; i++)
    //	{
    //		int j = 0;
    //		//一趟内部比较的对数
    //		for (j = 0; j < (sz - 1 - i); 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] = { 0 };
    	//输入
    	int i = 0;
    	int sz = sizeof(arr) / sizeof(arr[0]);
    
    	for (i = 0; i < sz; i++)
    	{
    		scanf("%d", &arr[i]);
    	}
    
    	//排序 - 升序
    	//arr作为数组进行了传参
    	//数组传参,传递的是地址,传递的是首元素的地址
    	bubble_sort(arr, sz);//让这个函数来完成数组arr中数据的排序
    					 //arr是数组首元素的地址
    	
    	//输出
    	for (i = 0; i < sz; 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    此外,我们还可以对它进行一些优化:

    //冒泡排序的优化
    
    #include 
    
    void bubble_sort(int* arr, int sz)//这里的arr的本质是指针
    {
    	//           4       /        4      = 1
    	//int sz = sizeof(arr) / sizeof(arr[0]);//sz=1
    	int i = 0;
    
    	for (i = 0; i < sz - 1; i++)
    	{
    		//每一趟开始前就假设已经有序了
    		int flag = 1;
    
    		int j = 0;
    		//一趟内部比较的对数
    		for (j = 0; j < (sz - 1 - i); j++)
    		{
    
    			if (arr[j] > arr[j + 1])
    			{
    				//交换
    				int tmp = arr[j];
    				arr[j] = arr[j + 1];
    				arr[j + 1] = tmp;
    				flag = 0;
    			}
    
    		}
    
    		if (1 == flag)
    		{
    			break;
    		}
    
    	}
    
    }
    
    int main()
    {
    	int arr[10] = { 0 };
    	//输入
    	int i = 0;
    	int sz = sizeof(arr) / sizeof(arr[0]);
    
    	for (i = 0; i < sz; i++)
    	{
    		scanf("%d", &arr[i]);
    	}
    
    	//排序 - 升序
    	//arr作为数组进行了传参
    	//数组传参,传递的是地址,传递的是首元素的地址
    	bubble_sort(arr, sz);//让这个函数来完成数组arr中数据的排序
    					 //arr是数组首元素的地址
    
    	//输出
    	for (i = 0; i < sz; 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    看完以上代码,肯定会有疑惑:为什么sizeof(arr)中的arr表示整个数组,而传参时arr表示数组首元素的地址呢?

    //数组名该怎么理解?
    //数组名通常情况下就是数组首元素的地址
    //但是有2个例外:
    //1. sizeof(数组名),数组名单独放在sizeof()内部,这里的数组名表示整个数组,计算的是整个数组的大小
    //2. &数组名,这里的数组名也表示整个数组,这里取出的是整个数组的地址
    //除此之外,所有遇到的数组名都表示数组首元素的地址
    
    #include 
    
    int main()
    {
    	int arr[10] = { 1, 2, 3, 4, 5, 6 };
    	printf("%p\n", arr);
    	printf("%p\n", arr + 1);
    
    	printf("%p\n", &arr[0]);
    	printf("%p\n", &arr[0] + 1);
    	
    	printf("%p\n", &arr);//数组的地址
    	printf("%p\n", &arr + 1);//+1,跳过整个数组
    
    	//printf("%d\n", sizeof(arr));//40?
    
    	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

    数组名的理解

  • 相关阅读:
    wget 下载盯盘文件
    Pyspark:ml.Classification包的使用
    上周热点回顾(12.18-12.24)
    17. 机器学习 - 随机森林
    机器学习笔记 - Deep Q-Learning算法概览
    【Android 四大组件之Content Provider】一文吃透 BroadcastReceiver 广播接收器
    IDEA控制台取消悬浮&全局配置&SpringBoot配置https
    OFDM原理及MATLAB仿真
    React Native快速上手
    [附源码]SSM计算机毕业设计校园一卡通管理信息系统台JAVA
  • 原文地址:https://blog.csdn.net/weixin_73077334/article/details/130780358