入门C语言第三话:数组之理论篇——你知道为什么打印数组时arr[i]等价于i[arr]吗?(内有冒泡排序与例题)

前言

  • 标题的问题的解析,详见文末图解。

概念的引入

 当我们要处理的变量过多并且是相同类型的时候,为了避免一个变量一个变量的命名,这时就需要数组来帮我们省事,这是数组的一个基本用途,下面我们来了解一下,数组的内容吧!

大纲

在这里插入图片描述

数组

定义

 数组 (Array)是有序的元素序列。 若将有限个类型相同的变量的 集合 命名,那么这个名称为数组名。

一维数组

创建

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

注意:数组的命名与变量命名的规则一样。
1.只能由字母(包括大写和小写)、数字和下划线( _ )组成。
2.不能以数字开头。
3.长度不能超过63个字符。
4.变量名中区分大小写的。
5.变量名不能使用关键字。

初始化

规则:
1.数组名的后的[ ] 里面的内容可以不写,如果写必须大于0,但是后面数组的内容必须要有。
正确代码:

int arr[]={1};
         //数组的内容——1不能省,因为这说明了数组有一个元素。
int arr1[4]={1};//这里是在有四个整形大小的数组里面放了第一元素1。
//数组的其余元素初始化为0         

2.在C99标准之前, [ ] 中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化。
代码:

int n =0;
scanf("%d",&n);//注意输入的数必须大于0
int arr[n];//如果不输入内容,默认是1(这只是牛客网上测的,以具体编译器打印的值为准)

思考以下代码:
  请说出下列数组的类型,数组大小,数组个数,内容的元素个数,数组中存的具体数值(是存在数组中的值),如果为char类型会不会正常打印?

说明:char数组打印时,遇到\0停止。

#include<stdio.h>
int main()
{

	int arr0[] = { 1,2,3,4 };
	int arr1[4] = { 1,2,3,4 };
	int arr2[4] = {1};
	

	char arr3[4] = "abcd";
	char arr4[4] = "abc";

	char arr5[4] = { 'a','b','c','\0'};
	char arr6[4] = { 'a','b','c','0' };
	char arr7[4] = { 'a','b','c',0 };
	

	char arr8[] = "abc";
	char arr9[] = { 'a','b','c' };
	char arr10[4] = { 'a'};
	char arr11[4] ='a';//字符的类型跟char[4]不匹配
	char arr12[4] ="a";//字符串的类型char[4]是匹配的
	char arr13[2]={'a'};
	char arr14[2]="a";
	//这两个数组相同,但又不完全相同,arr13是将字符'a'放入第一个变量类型是char与之匹配
	//第二个数组,"a"是将字符串的首字母依次放入第一个变量。第二个变量直到将\0放入为止。
	char arr15[2]={"a"};//同理,说明""和{}是不完全相同的。
	return 0;
}

 经过上面的思考我相信你对数组有了一个较为深刻的印象。
下面我们来具体说一下注意的点

	int arr2[4] = {1};
//这里放了一个元素:1,数组中存的:1 0 0 0
	char arr10[4] = { 'a'};
//同理
	char arr3[4]="abcd";
//这里的是把abcd\0的前四个元素放进数组中,因为数组只能放四个
//字符,所以不会正常打印。
//这里注意两点:数组的大小,数组后面的内容的大小是否能与数组
//的大小相匹配

	char arr5[4] = { 'a','b','c','\0'};
	char arr6[4] = { 'a','b','c','0' };
	char arr7[4] = { 'a','b','c',0 };
//这里要注意数字0存入数字中要涉及ASCII码值的转换为‘\0’
//arr5与arr7能正常打印,而arr6不能,最后只是个字符0。

到这里想必已经对数组的初始化了如指掌了,下面我们继续学习。

内存的存储

  说到内存,我们就不得不从地址开始进行了解,因为在栈区内存的开辟是从高地址到低地址进行开辟的。
举例:

#include <stdio.h>
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] = %p\n", i, &arr[i]);
	 }
	 return 0;
}

我们找一组(栈区是动态管理的)比较好看的数字(地址是16进制存储的):
在这里插入图片描述
从上到下,每次加4,&arr[9]减&arr[0]等于40这就是数组arr开辟的空间。

冒泡排序

首先我们了解一下都有哪些排序算法。

在这里插入图片描述
今天我们就来了解其中较为简单的冒泡排序。

图解:
在这里插入图片描述
原理:从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个最小的一个。这个数就会从序列的最右边冒出来。因此可以用来升序排序也可以用来降序排序。

规律:第一趟比较的是数组的元素减一次,第二趟为数组的元素个数减2次……第n次为数组的元素减n次。

总共最少比较0+1+2+3+4+……+数组元素个数减1次用等差数列可求值。
代码:

	//冒泡排序
	//要排序的数组
	int arr[10] = { 6,4,1,2,9,3,7,8,10,5 };
	//计算元素个数,也是排列元素所需的躺数
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	int j = 0;
	for (i = 0; i < sz; i++)
	{
		//一趟
		for (j = 0; j < sz - i - 1; j++)
		//这里的减1是为了防止第一次访问数组越界,sz-i-1是所
		//需的最少躺数。
		{
			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]);
	}

结果:
在这里插入图片描述

二维数组

这里由于跟一维数组大同小异,我在这里把两者的区别说明一下。

创建

1.可以不定义行,但必须定义列。
代码举例:

int arr[][4];

初始化

int arr[4][4]={0};//相当于在4*4的数组中都放入了0。
int arr1[4][4]={{1,2},{1,2}};//是在数组的第一行和第二行的开
//头依次放入,1和2,其他元素默认为0;
int arr[3][3]={1,2,3,4,5,6,7,8,9};//把第一行元素放满之后再放第二行元素直到放满数组为止。

内存的存储

#include<stdio.h>
int main()
{	
 	int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 3; j++)
		{
			printf("&arr[%d][%d]%p\n",i,j, &arr[i][j]);
		}
	}
	return 0}

打印结果:
在这里插入图片描述
由这里我们看出每次都加了4,说明在二维数组中内存是连续存放的。
看下图了解二维数组如何访问每一个元素。
图解:
在这里插入图片描述

指针与数组

除去这两种情况外:
1.sizeof(arr)计算的是整个数组的大小。
2.&arr取出的是整个数组的地址,但是取出的地址跟arr相同,唯一的区别是在计算上,arr +1加的是一个元素的大小,&arr加1加的是整个元素的大小。
 数组名是首元素的地址。
 打印数组时arr[i]时计算机不能直接进行计算,所以要转化为*(arr+i),而 *(arr+i)等价于*(i+arr)进而等价于 i[arr],这里要明白的一个点是变量1[变量2 ]等价与*(变量1加变量2 ),这里的变量一,二其中一个为指针。
图解:
在这里插入图片描述
注意:函数传参时的arr为首元素的地址,函数可以用arr[ ]也可以用* arr来接收,至于类型看传入的类型而定,但在函数里可不能用sizeof来求数组的大小,因为这里的arr只是首元素,而不是整个数组。

int size(int *arr)
{
 return sizeof(arr);
}
int main()
{
 	int arr[3]={0};
 	int sz = sizeof(arr);//求的是12
 	int ret = size(arr);//求的是4
	return 0;
}

总结

如果能认真看到这里,我坚信你能收获很多很多!也希望这篇文章能帮助到你,如果觉得不错,请点击一下不要钱的赞,如果有误请温柔的指出,在这里感谢大家了!

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值