一维数组
数组的创建
数组是一种相同类型元素的集合
数组的创建方式
C99 中引入了变长数组的概念,变长数组支持数组的大小使用变量来指定
明显这里的vs2019不支持变长数组
数组初始化和不完全初始化
第二个数组就是典型的不完全初始化,开辟了10个空间,只有第一个是1,剩下的就用0填充
这里的ch1和ch2看起来似乎一样,但ch1只有 a b c, 后面的0是编译器主动加上的;ch2是abc\0,\0的ASCII码值也是0,所以后面也是6个0,但ch2本身就自带了一个
这样的代码也是有问题的,这里只用了一个空字符串初始化,所以数组的长度是一个元素
一维数组的使用
一个数组初始化好后每个元素都有其下标,下标是从0开始的
一维数组在内存中的存储
这里我们打印一下数组的每个元素的地址看看,%p是打印地址
我们发现每个相邻的地址最后的数字就相差4,因为这是整形数组,而一个整型是4个字节
数组在内存重视连续存放的!
随着数组下标的增长,地址也是由低到高变化的
数组开辟的空间也不宜太大
数组中的数据放在栈区
0和\0
二维数组
二维数组的创建
初始化
第一个参数是行数,第二个是列数
这个数组是怎么存放的呢?
其实是1234先把第一行放满,5放在第二行,其余的位置都是0
还有另一种初始化方式
就是指定初始化位置
以及,对于二维数组,初始化时,可以省略行,不能省略列
二维数组的使用
我们尝试一下一列一列打印
二维数组在内存中的存储
试着打印一下地址看看
能发现他们似乎也是连续存放的
也能将它们理解为一个12元素的整型数组
数组越界
当我们访问的空间超过数组申请的空间时,就造成了越界访问
还有这样
可能有人比较疑惑,为啥5会打印两次呢?
第一次打印了5个,第二次还是从行的下标0位置处开始,5这个位置是数组第二行的第一个元素,所以还会被打印一次。
数组应用
冒泡排序
冒泡排序(Bubble Sort)是一种简单直观的排序算法
冒泡排序的核心思想是:
通过相邻元素两两比较,把较大的元素“冒泡”到序列的一端,像水中的气泡一样逐步上升。
具体过程如下:
-
从头到尾依次比较相邻两个元素,如果前一个比后一个大,就交换它们;
-
每完成一轮,最大的元素就被“冒泡”到了当前未排序部分的末尾;
-
然后对剩下的部分重复这一过程,直到整个序列有序。
比如排序 [5, 2, 4, 3, 1]
,第一轮结束后变成 [2, 4, 3, 1, 5]
,最大值 5 被放到了最后。之后对 [2, 4, 3, 1]
再次进行“冒泡”,直到全部排好序。
设有一个长度为 n
的数组,共需进行最多 n-1
轮“冒泡”:
-
第 1 轮:比较
n-1
次,把最大值移到末尾; -
第 2 轮:比较
n-2
次,把次大值移到倒数第二位; -
…
-
第
n-1
轮:只需比较 1 次。
基本理念就是数组中的元素两两相比较,随后判断是否交换位置,最终的目的是排成一个升序或降序数组
或者函数的形式
#include<stdio.h>
void bubble_sort(int arr[10])
{
//求数组的元素个数
int sz = sizeof(arr) / sizeof(arr[10]);
//冒泡排序的趟数
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] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
//0 1 2 3 4 5 6 7 8 9
//要对数组升序排序
//冒泡排序
bubble_sort(arr);
//打印
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
但结果好像不对诶~
原来上面数组名传参的时候传递的只是数组首元素的地址,形参就是指针变量来接收,并没有把整个数组传上去。(这叫做数组名的降级)
上面sz就是1了,所以数组才会没变化
这时我们只需要在main函数里先把sz计算好,然后传给排序函数就行
#include<stdio.h>
void bubble_sort(int arr[10],int sz)
{
//冒泡排序的趟数
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] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
//0 1 2 3 4 5 6 7 8 9
//要对数组升序排序
//冒泡排序
bubble_sort(arr,sizeof(arr)/sizeof(arr[0]));
//打印
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
看一下这段代码
运行结果是两边都相等!
这里刚好也得出了
当p指向数组的第一个元素时,p+i就指向数组第i个元素
p里存放着数组首元素的地址,所以p和arr可以相互替换,下面这些效果也相等
还有加法交换律能得出的结论
前面讲了数组名是数组首元素地址,但存在两个例外
sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小,单位是字节
&数组名,数组名表示整个数组,取出的是整个数组的地址
看看这个,前面两个+1后跳过了一个整型元素,地址都是+4,而第三个+1后跳过了整个数组,地址变化了40个字节