
文章目录一、数组的概念二、一维数组1. 一维数组的创建2. 一维数组的初始化3. 数组的类型4. 一维数组的使用5. 一维数组在内存中的存储6. sizeof计算数组元素个数三、二维数组1. 二维数组的概念2. 二维数组的创建3. 二维数组的初始化4. 二维数组的使用5. 二维数组的输入和输出6. 二维数组在内存中的存储7. 二维数组中对于数组名的理解四、字符数组1. 字符串常量2. 指针存储字符串常量3. 数组存储字符串常量一、数组的概念数组是一组相同类型元素的集合从这个概念中我们就可以发现2个有价值的信息●数组中存放的是1个或者多个数据但是数组元素个数不能为0。●数组中存放的多个数据类型是相同的。数组分为一维数组和多维数组多维数组中一般比较常见的是二维数组。二、一维数组1. 一维数组的创建一维数组创建的语法如下存放在数组中的值被称为数组的元素数组在创建的时候可以指定数组的大小和数组的元素类型。●type指定的是数组中存放数据的类型可以是: char、short、int、float等也可以是自定义的类型。●arr_name指的是数组的名字这个名字根据实际情况起的有意义就行。(注意不要跟关键字重名)●[ ]中的常量值是用来指定数组的大小的(元素个数)数组的大小根据实际的需求指定就行。需要注意在创建数组时[ ]中要给的是一个常量才可以不能给变量。[ ]中可以直接使用常量常量表达式或者宏定义都可以。示例#includestdio.h#defineNUM6intmain(){intarr1[10];intarr2[23];charch[NUM];return0;}2. 一维数组的初始化在创建数组的同时给一些初始值这种就称为数组的初始化。那数组如何初始化呢? 数组的初始化一般使用大括号将数据放在大括号中//完全初始化intarr1[5]{1,2,3,4,5};//不完全初始化intarr2[5]{1};//第一个元素初始化为1,剩下的元素默认初始化为03. 数组的类型数组也是有类型的数组算是一种自定义类型去掉数组名留下的就是数组的类型。例如intarr[10];charch[5];arr数组的类型为int [10]ch数组的类型为char [5]。4. 一维数组的使用学习了一维数组的基本语法一维数组可以存放数据存放数据的目的是对数据进行操作那我们如何使用一维数组呢?(1) 数组下标C语言规定数组是有下标的下标从0开始假设数组有n个元素最后一个元素的下标是n-1下标就相当于数组元素的编号如下intarr[10]{1,2,3,4,5,6,7,8,9,10};在C语言中对于数组的访问提供了一个操作符[ ]这个操作符叫下标引用操作符。有了下标引用操作符我们就可以轻松的访问数组的元素了比如我们访问下标为6的元素我们就可以使用arr[6]想要访问下标是4的元素就可以使用arr[4]如下代码#includestdio.hintmain(){intarr[10]{1,2,3,4,5,6,7,8,9,10};printf(%d\n,arr[6]);printf(%d\n,arr[4]);return0;}运行结果(2) 数组元素的打印如果想在屏幕上打印数组的元素就用for循环产生0~9的下标使用下标访问数组的元素即可#includestdio.hintmain(){intarr[10]{1,2,3,4,5,6,7,8,9,10};inti0;for(i0;i10;i){printf(%d ,arr[i]);}return0;}运行结果(3) 数组元素的输入可以根据自己的需要用scanf函数给数组输入值存入到数组中。给数组输入想要的数据#includestdio.hintmain(){intarr[10]{0};inti0;for(i0;i10;i){scanf(%d,arr[i]);}for(i0;i10;i){printf(%d ,arr[i]);}return0;}运行结果5. 一维数组在内存中的存储一维数组在内存中是怎样存储的呢我们通过下面一段代码来看#includestdio.hintmain(){intarr[10]{1,2,3,4,5,6,7,8,9,10};inti0;for(i0;i10;i){printf(arr[%d]%p\n,i,arr[i]);}return0;}运行结果从输出的结果可以发现数组随着下标的增长地址是由小到大变化的并且我们发现每相邻两个元素之间相差4(因为一个整型是4个字节)。所以我们得出结论数组在内存中是连续存储的。6. sizeof计算数组元素个数在遍历数组的时候我们经常想知道数组的元素个数那C语言中有办法使用程序计算数组的元素个数吗? 答案是有的。通过sizeof可以求数组的元素个数。sizeof是一个操作符用来计算类型或者变量的大小(单位字节)。sizeof也可以用来计算数组的大小#includestdio.hintmain(){intarr[10]{0};printf(%d\n,sizeof(arr));return0;}运行结果输出的结果为40计算的是整个数组所占内存空间的大小单位是字节(数组名单独放在sizeof中计算的是整个数组的大小)。又因为数组中所有元素的类型是相同的所以只要计算出一个元素的大小那数组的元素个数就可以计算出来了。我们通常选择计算第一个元素的大小#includestdio.hintmain(){intarr[10]{0};//计算数组中第一个元素的大小printf(%d\n,sizeof(arr[0]));//计算数组的元素个数intszsizeof(arr)/sizeof(arr[0]);printf(%d\n,sz);return0;}运行结果可以看到第一个元素的大小为4(字节)计算出的数组元素个数为10。以后在代码中需要数组元素个数的地方就不用固定写死了这种计算数组元素个数的方式不管数组怎么变化计算出的大小也会随之变化。三、二维数组1. 二维数组的概念上面学习的数组叫一维数组数组的元素都是内置类型的。如果把一维数组做为数组的元素这时候就是二维数组。二维数组作为数组元素的数组被称为三维数组二维数组以上的数组统称为多维数组。2. 二维数组的创建如何创建二维数组呢语法形式是什么?如下例如intarr[3][5];doubledata[2][7];上面的第一行代码就是一个整型的二维数组。其中●3表示有3行5表示有5列总共有3*515个元素。●int表示数组的每个元素是整型类型。●arr是数组名可以根据自己的需要指定名字(注意不能和关键字重名)。第二行代码是一个双精度浮点型二维数组。3. 二维数组的初始化在创建数组的同时给一些初始值就叫数组的初始化。二维数组的初始化也跟一维数组类似使用大括号初始化(1) 不完全初始化intarr1[3][5]{1,2};intarr2[3][5]{0};在屏幕上打印这两个数组可以看到上面对于两个二维数组不完全初始化的打印结果对于arr1数组只初始化了两个元素即从第一行的一维数组的第一个元素开始从左往右依次初始化。如果一行的元素值给够了就会从下一行一维数组的第一个元素开始从左往右初始化。对于没有给到值的元素会默认初始化为0。arr2数组只初始化了第一行的第一个元素为0其余元素默认初始化为0。如下(2) 完全初始化intarr3[3][5]{1,2,3,4,5,2,3,4,5,6,3,4,5,6,7};在屏幕上打印arr3数组的内容完全初始化就很好理解了在创建二维数组的同时对二维数组的所有元素都给一个初始值就叫作完全初始化对于{ }里的值会从左往右依次给到二维数组对应的元素。如果一行的值够了就会从数组下一行的一维数组的第一个元素开始从左往右初始化。(3) 按照行进行初始化什么叫按照行进行初始化其实就是按照二维数组的每个一维数组进行初始化在二维数组的大括号{ }内部会明确的给出每个一维数组对每个一维数组进行初始化。例如intarr4[3][5]{{1,2},{3,4},{5,6}};打印出数组的内容如下图样式可以看到上面的二维数组按照行进行初始化在大括号的内部明确给出了二维数组的每个一维数组因为一维数组的内容也是用大括号括起来的。所以在二维数组里对每一行进行初始化是遵循一维数组的初始化原则的。(4) 二维数组初始化时可以省略行但不能省略列二维数组在创建并初始化时可以省略行数但是不能省略列数intarr5[][5]{1,2,3};intarr6[][5]{1,2,3,4,5,6,7};intarr7[][5]{{1,2},{3,4},{5,6}};上面三个数组得到数组形式会是可以看到当数组给出列数却没有给出行数时系统会根据你大括号里初始化数据的多少自行计算数组的行数确定数组是什么类型。4. 二维数组的使用二维数组的访问也是使用下标的形式进行的二维数组是有行和列的只要锁定了行和列就能唯一锁定数组中的一个元素。C语言规定二维数组的行是从0开始的列也是从0开始的如下所示intarr[3][5]{1,2,3,4,5,2,3,4,5,6,3,4,5,6,7};上图中最左侧的灰色数字表示行号最上面一行的橙色数字表示列号可以发现下标都是从0开始。比如行号为2列号为3的元素就是6#includestdio.hintmain(){intarr[3][5]{1,2,3,4,5,2,3,4,5,6,3,4,5,6,7};printf(%d\n,arr[2][3]);return0;}运行结果5. 二维数组的输入和输出上面讲过一维数组的访问是通过下标进行的用for循环产生对应的下标。二维数组也是一样的也是通过下标来访问只不过二维数组有行和列两个下标如果要对二维数组进行输入输出的话就要使用两个for循环外层循环控制每一行的循环内层的循环控制每一行里所有元素个数(列数)的循环。比如我们要输入和打印上面的arr数组在屏幕上行的范围是0~2列的范围是0~4用两个for循环产生相应的行和列号#includestdio.hintmain(){intarr[3][5]{1,2,3,4,5,2,3,4,5,6,3,4,5,6,7};inti0;//输入for(i0;i3;i)//产生行号{intj0;for(j0;j5;j)//产生列号{scanf(%d,arr[i][j]);//输入数据}}//输出for(i0;i3;i)//产生行号{intj0;for(j0;j5;j)//产生列号{printf(%d ,arr[i][j]);//打印数据}printf(\n);}return0;}输入数据后得到的结果6. 二维数组在内存中的存储与一维数组一样如果想知道二维数组在内存中的存储方式我们也是可以打印出数组所有元素的地址的。代码如下#includestdio.hintmain(){intarr[3][5]{0};inti0;intj0;for(i0;i3;i){for(j0;j5;j){printf(arr[%d][%d]%p\n,i,j,arr[i][j]);}}return0;}运行结果从输出的结果来看每一行内部的元素两两都是相邻的地址之间相差4个字节跨行位置处的两个元素(如: arr[0][4]和arr[1][0])之间也是差4个字节所以得到的结论是二维数组在内存中也是连续存储的。7. 二维数组中对于数组名的理解在二维数组中数组名表示什么含义我们之前讲过一维数组的数组名是表示数组首元素的地址也就是数组中第一个元素的地址。那二维数组的数组名其实也表示数组首元素的地址但是这个首元素是指哪个呢这里我们要把二维数组看成一维数组。举个例子intarr[3][4]{0};二维数组其实可以看作是由一维数组构成的数组也就是把每行的一维数组整体看做是一个元素则二维数组现在就相当于一个一维数组数组的首元素就是第一行的一维数组则数组名就是第一行一维数组的地址它是一个数组指针。就像上面的arr[3][4]数组数组名arr表示的是第一行一维数组的地址它是一个int(*)[4]类型的数组指针即arrarr[0]。二维数组去掉列下标部分就是一维数组的数组名如下数组名表示的是数组首元素的地址。则二维数组去掉列下标后的数组名如上面的arr[0]、arr[1]和arr[2]分别表示二维数组中每行一维数组的首元素地址即每个一维数组的第一个元素的地址类型是int*的指针arr[0]arr[0][0]、arr[1]arr[1][0]、arr[2]arr[2][0]。所以在二维数组中要区分开上面的两种数组名不能混淆尤其是在sizeof操作符中放有关数组名的各种表达式时要特别区分上面的两种数组名。四、字符数组1. 字符串常量字符串常量(也叫字符串字面量)是用双引号括起来的字符序列例如hello worldabc// 空字符串字符串常量本质上是一个字符数组编译器会自动在末尾添加’\0’作为结束标志。例如 “hello” 实际占用了6个字节‘h’,‘e’,‘1’,1’,‘o’,‘\0’。字符串常量通常存储在程序的只读数据段(.rodata)中程序运行期间不可修改。2. 指针存储字符串常量char*pstrhello world;上面这种将字符串常量的地址(即第一个字符的地址)存放在一个指针变量中这样的话就不能通过pstr去修改这个字符串常量pstr[0]H;// 程序会报错:未定义行为(UB)!试图修改只读内存因为指针指向的是只读区通过它修改内容会导致● 段错误(Segmentation Fault)● 或其他未定义行为正确的写法应该是constchar*pstrhello world;//推荐加const修饰,防止误修改3. 数组存储字符串常量如果是用数组的形式去存储字符串常量那就可以正常的修改字符串常量中的字符chararr[]hello world;// 编译器将字符串复制到栈上存储arr[0]H;这种在函数内部创建的局部数组其实是在栈区存放着所以可以修改数组元素。char arr[] hello的本质是chararr[]{h,e,l,l,o, ,w,o,r,l,d,\0};