C语言:一文理解数组——一种特殊的数据结构
C语言:一文理解数组——一种特殊的数据结构
数组是C语言中非常重要的基础结构,为程序提供了高效的数据存储和访问手段。它的连续存储特点带来了快速的访问能力,同时固定大小的限制也促使开发者在设计程序时更精细地考虑内存分配,数组可以实现丰富多样的功能,是C语言编程的核心工具之一。
一、数组的概念
1.1概念:
数组是一组连续的相同类型元素的集合(数组的本质:数组是系统在内存中申请的一块连续的存储空间)
注意:
- 数组中存放的是1个或者多个数据,但是数组元素个数不能为0。
- 数组是一组有序数据的集合,数组用下标来代表着数据在数组中的序号。(本质就是在内存中的地址)
- 数组中存放的多个数据,数据的类型是相同的。 数组分为一维数组和多维数组,多维数组一般比较常见的是二维数组。
1.2数组图示
二、数组的创建和初始化
2.1数组的创建
要使用数组就得先在程序中创建数组,创建一维数组的基本语法如下:
type arr_name[常量值];
例如以下代码:
int a[10];
存放在数组的值被称为数组的元素,数组在创建的时候可以指定数组的大小和数组的元素类型。以上代码就定义了一个整形数组,数组名为a,该数组包含了10个整形元素。
详细解释如下:
- type 指定的是数组中存放数据的类型,可以是: char、short、int、float 等,也可以自定义的类型
- arr_name 指的是数组名的名字,这个名字根据实际情况,起的有意义就行。
- 中的常量值是用来指定数组的大小的,这个数组的大小是根据实际的需求指定就行。 例如:我们现在想存储某个班级的20人的数学成绩,那我们就可以创建一个数组,如下:
int math[20];
2.1.1数组的类型
我们也可以根据需要创建其他类型和大小的数组:
char ch[8];
double score[10];
2.2数组的初始化
有时候,数组在创建的时候,我们需要给定一些初始值值,这种就称为初始化的。 那数组如何初始化呢?数组的初始化一般使用大括号,将数据放在大括号中。
以下是不同情况的初始化:
// 完全初始化
int arr[5] = {1,2,3,4,5};
// 不完全初始化
int arr2[6] = {1};//第一个元素初始化为1,剩余的元素默认初始化为0
int arr3[10];//这种初始化后数组每个成员为随机值
// 错误的初始化 - 初始化项太多
int arr4[3] = {1, 2, 3, 4};
三、访问数组元素
3.1 [ ]运算符
上述中我们创建了一个个数组,那么我们又该如何对其进行访问和修改呢?
这里需要用到数组下指针访问成员运算符—— [ ] :
array_name [ num];
array_name: 数组的名称
[num]: 对数组进行解引用操作,num是用来指定对数组的第几个元素进行操作的。
图示:
比如用arr[2]就是对数组array进行访问
3.2 [ ]运算符的应用
3.2.1对数组成员进行赋值
示例:
arr[2] = 6
该行代码就是对数组的第三个元素进行访问并将其赋值为6。
3.2.2作为其他函数的参数
例如我们想把数组的一个元素打印出来,可以这样来实现:
printf("%d",arr[2]);
3.3 数组的遍历
如果想访问一个数组的所有元素,直接一个一个arr[0],arr[1],arr[2]……进行访问太过麻烦,这里我们可以借助之前学到的for循环语句来实现:
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int i, j;
printf("请输入10个数组元素:\n");
for (i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
printf("输出结果:\n");
for (j = 0; j < 10; j++)
{
printf("arr[%d]=%d\n", j, arr[j]);
}
return 0;
}
运行结果:
3.4越界访问
3.4.1 越界访问的定义
数组的下标范围是从 0 到数组长度减 1。例如,对于一个长度为 n 的数组,有效的下标范围是 0 到 n-1。
若访问的数组下标小于0或大于数组长度-1,就会造成访问越界。
3.4.2越界访问的危险性:
- 安全风险:越界访问可能会导致数据损坏或内存破坏,从而引发安全漏洞。
- 越界访问会导致未定义行为(Undefined Behavior),这意味着程序的行为是不可预测的。程序可能会崩溃,也可能继续执行但产生错误的结果。(比如会得到一些随机数)
四、数组在内存中的存储
4.1 数组的存储
前面我们说到数组是系统在内存中申请的一块连续储存空间,那么为什么是连续的呢?这里我们演示一段代码开看看。
示例:
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i < 10; i++)
{
printf("&arr[%d] = %p\n ", i, &arr[i]);
}
return 0;
}
运行结果:
这里打印出来的地址是16进制的,把输出格式改换成整形就是以下结果:
4.2 结论
从输出的结果我们分析,数组随着下标的增⻓,地址是由⼩到⼤变化的,并且我们发现每两个相邻的 元素之间相差4(因为⼀个整型是4个字节)。所以我们得出结论:数组在内存中是连续存放的。这就 为后期我们使⽤指针访问数组奠定了基础。
五、sizeof计算数组长度
如果我们想知道一个数组的元素个数可以用sizeof关键字。
sizeof 中C语⾔是⼀个关键字,是可以计算类型或者变量⼤⼩的,我们也可以用sizeof来计算数组的⼤⼩。
示例:
#include <stido.h>
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));
return 0;
}
运行结果:40
这里输出的结果是40,计算的是数组所占内存空间的总⼤⼩,单位是字节。 我们⼜知道数组中所有元素的类型都是相同的,那只要计算出⼀个元素所占字节的个数,数组的元素 个数就能算出来。这⾥我们选择第⼀个元素算⼤⼩,然后就能借此来计算出整个数组的元素个数了。
示例:
#include <stido.h>
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", sz);
return 0;
}
运行结果:
以后在代码中需要数组元素个数的地⽅就不⽤固定写死了,使⽤上⾯的计算,不管数组怎么变化,计 算出的⼤⼩也就随着变化了。
示例:
#include<stdio.h>
int main()
{
int arr[] = { 2,4,5,8,13,26 };
int j;
int sz = sizeof(arr) / sizeof(arr[0]);
printf("输出结果:\n");
for (j = 0; j < sz; j++)
{
printf("arr[%d]=%d\n", j, arr[j]);
}
return 0;
}
运行结果: