征服C语言之数组

征服C语言之数组,第1张

征服C语言之数组

目录

一.数组的创建和初始化

数组的创建

数组初始化

一维数组的使用 

一维数组在内存中的存储

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

二维数组的创建

二维数组的初始化

二维数组的使用

二维数组在内存中的存储

 三.数组越界

四.数组作为函数参数

数组名是什么 

数组实例


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

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

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

 数组创建的实例:

//代码1
        int arr1[10];
//代码2
        int count = 10;
        int arr2[count];//数组时候可以正常创建?
//代码3
        char arr3[10];
        float arr4[1];
        double arr5[20];

注: 数组创建,在 C99 标准之前, [] 中要给一个 常量 才可以,不能使用变量。在 C99 标准支持了变长数组的概念。即代码2 数组初始化 数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。
#define _CRT_SECURE_NO_WARNINGS
#include
#include
int main()
{
	int arr[8];
	char ch[5];

	int arr1[10] = {1,2,3,4,5,6,7,8,9,10};//完全初始化

	int arr2[10] = { 1,2,3,4,5 };//不完全初始化
	int arr3[] = { 1,2,3,4,5 };

	char ch1[5] = {'b', 'i', 't'};//
	char ch2[] = { 'b', 'i', 't' };//b i t 

	char ch3[5] = "bit";//b i t  0
	char ch4[] = "bit";//b i t 

	printf("%dn", strlen(ch1));//3
	printf("%dn", strlen(ch2));//随机值
	printf("%dn", strlen(ch3));//3
	printf("%dn", strlen(ch4));//3

	printf("%sn", ch3);//bit
	printf("%sn", ch4);//bit

	return 0;
}
  • 数组的元素个数可以根据使用者明确指明,即arr,ch,arr1,arr2,ch1,ch3数组,
  • 数组的元素个数可以根据初始化的内容来确定,即arr3,ch2,ch4数组,
  • 数组可以不初始化,如果不初始化则默认补0,比如arr,ch数组,
  • 数组可以完全初始化,也可以不完全初始化,完全初始化:arr1数组,不完全初始化:arr2,ch1,ch3数组,
  • strlen这个库函数读取到结束,计算的是之间的字符长度,这里不细讲了,
一维数组的使用  对于数组的使用我们之前介绍了一个 *** 作符: [] ,下标引用 *** 作符。它其实就数组访问的 *** 作符。 我们来看代码:
#include int main () {         int arr [ 10 ] = { 0 }; // 数组的不完全初始化           //计算数组的元素个数           int sz = sizeof ( arr ) / sizeof ( arr [ 0 ]);         //对数组内容赋值 , 数组是使用下标来访问的,下标从 0 开始。所以:         int i = 0 ; // 做下标         for ( i = 0 ; i < 10 ; i ++ ) // 这里写 10 ,好不好?         {                 arr [ i ] = i ;         }         //输出数组的内容         for ( i = 0 ; i < 10 ; ++ i )         {                 printf ( "%d " , arr [ i ]);         }         return 0 ; }
总结 : 1. 数组是使用下标来访问的,下标是从 0 开始。 2. 数组的大小可以通过计算得到。
int arr [ 10 ]; int sz = sizeof ( arr ) / sizeof ( arr [ 0 ]);
一维数组在内存中的存储 接下来我们探讨数组在内存中的存储。 看代码:
#define _CRT_SECURE_NO_WARNINGS
#include 
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

	for (i = 0; i < sz; ++i)
	{
		printf("&arr[%d] = %pn", i, &arr[i]);
	}
	return 0;
}

  •  %p - 是按地址的格式打印 - 十六进制的打印
  • 仔细观察输出的结果,我们知道,随着数组下标的增长,元素的地址,也在有规律的递增。 由此可以得出结论: 数组在内存中是连续存放的 。

