【C语言】一维数组,二维数组的创建,初始化,存储,以及数组传参的常见问题,冒泡排序及其错误写法以及优化

1.创建数组时候中括号内部必须是常量表达式,比如int arr[10];不能写成int n=10; int arr[n];

但是注意仅仅是创建数组的时候不允许中括号内部使用变量,如果是访问数组的时候,括号内可以是变量。

2.数组的初始化

整形数组

【C语言】一维数组,二维数组的创建,初始化,存储,以及数组传参的常见问题,冒泡排序及其错误写法以及优化_第1张图片

可以用大括号完全初始化,也可以不完全初始化,不完全初始化的话剩余的元素会被编译器初始化为0。可以省略数组长度,这样数组长度默认就是我们初始化的个数。

字符数组

字符数组可以用来放字符串,因此可以用双引号初始化,用这种方式初始化会在字符串末尾放一个\0,当然也可以用大括号来初始化,把字符一个个的放进去。

注:字符在内存中存放的时候存的是他的ASCII码值。

3.数组在内存中的存储

【C语言】一维数组,二维数组的创建,初始化,存储,以及数组传参的常见问题,冒泡排序及其错误写法以及优化_第2张图片

通过打印地址我们可以发现一维数组的元素在内存中是连续存放的,如图所示,数组中每个元素是int类型,那么数组每个元素地址就相差4(int类型元素的字节大小)

二维数组

见二维数组,脑中要有棋盘的样子

见二维数组,可以想象他是一个由m个一维数组组成的一维数组。m是数组的行数

1.二维数组的创建

int arr[3][4];表示创建了一个三行四列的二维数组,每个元素的类型是int

2.二维数组的初始化

一个三行四列的二维数组,可以认为他是有三个一维数组构成的,每个一维数组有四个元素,根据这个原理,可以如图初始化。

这三个一维数组也是连续存放的。这种初始化方式就好像可以把二维数组也看成一个一维数组,数组中每个元素类型也是一维数组。或者说二维数组是【一维数组】的数组。

也可以直接这样初始化

这样写的话默认是第一行放满了就放第二行,第二行放满了就放到第三行。两种初始化方式是等效的。但是第一种初始化方式更突出了二维数组是3个连续存放的一维数组这个思想。

注:二维数组初始化的时候可以省略行,但是不能省略列。

3.打印二维数组

【C语言】一维数组,二维数组的创建,初始化,存储,以及数组传参的常见问题,冒泡排序及其错误写法以及优化_第3张图片

使用两层for循环即可打印二维数组。

常见错误:1.把j定义在外层的for循环之外 2.循环的边界值搞错

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

【C语言】一维数组,二维数组的创建,初始化,存储,以及数组传参的常见问题,冒泡排序及其错误写法以及优化_第4张图片

通过打印二维数组中每个元素的地址可以看出,一个四行五列的数组,他的每一行可以看成一个一维数组,也就是说他可以看成四个一维数组,这四个一维数组是连续存放的。如图是二维数组在内存中的存放形式

这种连续存放的形式也就解释了为什么在初始化二维数组的时候为什么行可以省略但是列不能省略。因为只要知道了构成二维数组的一维数组有几列,那么我们在初始化的时候放满了就可以往后面按顺序放。自动到了下一行。但是有几行无所谓,大不了放着放着没元素了就不放了,这时候有多少行就是多少行。

5.对二维数组的另一种理解

【C语言】一维数组,二维数组的创建,初始化,存储,以及数组传参的常见问题,冒泡排序及其错误写法以及优化_第5张图片

假如这是一个四行五列的二维数组,他在内存中的存储形式如图,要想访问第一行的元素,其实就是通过下标arr[0][1]......arr[0][4],前面都是arr[0],也就是说要访问第一行的元素,通过arr[][i]即可,对比一维数组访问的时候比如一个有五个元素的一维数组arr,要想访问他的每个元素只需要通过arr[i]即可,而这个一维数组的数组名是arr,因此我们可以把二维数组的第一行看做一个数组名为arr[0]的一维数组。以此类推,二维数组第二行的那个一维数组,他的数组名就是arr[1],第三行数组名就是arr[2]。

冒泡排序

【C语言】一维数组,二维数组的创建,初始化,存储,以及数组传参的常见问题,冒泡排序及其错误写法以及优化_第6张图片

来看一种经典的错误写法

【C语言】一维数组,二维数组的创建,初始化,存储,以及数组传参的常见问题,冒泡排序及其错误写法以及优化_第7张图片

这种写法在写bubble_sort函数的时候形参只有一个,传参的时候只把arr传过去了,这样拿到的其实只是arr的地址,函数只知道arr的首地址,并不知道数组的长度。我们在上面代码中加了一句打印,发现接收的数组长度居然是1,这是因为我们传递的是数组名,也就是首元素地址,既然是地址,在32位环境下大小就是4个字节,而int类型变量的大小恰好也是4个字节,利用除法算出来的数组长度就是这里的1,显然是错误的。

你可能有疑问,说以前我们计算数组长度的时候不也是sizeof(arr)吗?怎么那里是计算的整个数组大小?这是因为数组名在一般情况下是首元素的地址,但是有两种特殊情况,第一种就是sizeof(数组名),数组名单独放在sizeof内部,计算的是整个数组的大小,第二种就是&数组名,对数组名取地址,拿到的是整个数组的地址。数值上其实和数组首元素地址是一样的,但是代表的意义不一样。最直观的就是打印arr+1和&arr+1,前者会跳过一个元素,后者会跳过整个数组。

而上图中代码arr是作为参数传到了bubble_sort函数内部,那他的意义就是首元素地址,本质上就是个指针变量了。

这就提示我们在数组传参的时候,如果需要用到数组长度,一定要把数组长度作为参数传过去。

注:1.一个含n个元素的数组,用冒泡排序的算法只需要排n-1次

2.把冒泡排序写成函数的时候应该把数组名和数组长度都传过去,也即需要两个参数

3.第一次会把最大的数放到最后,需要n-1-0次,第二次是把倒数第二大的放到倒数第二,需要n-1-1次,以此类推,并不是说每次把第一个数放到他对应的位置。

对于冒泡排序来讲,如果我们发现有一趟排序中一次交换也没产生,说明这一趟就不用再继续交换了,直接开始下一趟就行,因此我们还可以优化这个代码

【C语言】一维数组,二维数组的创建,初始化,存储,以及数组传参的常见问题,冒泡排序及其错误写法以及优化_第8张图片

你可能感兴趣的:(c语言,java,算法,c++,数据结构)