数组是C语言中高频使用的工具,数组能将一组同类型的元素集合在一起,在进行调用或排序时很方便,由于有了数组,我们可以用数组名引用一系列变量,然后再通过下标索引的方式访问具体元素。数组还有一个特点:数组名表示首元素地址,这就意味着数组跟指针有着密切的联系,或者数组是指针的一种特殊表现形式。
注意:图片中代码的头文件位于文件最顶部,因截图无法截取,所以默认已引头文件
正文
数组分为一维数组和多维数组,而在现阶段的学习中,只需要用到一维数组和二维数组,所以本文主要介绍这两种数组的特点和用法。
一维数组是最简单数组,这种数组只带有一个下标引用操作符[ ] 指向关系比较明确,能够轻而易举的找到欲查找元素。
数组的创建需要有两个必要条件,一是数组内元素类型(整型、浮点型、字符型等),二是必须有数组名(数组名不能与关键字冲突),关于数组大小,可以不设定,但不能不清楚。
注意:创建数组时最好将三个条件设置好,同时不要用变量充当数组长度。
同变量创建时顺便初始化一样,数组初始化能给数组赋上准确值,而不是不可知的随机值,同时在有的场景中数组初始化很重要。
注意:初始化时要注意是否已设定好数组大小,若设定好了大小,初始化时不能超过设定大小;若没有设定大小,初始化后数组内元素个数默认为数组大小。若是字符数组,且初始化时赋字符串,要特别注意字符串自带一个 \0 因此大小会加1。
数组在使用时需要依赖于下标引用操作符 [ ] ,也就是框住数组大小的那个符号,下标引用操作符就像是一道传送门,设置好目的地(下标),就能访问到相应的元素,从而进行使用。
//下标
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", arr[5]);//是否为数字5?
int i = 0;
for (i = 0; i < 10; i++)
{
//i是否可以等于10?
printf("%d ", arr[i]);
}
return 0;
}
注意:1.数组是通过下标来使用的,下标从0开始。2.若数组的大小未知,可通过sizeof(arr)/sizeof(arr[0])计算得到,即数组名大小/数组首元素大小==40/4=10。
我们都知道,内存地址是唯一且连续的,而我们的数组能通过下标访问元素,由此可以推断出数组在内存的储存也是连续的,具体元素地址也是唯一的。
注意:数组在内存中是连续存放的,且随着下标的增长,地址由低变高。
二维数组由一维数组拉伸而来,也就是说二维数组一般比一维数组要长,因为是一维数组的同类,所以二维数组在很多地方跟一维数组有着相似之处。
因为都差不多,所以我放在一起说
二维数组的创建需有两个下标访问操作符,都是表示大小
二维数组初始化跟一维数组一样,能省略,但只能省略一点点,即列不能省略
二维数组在使用时需要注意下标问题,因为是两个下标,所以在使用前可以先画图理解
我们已经知道了一维数组在内存中是连续存放的,那么二维数组是否也如此呢?
//存储
int main()
{
int arr[2][2] = { 1,2,3,4 };
int i = 0;
int j = 0;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 2; j++)
{
printf("行下标:%d 列下标:%d的元素地址为:%p\n", i, j, &arr[i][j]);
}
}
return 0;
}
数组的下标是有范围限制的,下标总是从0开始,到n-1结束(n表示数组大小),如果数组下标小于0或大于n-1,那么此时就属于数组越界。C语言本身不做越界检查,编译器也不一定会报错,但如果出现下标越界,就意味着程序有错误,需要我们程序员去排查错误或者在编写代码阶段做好下标的检查,避免出现越界。
//越界
int main()
{
int arr[10] = { 0 };
int i = 0;
for (i = 0; i <= 10; i++)
printf("%d ", arr[i]);
return 0;
}
跟变量和常量一样,数组能作为参数传递给函数,以便函数执行操作
冒泡排序可以将数组进行排序,因此需要把输入传入排序函数中。冒泡排序是拿元素逐个比较,确定所在的位置,完成排序。
//冒泡排序-1.0-err
//这是一个错误版本
void bubble_sort(int arr[])
{
int i = 0;
int sz = sizeof(arr) / sizeof(arr[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 };
bubble_sort(arr);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
//冒泡排序-2.0-right
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 - 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]);
bubble_sort(arr,sz);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
经过这么多程序的磨练,我们已经知道了数组名就是首元素地址的事实,但是有两个例外: 1.sizeof(数组名),此时数组名代表整个数组,sizeof(数组名)就是求出整个数组的大小 2.&数组名,此时取出的是数组的地址,数组名此时表示整个数组,在进行加减操作时会直接跳过整个数组。
数组的知识也比较简单,无非就是一维数组、二维数组的创建、初始化、使用、储存与数组传参,我们可以利用数组表示出矩阵,也就是说我们可以利用目前所学的知识写出三子棋、扫雷等小游戏,三子棋马上更新!
如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正!