二.二维数组的创建和初始化 二维数组的创建
// 数组创建 int arr [ 3 ][ 4 ]; char arr [ 3 ][ 5 ]; double arr [ 2 ][ 4 ];
二维数组的初始化
// 数组初始化 int arr [ 3 ][ 4 ] = { 1 , 2 , 3 , 4 }; int arr [ 3 ][ 4 ] = {{ 1 , 2 },{ 4 , 5 }}; int arr [][ 4 ] = {{ 2 , 3 },{ 4 , 5 }}; // 二维数组如果有初始化,行可以省略,列不能省略
二维数组的使用 二维数组的使用和一维数组使用一样,都是通过下标的方式进行访问 看代码:
#define _CRT_SECURE_NO_WARNINGS
#include 
int main()
{
	//创建
	int arr[3][4];
	char ch[3][10];

	//初始化 - 创建的同时给赋值
	int arr1[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	int arr2[3][4] = { 1,2,3,4,5,6,7 };//不完全初始化 - 后面补0
	int arr3[3][4] = { {1,2}, {3,4} ,{4,5} };

	int arr4[][4] = { {1,2}, {3,4} ,{4,5} };
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 4; j++)			//1  2  0  0
		{								//3  4  0  0
			printf("%d ", arr4[i][j]);  //4  5  0  0
		}
		printf("n");
	}
}
二维数组在内存中的存储 像一维数组一样,这里我们尝试打印二维数组的每个元素。
#define _CRT_SECURE_NO_WARNINGS
#include 
int main()
{
	//二维数组在数组中存储
	int arr[][4] = { {1,2}, {3,4} ,{4,5} };
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 4; j++)
		{
			printf("&arr[%d][%d] = %pn", i, j, &arr[i][j]);
		}
	}
}

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

在进一步研究:

  •  我们又发现,arr[0]可以看成一维数组的数组名,同理arr[1]和arr[2]也一样,

总结:二维数组在内存中是连续存放的,一行内部连续,跨行也是连续的,

 三.数组越界 数组的下标是有范围限制的。 数组的下标规定是从 0 开始的,如果数组有 n 个元素,最后一个元素的下标就是 n-1 。 所以数组的下标如果小于 0 ,或者大于 n-1 ,就是数组越界访问了,超出了数组合法空间的访问。 C 语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的, 所以程序员写代码时,最好自己做越界的检查,
#define _CRT_SECURE_NO_WARNINGS
#include 
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]);//当i等于10的时候,越界访问了
	}
	return 0;
}

  • 虽然不报错,但是编译器会报警告, 进而更加确定数组是不能越界访问的,所以程序员写代码时,最好自己做越界的检查,
  • 注:二维数组的行和列也可能存在越界。
四.数组作为函数参数 往往我们在写代码的时候,会将数组作为参数传个函数,比如:冒泡排序中求数组元素个数的语句,冒泡排序的思想如下:
  • 其中如果要排10个数字则需要最多需要9趟冒泡排序,则n个数字最多需要n-1趟冒泡排序,因为原来的最后一个数字,已经到最前面的,所以少一次,
  • 在一趟冒泡排序中如果有n个数字待排序,则需要n-1次比较, 

代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include 
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[] = { 3,1,7,5,8,9,0,2,4,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);//是否可以正常排序?
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

  • 其中不能把sz(求数组元素)定义在bubble_sort里面,数组传参传递的是数组首元素的地址,其实这也和sizeof这个库函数有关系,这里不详细的讲了
数组名是什么 

看代码:

#define _CRT_SECURE_NO_WARNINGS
#include 
int main()
{
	int arr[10] = { 0 };

	printf("%p ", &arr[0]);//1
	printf("%p ", arr);//2-数组名是首元素的地址

	printf("%p ", &arr);//3 - &arr取出的是数组的地址
	printf("%p ", &arr + 1);//4
	printf("%p ", arr);//5
	printf("%p ", arr + 1);//6
	
	int sz = sizeof(arr);//7 - 数组名表示整个数组
	printf("%dn", sz);

	return 0;
}

 

  • 从第一个printf和第二个printf中可以看出数组名就是数组首元素的地址,
  • 从第三个printf和第五个printf中可以看出取数组的地址和数组名的地址好像一样,但是从第3,第4,第5,第6个printf中发现取数组的地址+1和数组名的地址+1不一样,一个跳过40个地址,另一个跳过4个地址,所以得出结论取数组的地址和数组名的地址不一样
  • 对于第三个printf来说,取的是数组地址,但是只是打印的数组首元素的地址,加1会跳过一个数组,
  • 我在上面说了,数组名是首元素的地址,但是第7个printf它打印的不应该是数组首元素的地址吗?不应该是4吗?这不就和我说的矛盾了吗?其实只是一个特例,sizeof(数组名)计算的数组总的大小,所以结果是40,

总结:

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

 除此1,2两种情况之外,所有的数组名都表示数组首元素的地址。

数组实例 数组的应用实例 1 :三子棋 三子棋main.c 三子棋test.c 三子棋test.h​​​​​​​ 数组的应用实例2:扫雷 扫雷

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5699704.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存