目录
- :exclamation:前言:认识数组
- :one:一维数组的创建和初始化
-
- 1.1、数组的创建
-
- :pushpin:附:数组的大小除了写常量值还可以是什么?
-
- 常量表达式
-
- 1、宏定义常量:
- 2、字面常量:
- 3、三元运算符:
- 4、枚举(enum)常量:
- C99的变长数组
- 1.2、数组的初始化
-
- :exclamation:字符、字符串数组的
- 1.3、数组的类型
- :two:一维数组的使用
-
- 2.1、数组的下标
- 2.2、数组元素的打印
- 2.3、数组的输入
- 2.4、数组的内存中的存储 (连续存放)
- :three:`sizeof`计算数组元素个数
📝学前预警:
- 在前面的学习中,我们已经学了C语言的三大结构(顺序、选择、循环)和部分知识,如有忘记可以点击下面链接进行回顾学习 🔗C语言学习专栏
- 下面我们将学习C语言的一个重点,数组
- 数组和我们高中所学的集合类似,可以认为数组是一种数据类型的集合
- 下面我们将会学习到一维数组,数组的创建和初始化和类型
- 数组的大小的多种写法和变长数组
- 数组赋初值,字符数组和字符串数组不同(\\0的存在)
- 不同数据类型的数组
- 一维数组的使用:通过下标使用,数组是连续存放的
- 通过sizeof计算数组的大小,数组某个元素的大小,数组元素的个数,sizeof计算的大小是以字节为单位的
❗️前言:认识数组
我们前面学习了数据类型,有整型、浮点型、字符型等等…
- 如果我们要存100个整型类型的数据我们应该如何存储呢?
- 如果是前面的学习中我们要存这100个数据就需要创建100个整型变量,来存储100个数据
- 如果真这样存储的话,我们就会在创建变量上浪费时间,这是不好的,那么我们有什么方法可以解决这个问题呢?
- 在数学的学习中我们学过集合,那么在C语言中存储这100个数据是不是也可以用一个集合来存储它们呢?——数组
- 数组是一组相同类型元素的集合
- 数组中存放的元素可以是1个或者多个,但不能是0个;
- 数组存放的是多个类型相同的数据
数组分为一维数组和多维数组,多维数组中常见的是二维数组
1️⃣一维数组的创建和初始化
1.1、数组的创建
一维数组的基本语法:
type arr_name[常量值];
//type:数组的元素类型(int、double、float…)
//arr_name:数组名(自定义)
//常量值:存储元素的个数,根据实际需求指定即可(1、2、3、4…)
例如:int arr[100];
- 存放数组的值是数组的元素
- 数组创建是可以指定,数组的大小(存储元素的个数);数组的数据类型
📌附:数组的大小除了写常量值还可以是什么?
一般情况下我们是在创建数组时,指定了数组的大小,这个大小一般是常量,除了常量还可以常量表达式和C99的变长数组
常量表达式
我们可以打开监视窗口来进行查看这些是否符合我们下面的说法监视窗口学习🔗
- 下面有放我打开监视查看的信息
1、宏定义常量:
宏定义常量:
#define N 5 // 宏定义常量,在函数外面就已经定义好
int arr0[N]; // N是宏常量(常量表达式) =>arr1[5]这个变量的值了,不可以修改的,相当于是常量

2、字面常量:
字面常量:
int arr1[4];//4是常量 =>arr0[4]
常量组成的表达式:
int arr2[3+2]; // 3+2是常量表达式 =>arr2[5]
int arr3[N*2+1];//arr3[11]

3、三元运算符:
三元运算符(前提:条件和结果都是常量表达式)
int arr4[(10>5) ? 4 : 6]; // 三元运算符+常量 =>arr[4]
#define X 5
#define Y 10
int arr5[(X > 3) ? X : Y];//arr5[5]

如果三元运算符中有变量参与,就不再是常量表达式:
int n = 5;
int arr6[(n > 3) ? 10 : 20]; //error

4、枚举(enum)常量:
enum 枚举常量:
enum { SIZE = 20 };
int arr7[SIZE];
有不记得枚举知识的可以打开下面的链接进行学习 枚举enum🔗

C99的变长数组
C99给的 变长数组(LVA) 的新特性,可以让我们使用变量来进行指定数组的大小
- 在dev C++中是可以使用的(其是gcc编译器),或者是VS2022的clang编译器(VS2022默认使用msvc编译器,这个不知何词C99的变长数组,使用会报错)
- VS2022的clang需要在VS2022 installer中进行修改,在安装详细信息中勾选“适用Windows的C++ clang工具”来安装
- 使用我们在项目目录中右击鼠标点击属性,常规里的平台工具集(里面的默认msvc进行修改),修改后应用就可以了
- 但是变长数组的大小指定好后是不可以再调整的。
int n=10;
int arr[n];//相当于arr[10]
- arr是变长数组,其的长度取决于变量n的值,编译器无法事先知道,只有在运行时才可以知道n的值是多少
- 所以我们可以知道:变长数组的数组长度是只能才运行时确定的,因此变长数组不能初始化
- 变长数组:是数组的大小可以使用变量进行指定,在程序运行时根据变量大小来指定数组元素的个数, 而不是数组的大小是可变的
#include<stdio.h>
int main(){
int n=0;
scanf("%d",&n);
int arr[n];
for(int i=0;i<n;i++){
scanf("%d",&arr[i]);
}
for(i=0;i<n;i++){
printf("%d ",arr[i]);
}
return 0;
}
****************************
输入:5
1 2 3 4
输出:1 2 3 4
1.2、数组的初始化
在数组创建的时候,我们可需要定一些初值,这种称为初始化
- 数组初始化一般使用大括号{ },将数据放在大括号中
完全初始化
int arr[5]={1,2,3,4,5};
不完全初始化
int arr[5]={1};//第一个元素初始化为1,剩余其他4个元素默认初始化为0
int arr[5]={0};//将5个元素默认初始化为0
根据初始化的个数决定数组的大小
int arr[]={1,2,3,4,5};//数组的大小为5,即arr[5]
//int arr[]={0}; 这个说明数组的大小为1,即:arr[1]={0}
❗️字符、字符串数组的
字符串数组的最后是有一个\\0存在,所以要预留多一个位置
- 如字符串hello中相当于h e l l o \\0,所以我们看着数组的大小为5,但实际是6
- 在我们指定字符串数组大小时是要多预留一个大小
字符数组:
char arr[]={'h','e','l','l','o'};//数组大小为5
字符串数组:
char arr[]="hello";//数组大小为6,因为有一个'\\0'在最后
1.3、数组的类型
int arr1[10];//arr1数组的类型是int型(int [10])
char arr2[10];//arr2数组的类型是char型(char [10])
long arr3[10];//arr3数组的类型long型(long [10])
double arr4[10];//arr4数组的类型double型(double [10])
.....
2️⃣一维数组的使用
2.1、数组的下标
数组是有下标的,下标是从0开始的,依次往后,如果数组大小为n,则最后一个元素的下标为n-1,下标相当于数组元素的编号
- 数组arr[10]的 []是下标引用操作符
比如:
#include<stdio.h>
int main(){
int arr[10]={1,2,3,4,5,6,7,8,9,10};
printf("%d\\n",arr[2]);//访问下标为2的元素:3
printf("%d",arr[4]);//访问下标为4的元素:5
return 0;
}
2.2、数组元素的打印
如果想要打印数组的内容,我们可以一个一个的遍历(通过数组下标访问)打印, 字符串数组是可以不用一个一个打印的
#include<stdio.h>
int main(){
char arr1[]="hello";
char arr2[]={'h','e','l','l','o'};
//直接打印字符串数组
printf("%s\\n",arr1);
int i=0;
//一个一个字符打印字符串数组
for(;i<6;i++)//建议是6,因为最后有一个'\\0'的存在
printf("%c ",arr1[i]);
printf("\\n");
//除了字符串数组外,其他类型的数组打印all内容是一个一个打印的
//遍历循环生成0-9的下标,通过数组下标对数组的值进行访问
for(i=0;i<5;i++)
printf("%c ",arr2[i]);
return 0;
}
2.3、数组的输入
也是通过数组的下标进行对数组的访问,将值放入数组之中, 除了字符串数组是可以直接通过数组名将值一口气输入
- 下面是有scanf的知识,如果有忘记的可以打开下面的连接进行学习🔗scanf相关知识:
- 有字符的可以忽略空白字符,避免将空白字符也认为是一个字符,占用数组的空间
- 有字符串的可以不忽略空白字符,保留空白字符
#include<stdio.h>
int main(){
//记得预留数组的大小
char arr1[10]; //字符串数组(要预留'\\0'的位置,所以要大一点,避免越界访问)
char arr2[10]; //字符数组
int arr3[10]; //整型数组
//输入字符串数组
printf("请输入字符串数组的值:");
scanf("%[^\\n]s",arr1);
//输入字符数组
int i=0;
printf("\\n请输入字符数组的值:");
for(;i<5;i++)
scanf(" %c",&arr2[i]);
//输入整型数组
printf("\\n请输入整型数组的值:");
for(i=0;i<5;i++)
scanf("%d",&arr3[i]);
//打印数组的值:
printf("\\n%s",arr1);
printf("\\n");
for(i=0;i<5;i++)
printf("%c",arr2[i]);
printf("\\n");
for(i=0;i<5;i++)
printf("%d",arr3[i]);
return 0;
}
2.4、数组的内存中的存储 (连续存放)
从下面的代码中,我们可以看到数组的首元地址,整个数组的地址和数组的第一个元素地址的值是一样的,它们除了表达方式不同外是一样的没有任何区别
依次打印数组元素的地址:
#include<stdio.h>
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (; i < 10; i++)
printf("地址:arr[%d]=%p\\n", i, &arr[i]);
printf("地址arr:%p\\n", arr);
printf("地址&arr:%p\\n", &arr);
printf("地址arr[0]:%p", &arr[0]);
return 0;
}

从输出的值可以看出,数组随着下标的增长,地址是从小到大变化的,每个相邻的元素之间相差4,从下标为0的开始向下逐一+4(一个整型是4个字节)
- 由此我们可以知道 数组在内存中是连续存放的
- 上面编译运行出来的地址看着不同,是因为配置环境不同,
- 第一个是x64(配置64位环境,编译出来时64位程序,只可以在64位环境中运行),
- 第二个是x86(配置32位环境,编译出来时32位程序,只可以在32/64位环境中运行)
- 我们也可以看的出来 数组、数组首元素、数组名 它们的地址相同
3️⃣sizeof计算数组元素个数
遍历数组时,我们会想知道数组的个数,可以用sizeof计算数组的个数
- sizeof是C语言的一个关键字,可以计算类型(在我们前面的学习中有涉及到🔗sizeof求数据类型的大小)或者变量大小的,可以计算数组的大小,以字节为单位
- 从下图中可以看出:
- arr5和arr4可以得到数组的大小是和数组元素个数相关的,是写死的,不会因为后面字符串所书写的个数而影响数组的实际大小

- arr5和arr4可以得到数组的大小是和数组元素个数相关的,是写死的,不会因为后面字符串所书写的个数而影响数组的实际大小
- 我们可以计算某一个元素的大小,例如:
#include<stdio.h>
int main(){
int arr1[5]={0};
printf("arr1[0]=%zu\\n",sizeof(arr1[0]));//4字节
return 0;
}
从上面我们知道如何计算数组的大小和数组中某一个元素的大小,那么我们可以计算数组元素的个数了,数组的大小/数组某个元素的大小
#include<stdio.h>
int main(){
int arr1[5]={0};
printf("%zu",sizeof(arr1)/sizeof(arr1[0]));
/*
* 也可以将数组的元素个数通过某一个变量接收后在输出其
int sz=sizeof(arr1)/sizeof(arr1[0]);
printf("%zu",sz);
*/
return 0;
}
当数组元素个数的地方例如:arr[20]写死后,无论如何写数组大小均不发生改变
✒️小结:
- 上面我们学习了一维数组,后面我们将会学习二维数组
- 二维数组其实是在一维数组的基础上发生部分变动,底层的没有太大变化,为了后面的学习我们需要将数组的基础用法学透。
如果上面的内容有错误和不足欢迎大家在评论区指出,会积极修正! 感谢大家的阅读🌹🌹


