各位小伙伴大家好,欢迎来到我的博文参观。今天学了数组,我就又来分享我今天所学的知识了,希望大家喜欢。下面时本文章的讲解思路。
一、一维数组
1.1一维数组的创建和初始化
数组是相同数据类型的有序数据的集合。其中的数据可以是int型、float型、char型、指针、结构体和共用体等类型。
数组的定义方式:
类型名 数组名[常量表达式]
如以下代码:
注意:在vs编译器下不支持变长数组,变长数组的意思是方括号里面是一个变量。它的大小可以随变量的改变而改变,变长数组是c99标准所支持的概念,而在c99标准之前是没有这个概念的。
数组的初始化
完全初始化和不完全初始化
另外还需要注意,char类型数组的初始化,比如:把char arr[3] = {'a','b','c'},中的元素按字符串的形式打印出来,会发生什么。
我们可以看到,后面出现了乱码,那么为什么会出现这种情况呢,是因为,字符串打印碰到'\0'才会停止,而我们这里没有'\0',所以会一直越界访问,而编译器不知道后面存储的是什么,所以会出现乱码问题。
char类型的数组还可以这样来定义和初始化。
1.2一维数组的使用
我们在初识C语言中,介绍了[ ],下标引用操作符,该操作就是访问数组元素使用的。我们可以使用for循环来访问数组元素。代码如下:
注意:一维数组的下标识从0开始的,数组的大小可以通过计算得到:
十个整型类型的数据,每个整型占用内存大小为4个字节。所以,数组的大小为:4 * 10 = 40。
我们还可以通过以下方式去访问数组
这里的原来是,先把arr的地址赋给指针变量p,p就指向了一维数组的首元素地址,通过i自增1找到数组中第i个元素的地址,进行解引用打印。每次加1,会跳过4个字节的内存,这是由于此数组是整型。
1.3 一维数组在内存中的存储。
要研究这个问题,我们可以这样做,打印数组元素的地址。
这里会涉及到进制转换的问题,可以去看看这篇文章:
由以上图片可知,内存地址在有规律的递增,所以我们可以得出结论:数组在内存中是连续存放的。
二、二维数组
2.1二维数组的创建和初始化
数组创建格式如下:
类型名 数组名 [整型表达式][整型表达式]
二维数组的初始化
数组初始化见下图
画图解释arr3数组为什么只能省略行:
2.2二维数组的使用
二维数组的使用也是通过下标的方式。
由这张图我们可知,二维数组其实是一个有两个元素(只是举例)的一维数组,只不过它里面元素的类型是数组罢了。
这样我们就可以通过两层for循环来进行访问二维数组,第一层找到第一个一维数组的位置,第二层找到一维数组里的每一个元素
代码如下:
int main
{
int arr1[2][3] = { 1,2,3,4,5,6 };
int i = 0;
int j = 0;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 3; j++)
{
printf("%d ", arr1[i][j]);
}
printf("\n");
}
return 0;
}
运行结果:
2.3二维数组在内存中的存储
我们还是可以使用打印地址的方式来讨论
我们把二维数组的每一行看作一个一维数组,那么每一行的一维数组也有数组名,如图所示:
三、数组的越界
数组的下标是由限制的,比如int arr[3]这个数组的下标范围是0~2,如果下标>2或者<0都会造成数组的越界。
C语言是不会检查数组下标越界的,这就需要程序员自己检查。
代码如下:
四、数组作为函数参数
这里我们先学习一个算法:冒泡排序算法。升序
4.1冒泡排序的错误设计
错误的代码如下:
void bubble_sort(int arr[])
{
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
int j = 0;
//控制趟数
for (i = 0; i < sz - 1; i++)
{
//控制每趟的比较次数
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 };
bubble_sort(arr);
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
运行结果:
我们发现数组竟然原样输出了,那么这是怎么回事呢,我们通过调试来分析。
要理解这里的内容,我们需要了解下一节内容。
4.2数组名是什么?
请看如下代码:
所以我们可以得出数组名=数组首元素地址。
但是有两种情况除外
sizeof(数组名),计算的是整个数组的大小,现在的arr表示的是整个数组。
&数组名,取出的是数组的地址。&数组名,数组名表示整个数组。
如下图所示:
我们再来看:
&arr取出整个数组的地址。
4.3冒泡排序函数的正确设计
当数组传参的时候,是把数组首元素地址传过去了,形参int arr[ ]表示的依然是一个指针:int* arr。
所以函数里面的sizeof就等于1或者2。需要改进冒泡排序,我们可以把sz放到主函数里求值,
然后作为函数参数传进去就可以了。
void bubble_sort(int arr[],int sz)
{
int i = 0;
int j = 0;
//控制趟数
for (i = 0; i < sz - 1; i++)
{
//控制每趟的比较次数
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);
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
运行结果:
可以看到排序完成。
第五部分内容会单独写一篇文章介绍,大家敬请期待!!!
各位小伙伴,今天就介绍到这里,我们下期见。请大家点点赞,谢谢大家了。