新手必看!C语言数组宝宝级讲解,看完直接懂

📅 2026/7/9 13:57:35 👁️ 阅读次数 📝 编程学习
新手必看!C语言数组宝宝级讲解,看完直接懂

1. 数组的概念

1.1 基本概念

数组是一组相同类型元素的集合;那宝宝们从这个概念中我们可以可以发现两个重要的信息:

  • 宝宝们数组中存放的是1个或者多个数据,但数组元素个数不能为0
  • 宝宝们数组中存放的多个数据,类型是相同的

还有宝宝们数组分为一维数组和多维数组,二维数组是最为常见的多维数组

2. 一维数组

2.1 一维数组的创建

//一维数组创建的基本语法如下: type arr_name[常量值]; //type:数组存放数据的元素类型,可以是:char、short、int、float等,也可以自定义的类型。 //arr_name:数组名,这个名字可以自定义。 //[常量值]:宝宝们这里的常量值表示数组元素的个数,可以用来指定数组的大小。

宝宝们下面我们就来创建一些数组:

int data[10]; char ch[20];

宝宝们因为讲了数组的创建就不得不讲一下数组中有的类型了:

就拿 int data[10]; 这个数组来说: 元素类型:int 数组类型:int[10] 数组指针类型:int (*)[10]

2.2 一维数组的初始化

宝宝们在有时候在数组创建的时候我们要指定一些初始值,这个过程我们就叫它数组的初始化。
当然宝宝们,数组初始化分为完全初始化和不完全初始化,下面我就来一一介绍:

