文章目录
- 1:一维数组的创建和初始化
- 1.1 创建方式
- 1.2:一维数组的初始化
- 1.3:一维数组的使用
- 1.3.1:数组下标
- 1.4:一维数组在内存中的存储
- 2:二维数组的创建和初始化
- 2.1:二维数组的创建
- 2.2:二维数组的初始化
- 2.3:二维数组的下标
- 2.4:二维数组在内存中的存储
- 3:数组越界
- 4:数组名
- 5:冒泡排序
嘿嘿,家人们,今天咱们来详细介绍下C语言中的数组,好啦,废话不多讲,开干!
1:一维数组的创建和初始化
概念:数组是指一组**相同类型元素**的集合。
从这个概念中,我们可以知道以下两个信息:
(1):数组中存放的是1个或多个数据,但是数组的元素个数不能为0。
(2):数组中存放的多个数据,其数据类型是相同的。
数组分为一维数组和多维数组,多维数组一般比较常见的是二维数组。
1.1 创建方式
type_t arr_name [const_n]
//type_t 指数组的元素类型
//const_n 为一个常量表达式用于指定数组的大小
//[]中的常量值是用于指定数组的大小,这个数组的大小要根据实际的需求来进行指定。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr1[5];int arr2[3 + 2];int n = 0;scanf("%d\n",&n);//变长数组char arr3[n];return 0;
}
PS:在创建数组时,我们通常使用一个常量表达式用于指定数组的大小,而不是变量,原因在于,在c99之前数组只能是常量指定大小,在C99之后引入了变长数组的概念,数组的大小是可以使用变量来指定滴。博主使用的vs2022是不支持变长数组滴,希望uu们注意。
1.2:一维数组的初始化
有时候,数组在创建的时候,我们需要给定一些初始值,这种操作就被称作初始化。那么如何对数组进行初始化呢?数组的初始化一般使用大括号,将数据放在大括号中。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{//完全初始化int arr1[5] = { 1,2,3,4,5 };//不完全初始化,第一个元素初始化为1,剩余的元素默认初始化为0int arr2[8] = { 1 };//未指定大小,则根据数组中元素的值来确定数组的元素个数int arr3[] ={1,2,3,4,5};//错误的初始化----初始化项太多,超过了数组的元素个数int arr4[3] = {1,2,3,4};return 0;
}
1.3:一维数组的使用
学习了⼀维数组的基本语法,⼀维数组可以存放数据,存放数据的⽬的是对数据的操作,那我们如何使⽤⼀维数组呢?
1.3.1:数组下标
C语言规定数组中的每个元素是有对应的下标的,下标是从0开始的,假设数组有n个元素,最后一个元素的下标识n-1,下标就相当于数组元素的标号。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };return 0;
}
在C语言中数组的访问提供了一个操作符[],这个操作符叫:下标引用操作符有了下标访问操作符,我们就可以轻松地访问到数组的元素了,譬如我们想访问下标为7的元素,就可以使用arr[7],访问下标为3的元素,可以使用arr[3]。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%d\n", arr[7]);printf("%d\n", arr[3]);return 0;
}
1.4:一维数组在内存中的存储
有了前面的知识,我们其实使用数组基本上没有什么障碍了,如果想要深入了解数组,我们最好能了解一下数组在内存中的存储。 接下来我们将使用如下代码来打印数组在内存中的存储。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };for (int i = 0; i < 10; i++){//%p用于打印指针的值,将地址以16进制的形式输出printf("&arr[%d] = %p\n", i, &arr[i]);}return 0;
}
从输出的结果我们可以发现,数组随着下标的增长,地址是由小到大变化的,并且每两个相邻的元素之间相差4(因为一个整型占4个字节)。因此,我们可以得出这样一个结论:数组在内存中是连续存储的,并且随着下标的增长,地址是由低到高变化的,从低地址到高地址。
2:二维数组的创建和初始化
概念:前面博主所讲的数组被称作一维数组,数组的元素类型都是内置类型的,如果我们把一维数组作为数组的元素,这个时候为**二维数组**,二维数组作为数组元素的数组被称为**三维数组**,二维数组以上的数组统称为**多维数组**。
PS:二维数组可以与我们在大学中线性代数中的矩阵进行类比哦
2.1:二维数组的创建
type arr_name[常量值1][常量值2]
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{//3表示数组有3行,5表示每一行有5个元素,即3行5列int arr1[3][5];double arr2[2][8];return 0;
}
2.2:二维数组的初始化
二维数组的初始化,和一维数组一样,也是使用大括号初始化滴!
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{//不完全初始化int arr1[3][5] = { 1,2 };int arr2[3][5] = { 0 };//完全初始化int arr3[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };return 0;
}
ps:二维数组在初始化时,行可以省略,但是列不能够省略,当行省略时,则是根据数组中的元素的值来确定行。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr1[][5] = { 1,2,3 };int arr2[][5] = { 1,2,3,4,5,6 };int arr3[][5] = { {1,2},{3,4},{5,6} };return 0;
}
2.3:二维数组的下标
当我们掌握了二维数组的创建与初始化后,那我们怎么样去使用二维数组呢?其实二维数组的访问也是通过下标的形式去访问的,二维数组是有行和列的,只要锁定了行和列就能唯一锁定数组中的一个元素。
C语言规定,二维数组的行是从0开始的,列也是从0开始的。
通过这段代码实现了对二维数组的访问,只要我们能够按照一定的规定产生所有的行和列,就能够实现对二维数组的访问。
2.4:二维数组在内存中的存储
和一维数组一样,如果想研究二维数组在内存中的存储方式,我们也是可以打印出数组所有元素的地址滴。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };//锁定行for (int i = 0; i < 3; i++){//锁定列for (int j = 0; j < 5; j++){printf("&arr[%d][%d] = %p ",i,j,&arr[i][j]);printf("\n");}printf("\n");}return 0;
}
从输出的结果来看,每一行的内部的每个元素都是相邻的,地址之间相差4个字节,跨行位置的两个元素(如:arr[1][4]和arr[2][0])之间也是差4个字节,因此二维数组中的每个元素都是连续存放的。如下图所示
3:数组越界
数组的下标是有范围限制的。
数组的下标规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。
因此数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组的合法空间的访问。
ps:C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的。
因此在写代码时,最好自己做越界的检查。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5 };for (int i = 0; i <= 10; i++){printf("%d ", arr[i]);}return 0;
}
4:数组名
什么是数组名呢?博主将通过下面这段代码来讲解数组名
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5 };printf(" arr = %p\n", arr);printf("&arr[0] = %p\n", &arr[0]);printf(" *arr = %d\n", *arr);return 0;
}
通过这段代码的运行结果我们可以得出,数组名表示数组首元素的地址。OK,如果数组名为首元素的地址,那么再看下面这段代码。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5 };printf("%d\n", sizeof(arr));return 0;
}
不是说数组名为首元素的地址吗,那这里为什么输出的是40呢?
> 补充:(1):sizeof(数组名),计算的是整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
(2):&数组名,取出的是整个数组的地址。&数组名,数组名表示整个数组。
除了这两种特殊情况,在其他情况,所有的数组名均表示数组首元素的地址。
5:冒泡排序
有了我们数组以及函数等等的相关知识,接下来博主将为uu们介绍一种排序算法----->冒泡排序。这里博主以排成升序为例。
核心思想:两两相邻元素进行比较。
我们通过上面的动图可以发现,每进行一趟冒泡排序,就可以让元素到达自己应该处的位置。假设我们要对10个数进行排序,那么应该要进行几趟冒泡排序呢?答案应该是9趟,因为单独的一个数我们可以认为它是有序滴,这里家人们要注意哈。首先我们来看单趟的冒泡排序。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };//求出数组中的元素个数int sz = sizeof(arr) / sizeof(arr[0]);for (int j = 0; j < sz - 1; j++){if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;} }return 0;
}
如果左边的元素大于右边的元素,那么这两个数就进行交换,直到该元素到达自己应该所处的位置,这是一趟冒泡排序,但是这里有10个数呀,要进行9趟冒泡排序,并且每次进行一趟冒泡排序后,趟数要减少,因此就要使用双层的嵌套循环来进行实现!
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };//求出数组中的元素个数int sz = sizeof(arr) / sizeof(arr[0]);printf("排序前:>");for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}//确定总趟数for (int i = 0; i < sz - 1; i++){//每进行一次冒泡排序,趟数要减少,因此- ifor (int 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;}}}printf("\n");printf("排序后:>");for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}
好啦,家人们,关数组这块的相关细节知识,博主就讲到这里了,如果uu们觉得博主讲的不错的话,请动动你们滴滴给博主点个赞,你们滴鼓励将成为博主源源不断滴动力!