
首先声明此博客不照搬抄袭存在自己的见解我所使用的编译器是VS2022目录1. 数组的概念2. 一维数组的创建和初始化3.数组的类型4. 一维数组的使用5. 一维数组在内存中的存储6. sizeof计算数组元素个数7. 二维数组的创建和初始化8. 二维数组的使用9. 二维数组在内存中的存储10. C99中的变长数组一、数组的概念数组就是一组相同类型元素的集合注意1数组的元素个数不能为0如int arr[0]这样写是不成立的2数组的初始化int arr[1]{};如果什么都不写在C99以及之后会自动将数组里的元素全部初始化为03数组中的所以元素它们的类型都是相同的分为一维数组和多维数组常见的是二维数组二、 一维数组的创建和初始化语法形式数据类型数组名[常量表达式]{初始化}; 例如int arr[3]{1,2,3};数据类型可以是char、short、int、float、double等也可以是自定义类型如结构体类型数组名可以任意取但不能取C语言已经存在的关键字其他的有意义就行常量表达式选取实际需要合适的常量值来设定大小就好了初始化用大括号括起来//完全初始化 int arr1[3] { 1,2,3 }; //不完全初始化arr[0]存的是1剩下元素自动初始化为0 int arr2[3] { 1 }; ////错误的初始化 - 初始化项太多,编译器会直接报错 int arr3[3] { 1,2,3,4 };一维数组的初始化[ ]内也可以不写常量比如int arr[ ]{1,2,3};这样初始化也是可以的编译器会根据你大括号内所写的元素个数来给数组arr设定合适的大小三、数组的类型数组去掉数组名留下的就是数组的类型例如int arr[10]; //类型为 int [10]char ch[5]; //类型为char [5]int arr1[3][5]; //类型为int [3][5]算是一种自定义类型四、一维数组的使用1.数组下标int arr [n];n为常量表达式int arr[10]{1,2,3,4,5,6,7,8,9,10};数组每个元素分别都对应着一个下标从0开始到n-1分别对应着一个数[ ]:下标引用操作符用于对数组的元素进行访问它是双目操作符有两个操作数分别是数组名和元素下标例如我们想访问数组里的10这个数我们先找10对应的下标是9数组名是arr所以对应的引用就是arr[9],就能找到10。也可以写9[arr]两个操作数交换位置不影响访问结果2.数组元素的打印#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(%d , arr[i]); } return 0; }运行截图注意直接写printf(%d ,arr)是无法打印出整个数组的只会打印出一串地址数因为单独的arr数组名所代表的含义是数组首元素的地址所以arrarr[0]。而且因为是用%d打印所以会把二进制位的地址数强行转化成一串十进制的数打印出来所以我们在打印整型数组时应该使用循环分别找到每个数对应的下标依次引用访问打印例如下方情况#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(%d , arr[i]); } printf(\n); printf(%d , arr); return 0; }运行截图但是如果是字符串数组例如char ch{abcde}那就可以用printf“%s”ch直接来打印数组而不需要使用循环例如下方代码#include stdio.h int main() { char ch[10] {abcde}; printf(%s\n, ch); return 0; }运行截图这是因为printf中使用%s打印字符串的规则就是找到字符串首元素的地址后会依次从低地址向高地址处打印直到遇到字符\0才会停下来而ch正是字符串首元素的地址字符串末尾会隐藏一个\0所以不会存在打印出错打印abcde后遇到\0就停止了打印3.数组元素的输入#include stdio.h int main() { int arr[10] { 0 }; int i 0; //输入数组元素 for (i 0; i 10; i) { scanf(%d, arr[i]); } //打印数组元素 for (i 0; i 10; i) { printf(%d , arr[i]); } return 0; }整型数字数组元素的输入也需要用循环输入数值一个个给每个数组的元素但对于字符数组的输入不需要使用循环运行截图下面演示字符数组输入的代码#include stdio.h int main() { char ch[10] { 0 }; int i 0; scanf(%s, ch); printf(%s\n, ch); return 0; }运行截图如图所示输入“abcde”可以正常打印但输入Hello bit时却只打印了Hello这里我们就要扩展一个知识点%s在scanf中遇到空白字符会自动截止不读取空白字符只读取空白字符之前的字符并且读完自动在末尾加 \0所以只读取了Hello想要解决这个问题我们要用到一个新的占位符%[^\n]扩展%[^\n]%[^\n]意思是除非遇到\n换行\n之前的内容全部读取是【仅属于 scanf】的专属格式占位符#include stdio.h int main() { char ch[10] { 0 }; int i 0; scanf(%[^\n], ch); printf(%s\n, ch); return 0; }运行截图五、一维数组在内存中的存储数组在内存中的存储是连续存放的并且随着小标的增长地址也从小到大从低到高增长我们可以来验证一下%p用于打印地址#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; }运行截图可以看到整型数组的每一个元素都为int类型占四个字节的地址内存图中arr[1]的内存地址正好比arr[0]的高四个字节的内存单元地址刚好是一个整型下方的也都一样都间隔四个四节的内存单元地址由此可说明数组在内存中的存储是连续的一个地址占一个内存单元单位为字节六、 sizeof计算数组元素个数sizeof操作符是一个可用于查询计算数据类型所占总空间的字节大小它的查询原理是在编译阶段就查询了C语言规定的各个数组类型的定义表格比如sizeofint编译时sizeof就查询int类型C语言规定是4个字节所以sizeofint结果就为4sizeofint [10])计算时其实是在编译阶段查询了int为4个字节然后已知这个数组中有10个元素就会直接计算4×1040来获得数组所占总空间字节的大小#include stdio.h int main() { int arr[10] { 0 }; printf(数组类型所占总字节大小%d\n, sizeof(int [10])); printf(数组空间所占总字节大小%d\n, sizeof(arr)); printf(数组元素所占字节的大小%d\n, sizeof(arr[0])); printf(数组中元素的个数%d\n, sizeof(arr)/sizeof(arr[0])); return 0; }运行截图sizeof(arr):数组空间所占总字节大小sizeof(arr[0]):数组元素所占字节的大小我们用sizeof(arr)/sizeof(arr[0])来计算出数组元素的个数七、 二维数组的创建和初始化1.二维数组的概念二维数组其实就是把一维数组作为了数组的元素就称之为二维数组亦知如果把二维数组作为数组的元素那么这个数组就被称为三维数组2.二维数组的创建数据类型数组名[常量表达式][常量表达式]{初始化} 例如int arr[3][5]{0};第一个常量表达式表示 行 第二个常量表达式表示 列int arr[3][5]表示一个3行5列的整型数组如下图所示3.二维数组的初始化//完全初始化 int arr[3][3] { {1,2,3} ,{ 2,3,4 } ,{ 3,4,5 } }; //完全初始化 int arr1[3][3] {1,2,3,2,3,4,3,4,5}; //不完全初始化只初始化的arr[0][0]为3剩下的元素自动初始化为0 int arr3[3][3] {3}; //不完全初始化只初始化每一行的前两个元素剩下的元素自动初始化为0 int arr4[3][3] {{12}{23}{34}};int arr[3][3]表示数组有3行3列初始化每一行都用一个括号括起来这样看起来更加清晰明了不加也没事就像上面的int arr1[3][3]的初始化那样也可以注意一维数组初始化时[ ]内部的常量可以省略编译器通过元素的个数来设定数组大小但int arr[]{};当你没有给数组给定大小时就不能不初始化不然编译器无法算出数组的大小会显示错误二维数组初始化时int arr[行][列],行可以省略但列不能省八、二维数组的使用1.数组下标二维数组的行下标是从0开始的列下标也是从0开始的例如int arr[3][5] {{1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7}}我们可以把二维数组看成一个个一维数组的集合如上图二维数组我们可以看成三个一维数组分别是int arr[0]int arr[1]int arr[2]这三个分别是它们的数组名然后我们再访问里面的元素如想访问第0行第0列的元素就使用int arr[0][0]2.数组元素的输入和打印#include stdio.h int main() { int arr[3][5] { 0 }; int i 0; //数组元素的输入 for (i 0; i 3; i) //产⽣⾏号 { int j 0; for (j 0; j 5; j) //产⽣列号 { scanf(%d, arr[i][j]); //输⼊数据 } } //数组元素的打印 for (i 0; i 3; i) { int k 0; for (k 0; k 5; k) { printf(%d , arr[i][k]); } printf(\n); } return 0; }运行截图九、 二维数组在内存中的存储二维数组在内存中的存储也是连续的我们可以打印出来看看#include stdio.h int main() { int arr[3][5] { {1,2,3,4,5} ,{ 2,3,4,5,6 } ,{ 3,4,5,6,7} }; int i 0; int j 0; for (i 0; i 3; i) { for (j 0; j 5; j) { printf(arr[%d][%d] %d 地址为%p\n, i, j,arr[i][j], arr[i][j]); } } return 0; }运行截图可以看到按照下标的顺序地址都是从小到大排列每个间隔四个字节刚好是一个数组元素的大小这说明二维数组中的元素在内存中的存储也确实都是连续的十、C99中的变长数组变长数组的好处就是我们在之前使用int arr[常量]{初始化}初始化数组时我们数组元素的大小都被固定了而有了变长数组之后我们之前存放数组的初始化大小的常量就可以变成存放变量我们在每次运行的时都可以重新设定数组的大小不用再修改代码解决了有时候数组大小太大占内存或者太小数组大小不够用的情况要注意的是由于变长数组的大小由于是在运行时创建的所以变长数组不能初始化因为一旦初始化数组的大小就会被确定和变量冲突会直接报错int n; scanf(%d, n); // 运行时输入大小 int arr[n]; // 用变量n做大小在C99以及C99之后的编译器基本都支持变长数组但Vs编译器尚未添加变长数组这个语法所以我用Devc来验证实现变长数组#include stdio.h int main() { int n 0; printf(数组长度); scanf(%d, n); int arr[n]; int i 0; printf(元素, n); for (i 0; i n; i) { scanf(%d, arr[i]); } printf(你输入的数组是); for (i 0; i n; i) { printf(%d , arr[i]); } return 0; }运行截图第一次修改数组长度为5运行截图第二次修改数组长度为10程序员不需要在再创建数组时给其一个估计的大小而是可以在运行后再给其分配所需的精确长度做到不浪费占用多余的内存内存利用率更高