intmain(){//完全初始化:intarr1[5]={0,1,2,3,4};intarr2[]={0,1,2,3,4};//宝宝们这种也是完全初始化 编译器推断为arr2[5]//不完全初始化:intarr3[5]={0,1,2};intarr4[5]={0};//错误的初始化://int arr5[];//不能这样初始化 可以不初始化数组长度,也可以不初始化数组的内容,但是不能两个都不初始化//int arr5[5] = {0, 1, 2, 3, 4, 5};//数组越界初始化 问题:初始化列表元素数量(6个)超过了数组声明大小(5个)。return0;}

int arr5[];问题:

宝宝们这样写编译器无法确定数组的大小

int arr5[];//大小未知,编译器无法分配栈空间 int arr5[10];//明确占用10 * sizeof(int)字节

一维数组越界初始化问题:

  • 编译期:GCC/Clang会产生警告excess elements in array initializer
  • 运行期:超出的元素会被丢弃,数组实际只存储前面一些在它存储大小内的元素
int arr5[5] = {0, 1, 2, 3, 4, 5};//arr5实际只存储{0, 1, 2, 3, 4},最后的5被抛弃

2.3 一维数组的下标 | 索引

宝宝们c语言规定数组是有下标(也可以叫索引)的,数组是通过下标访问到具体元素的,下标从0开始,假设数组有个n元素,那最后一个元素的下标为n-1,下标就相当于数组元素的编号,就比如:

宝宝们有了下标访问操作符,我们就可以轻松的访问到数组的元素了,比如我们访问下标为0的元素,我们就可以使用arr[0],想要访问下标是3的元素,就可以使用arr[3],如下代码:

#include<stdio.h>intmain(){intarr[5]={1,2,3,4,5};printf("%d\n",arr[0]);//0printf("%d\n",arr[3]);//3return0;}

2.4 一维数组元素的输入输出

宝宝们整形一维数组是没有办法一次性输入和输出的,只能这样:

#include<stdi.h>intmain(){intarr[5]={0};for(inti=0;i<5;i++){scanf("%d",&arr[i]);}for(intj=0;j<5;j++){printf("%d ",arr[j]);}return0;}

但是宝宝们字符型一维数组不仅仅只有上面那种写法,还有这种:

#include<stdio.h>intmain(){chararr[100];scanf("%s",arr);printf("%s\n",arr);return0;}

2.5 计算一维数组元素个数

宝宝们我们计算数组元素个数的时候一般用**sizeof**

宝宝们sizeof中C语言是一个关键字,是可以计算类型或者变量大小的,但也可以用sizeof也可以计算数组的大小。

#include<stdio.h>intmain(){intarr[5]={0};printf("%d\n",sizeof(arr));//输出结果为20return0;}

宝宝们这里输出的结果是20,计算的是数组所占内存空间的总大小,数组所占内存空间的总大小 = 元素个数 × 单个元素字节数,整形元素字节数为4,所以数组所占内存空间的总大小 = 4 * 5 = 20。所以宝宝们我们要计算元素个数就要 数组所占内存空间的总大小 / 单个元素字节数,这里我们一般选择第一个元素
那宝宝们接下来就来计算出数组元素个数:

#include<stdio.h>intmain(){intarr[5]={0};intsz=sizeof(arr)/sizeof(arr[0]);printf("%d\n",sz);//5return0;}

这里的结果是5,表示数组最大存储5个元素,宝宝们。

3. 二维数组

3.1 二维数组的概念

宝宝们因为数组都是内置类型的,如果我们把一维数组做为数组元素,这时候所组成的数组就是二维数组,同理把二维数组做为数组元素就是三维数组,二维数组以上的数组通称为三维数组。

3.2 二维数组的创建

type arr_name[常量1][常量2];//表示常量1行常量2列 比如: int arr1[1][5];//表示1行5列 int arr2[3][5];//表示3行5列

二维数组中有的类型:

宝宝们我们拿 int arr2[3][5] 这个数组来说: 元素类型:int[5] 数组类型:int[3][5]

3.3 二维数组的初始化

宝宝们,二维数组的初始化也分为完全初始化和不完全初始化:

intmain(){//完全初始化:intarr1[3][5]={0,1,2,3,4,1,1,2,3,4,2,1,2,3,4};intarr2[3][5]={{0,1,2,3,4},{1,1,2,3,4},{2,1,2,3,4}};intarr3[][5]={{0,1,2,3,4},{1,1,2,3,4},{2,1,2,3,4}};//不完全初始化:intarr4[3][5]={0,1,2};intarr5[3][5]={0};intarr6[3][5]={{1,2},{3,4},{5,6}};intarr7[][5]={{1,2},{3,4},{5,6}};//错误的初始化:intarr8[3][]={{0,1,2,3,4},{1,1,2,3,4},{2,1,2,3,4}};intarr9[][]={0,1,2,3,4,5};//二维数组的初始化可以省略行但是不能省略列intarr10[3][5]={{0,1,2,3,4},{1,1,2,3,4},{2,1,2,3,4},{3,1,2,3,4}};//数组越界初始化return0;}

宝宝们我们来说一下int arr8[3][] = {{0, 1, 2, 3, 4}, {1, 1, 2, 3, 4}, {2, 1, 2, 3, 4}};错误初始化的问题:
这报错根本的问题编译器无法计算元素地址,访问arr[i][j]的地址计算公式为:base_addr + (i × 第二维长度 × sizeof(int)) + (j × sizeof(int)),如果j未知编译器无法计算行偏移,宝宝们就比如二维数组是一栋房子i代表楼层数,j代表每层的房间数,要找「2楼3号房」,必须先知道每层有多少个房间,才能算出2楼从哪里开始:2楼起点 = 入口 + (2 × 每层房间数 × 房间大小),如果每层房间数未知,根本不知道2楼从哪里开始,找不到任何房间。
那宝宝们为什么int arr[][5] = {0, 1, 2, 3, 4, 5};能够这样初始化呢?
编译器会用总元素数 ÷ 列数来推导出行数,如果是int arr[][] = {0, 1, 2, 3, 4, 5};这样没有列数就不能推导出行数,所以宝宝们这样初始化也不行。
总结:二维数组的初始化可以省略行但是不能省略列

3.4 二维数组的下标 | 索引

宝宝们二维数组访问也是使用下标(或者索引)的形式的,只要锁定了行和列就能唯一锁定数组中的一个元素,当然行和列也都是从0开始的。
就比如:

intmain(){intarr[3][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};printf("%d\n",arr[2][3]);//14return0;}

3.5 二维数组的输入和输出

宝宝们因为二维数组有行和列所以二维数组的输入和输出要用2个for循环

#include<stdio.h>intmain(){intarr[3][5];for(inti=0;i<3;i++)//行{for(intj=0;j<5;j++)//列{scanf("%d",&arr[i][j]);}}for(inti=0;i<3;i++)//行{for(intj=0;j<5;j++)//列{printf("%d ",arr[i][j]);}printf("\n");}return0;}

4. 数组在内存中的存储

宝宝们在了解数组在内存中的存储我们先得了解x64x86之间的关系:

  • x64:编译产生64位的程序地址是64位的,比较长
  • x86:编译产生32位的程序地址是32位的,比较短

那宝宝们我们就分别用x64x86来依次打印数组元素地址
代码如下:

#include<stdio.h>intmain(){intarr[5]={0,1,2,3,4};for(inti=0;i<10;i++){printf("&arr[%d] = %p\n",i,&arr[i]);}return0;}


结论:宝宝们我们从输出的结果来分析,数组随着下标的增长,地址是由小到大变化的,并且宝宝们我们发现每两个相邻的元素之间相差4(因为一个整形是4个字节)。所以,宝宝们我们得出结论:数组在内存中是连续存放的,随着数组下标的增长,地址是由小(低)到大(高)变化的。

5. 总结

上面结论这么多,那宝宝们我们现在来总结一下吧

  1. 数组的概念:数组是一组相同类型元素的集合
  2. 一维数组:
要点说明
创建type arr_name[常量值];
初始化完全/不完全初始化;[]中的常量值可省略但需有初始化列表
访问arr[i],下标从0开始
输入输出整形用循环逐个;char型可直接用%s
元素个数sizeof(arr) / sizeof(arr[0])
  1. 二维数组:
要点说明
创建type arr[行][列],本质是"一维数组的数组"
初始化行可省略,列不可省略(编译器靠列数计算地址偏移)
访问arr[i][j],行列均从0开始
输入输出必须用两层for循环
  1. 内存存储:

数组在内存中连续存放,随下标增大,地址从低到高递增,相邻元素地址差 = sizeof(元素类型)