让搜索引擎收录网站,做长图文网站,网站美工建设软件,做任务有奖励的网站前言 数组是C语言中的一种自定义数据类型#xff0c;它的使用非常广泛。但是很多新手在使用数组时#xff0c;经常在一些细节上出问题#xff0c;导致程序崩溃或者无法编译。今天#xff0c;我就来详细聊聊数组的使用和我注意到的一些细节。 一、常见的数组类型与数组的创建… 前言 数组是C语言中的一种自定义数据类型它的使用非常广泛。但是很多新手在使用数组时经常在一些细节上出问题导致程序崩溃或者无法编译。今天我就来详细聊聊数组的使用和我注意到的一些细节。 一、常见的数组类型与数组的创建
1. 常见数组类型 与常见指针类型类似常见的数组类型也是与常见的数据类型一一对应的这里简单列举几个最常用的。
int arr1[10]; //整型数组
char arr2[20]; //字符数组
double arr3[5]; //双精度浮点型数组
struct stru arr[6]; //结构体数组
2. 数组的创建
int arr1[10]; //创建数组
int arr2[5] {0,0,0,0,0}; //创建数组并完全初始化
int arr3[10] {0}; //创建数组并不完全初始化
int arr4[] {1,2,3,4,5}; //创建未给定大小的数组并初始化 我们以整型数组为例上方为整形数组的四种创建与初始化方式。 首先来介绍第一行也是最基础的数组创建方式“数据类型 数组名 [数组大小]”。其中数组名和[ ]之间不能出现空格数组大小只能为常量可以为标识符常量且只能为正整数。那么我们来解读第一行就是一个名为“arr1”可以存放10个整型数据的数组数组大小为10个整型即40个字节该数组的数据类型为int[10]。 我们可以用“sizeof()”来计算数组在内存中占用的空间大小如下图。 接下来看第二行数组arr2为一个大小为5的整型数组它的五个数据均被初始化为0。其中花括号中的第一个0即对应数组的第一个数据称为数组的第一个元素以此类推。 同理第三行的arr3数组为一个大小为10的整型数组它的第一个元素被初始化为0剩余的9个元素未初始化。 第四行的arr4数组在创建时未给定大小那么它的大小就由初始化的元素个数决定。由此得出arr4的大小为5。 补充变长数组 VS编译器不支持 变长数组与常规数组的区别在于常规数组在定义时其数组大小只能为常量而变长数组的大小可以为变量。因此变长数组可以精准地开辟内存空间从而避免空间浪费。
3. 字符数组的初始化
char ch1[] {a,b,c};
char ch2[] abc; 字符数组可以按照常规数组初始化方式进行初始化也可以按照上图第二行的方式直接用字符串进行初始化。那么上图中的ch1ch2的大小分别是多少呢显然ch1的大小为3那么ch2的大小也为3吗我们来看下图。 我们发现数组ch2的大小为4这又是为什么呢我们不妨直接将这两个数组以字符串形式打印出来看看。 可以看见第一行出现了许多乱码而第二行则是正常的abc。这是为什么呢关于这个问题等到介绍数组在内存中的存储方式时我再来详细解释。 二、数组元素的访问 当我们创建了一个数组后我们应该如何调用数组中的元素呢换句话说如何访问数组的元素呢
1. 下标引用操作符
// [] - 下标引用操作符 int arr[10];
arr[0] 1; 数组的每个元素都有自己对应的下标通过其下标即可访问该元素。我们可以通过下标引用操作符“[ ]”。如图arr为一个大小为10的整型数组当我们创建了数组之后我们通过“数组名 [元素下标]”访问了arr数组中下标为0的元素并将其赋值为1。 注意上方代码中创建数组和访问数组元素均使用了“[ ]”但这两个“[ ]”的含义不同第一行的“[ ]”代表arr为一个int[10]类型的数组而第二行的“[ ]”则是下标引用操作符用来访问数组元素。 数组中第n个元素的下标为n-1例如第一个元素的下标为0。 2. 指针访问
int arr[10];
*(arr1) 2; //等价于 arr[1] 2; 本质上数组名就是指向数组起始地址的指针。由于数组arr为整型数组故访问数组元素时其数组名本质上为 int* 类型的指针可通过指针的解引用操作符访问其指向的元素。图中“arr1”即指针向后偏移一位指向了数组中的第二个元素因此等价于访问数组第二个元素。 int arr[10];
int* p arr;
*(p1) 2;同样地我们也可以用其它指针储存arr所指向的地址并通过该指针访问数组元素如图中的指针p。 三、数组在内存中的存储 相信通过上面的访问方式聪明的你一定已经猜到数组在内存中的存储形式了。数组在内存上占用一块连续的空间。我们通过VS的调试器来观察数组在内存中的存储如下图。每个整型数据占用四个字节的空间故地址每隔四存放一个数据。 而数组名arr即是首元素的地址我们可以通过打印地址来查看。这也就解释了为什么数组元素可以通过指针的方式来访问。 接下来我们来解决之前字符数组留下来的问题。 通过监视窗口我们可以看到ch1中只有三个元素相比之下ch2多出了第四个元素\0。\0是一个字符用来终止字符串。 由于ch2中存在\0打印ch2时才不会出现后面的随机值。而ch1中没有\0因此当ch1的元素全部打印完后编译器会继续打印数组外的内容由于未被赋值这些内容通常为随机值因此一直打印到遇到随机的\0打印才结束。 使用双引号 引用的字符串的末尾都会自带一个\0这就是为什么用abc初始化ch2后会多出一个\0。 四、二维数组
1. 二维数组的创建
int arr1[3][3] {0};
int arr2[][3] {0}; 二维数组有以上两种创建方式其中前后两个“[ ]”中的数字我们分别称为行数和列数。二维数组的大小等于行数乘以列数。 在第一行中我们给定了数组arr1的行数和列数均为3因此arr1的大小为9即可容纳九个元素。同样如果行数和列数都给定了就可以选择不初始化。 在第二行中我们给定了数组arr2的列数但没有给定行数这样一来数组的大小就根据初始化的值来确定了如图中将第一个元素初始化为0那么为了存储元素0数组必须开辟一行的空间由于一行有三列因此数组arr2的大小为3。从中我们可以看出为给定行数的二维数组的大小是由列数和初始化元素个数决定的。其大小必须为列数的整数倍并且必须大于元素个数。 2. 二维数组元素的访问
int arr[3][3];
arr[0][0]1; 二维数组的元素也是通过下标来访问的只不过由于二维数组有行和列因此下标也分为行标和列标。同样的行标和列标也都是从0开始如图中arr[0][0]即是访问第一行第一列的元素。 关于二维数组的指针访问本文就不过多解释了因为相对来说比较复杂涉及到二维数组的原理。有兴趣的小伙伴可以自行推导。提示要用到二级指针 3. 二维数组在内存中的存储 在我们理解二维数组时我们把二维数组分成行和列如上图。我们知道一维数组在内存中是占用一块连续的空间。那么二维数组在内存中又是如何存储的呢我们再次通过VS的内存窗口观察二维数组arr在内存中的存储情况。我们发现二维数组在内存中也是连续存储的并不是像我们理解的那样分为行和列来存储。 五、数组问题中一些常见的错误和技巧
1. 越界访问
int arr[10] {1,2,3,4,5,6,7,8,9,10};
int a arr[10]; 我们来看上面这段代码。首先创建一个大小为10的整型数组并完全初始化然后创建一个整型变量a并初始化为arr数组中下标为10的元素。但是数组arr的大小为10那么它最大的下标应该为9也就是说不存在下标为10的元素。这就是所谓的越界访问。 由于数组创建时只开辟了10个整型大小的合法空间而上方代码访问了第11个整型的空间因此形成非法访问。 2. 初始化与修改数组元素
//错误示范
int arr[] {1,2,3,4,5};
arr {1,2,3,0,0};
char ch[] hello;
ch world;//正确做法
int arr[] {1,2,3,4,5};
arr[3] 0;
arr[4] 0;
char ch[] hello;
ch strcpy(ch,world); 在讲数组的初始化时我提到可以使用花括号和字符串进行初始化。但是要注意当数组创建完毕并初始化后就不能再使用花括号或字符串来修改数组了。如果数组创建完成后需要修改数组元素则需通过下标访问需要修改的元素进行修改若需要整体修改则可借助循环遍历数组。 3. 数组传参
void test(int* arr)
{arr[0] arr[1];
}int main()
{int arr[3] {0,1,2};test(arr);return 0;
}之前介绍访问数组的方法时就提到数组名其实就是指向数组首地址的指针也就是说数组传参其实也就等价于指针传参。在声明函数的参数时若需接受数组只需要声明一个同类型的指针变量即可。 结束语 以上就是我对数组的一些基础知识的总结啦。关于数组我个人还是更喜欢将其理解为指针的一种变体因为C语言中指针可以说与内存息息相关而数组则是通过一个指针(数组名)来管理该数组空间内的所有数据。不知道大家都是如何理解的呢欢迎在评论区留言。