在正式讲解C语言数组之前,我们可以先了解一下,为什么出现数组这种自定义的数据类型? 其实想解决这个问题,非常的简单! 请看下面的例子:
// 假如我要设置4个整型变量,分别存放10,20,30,40.那代码也许你会这样写:
int a = 10;
int b = 20;
int c = 30;
int d = 40;
//也可能有的人这么写
int a = 10,b = 20, c = 30, d = 40;
看到这里,你也许会说,第二种写法不是比第一种写法更简洁、更好啊。但实际上,这两种的写法本质上是一样的。试想一下,如果你在写一个超大的项目代码时,不是关键的变量名的数量增加时,会大大降低代码的可读性。为了解决这种问题,数组就横空出世了!!!
接下来,让我们讨论一下数组是什么? 结合序言的例子,你也许就会有一个大致的概念:这个数组应该是可以同时存放一个或多个相同的数据类型。
没错,这个猜想十分的不错!!!👍👍👍
数组是一组相同类型元素的集合。
从这个概念中我们可以提取一些关键的信息:
数组的分类:一维数组和多维数组,多维数组一般比较常见的是二维数组。
我们在上面了解到了什么是数组了,那我们也应该知道该怎么创建和初始化数组了。
一维数组创建的基本语法:
type arr_name[常量值];
type : 指的是这个数组所存储元素的数据类型 arr_name : 指的是数组名。就像我们设置一个变量,都有个变量名一样。 [] : 里面的常量值就是指定数组能存放多少个元素,根据实际情况而定。
如果你看到这里还是有点懵的话,没有关系,下面就上例子:
//紧接这序言的内容,我们可以这样修改:
int num[4]; //里面就可以放4个整型类型的元素
//比如我想存放之前20个前女友的年龄,那我们可以创建一个数组存放这些数据:
int age[20];
//当然我们也可以根据实际情况设置其他的类型的数组,比如:
char name[10];
double score[50];
float weight[30];
有时候,在数组创建之初,我们就想在给数组里面制定一些初始值,这种操作就称为数组的初始化。
那数组的初始化是什么样子的呢?就是在一对大括号里面制定自己想要数据,并用逗号隔开。 演示:
//完全初始化
int arr[5] = {1,2,3,4,5};
//不完全初始化
int arr2[6] = {1} //这种赋值方式,意味着数组第一个元素被赋值为1,其余元素默认赋值为0
//错误的初始化 - 初始化的元素个数超过了数组本身元素的个数了
int arr3[3] = {1,2,3,4}; //err
这里主要展示数组的各种初始化情况,主要是注意一点:在数组遇到不完全初始化时,未被初始化的元素会被编译器默认初始化为0。
数组也是有类型,正如:整数为整型类型,字符为字符类型等等。
而数组类型该是怎样的呢? 你也许可能会猜:假如一个这样的数组 int arr[10],是不是就是int类型。可结果且大失所望。
不难推测,如果我给你一个整型的变量,形如下面:
int a = 10;
这是我问你,这个变量a是什么样的数据类型?你肯定会好不犹豫的说,这a是个整型变量。 但是是什么让你得出这个这个结论的,你也许会说,这个我是记住了的。 那么下面我将展示一个新的认识思路,希望读者们能够理解这个思路,这个思路对你们后期学习其他的数据类型很有帮助。
全新认识类型的视角:
假如我给你一个这样的语句:
int a; - > int a ; 是不是就为int类型了。
char ch; - > char ch ;是不是就是char类型了。
看到这里,你也许会惊叹既然还有这种理解方式。(作者第一次看到的时候也震惊了😮😮😮)
那基于这种理解方式,我们再去拆解数据的数据类型就会显得格外简单了。
下面我就讲几个例子,让你们理解得更加深刻:
int arr[5] ; - > int arr [5] 。int [5]就是数组的类型。
char ch[10]; - >char ch [10]。char [10]就是这个数组的类型。
看到这里也写读者可能就会发问,这个类型这么复杂,它能是真的吗? 下面我用VS(Visual Studio)的调试功能求证来这个点。
练习(找出这些数组的类型): 一定要先自己思考!
int arr1[10];
int arr2[12];
char ch[5];
答案:
在上面我们学习了一维数组的基本语法,一维数组可以存放一个或者多个相同数据类型的数据,我们存放数据的目的是:有朝一日能够从其中取出来使用。但是,我们该如何从数组中读出我们出入的数据呢? 这部分的知识比较重要!
C语言规定数组是有下标的,并且 下标是从0开始的(这个点一定要记住,新手特别容易犯错的点!)。假设数组中有n个元素,那么最后一个元素的下标就为 n-1。 如下:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
在C语言中提供了一种的操作符 —— [] ,这个运算符就做下标引用操作符。
有了这个下标引用操作符,我们就可以随心所欲的访问数组里面的内容了,比如:我们访问下标为6的元素,我们就可以写上arr[6]这个语句,想要访问下标元素为2的元素,就可以使用arr[2]。 就如下面这个代码:
#include<stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
printf("%d\n", arr[6]); //打印结果:7
printf("%d\n", arr[2]); //打印结果:3
return 0;
}
我们在上面访问数组中的一个元素。那如果我们想访问数组里面的所有元素,该怎么办? 答案也不难想,我们只需要它生成数组元素所有的下标的数值即可。那我们可以使用for循环产生0~9的下标,接下来使用下标访问就行了。 如下代码:
#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++)//这步就可以生成0~9之间的数字
{
printf("%d ",arr[i]);
}
return 0;
}
有了前⾯的知识,我们其实使⽤数组基本没有什么障碍了。但是如果我们要深⼊了解数组,我们最好能了解⼀下数组在内存中的存储。
相信通过上述的例子,读者们已经清楚的了解到了一维数组在内存中的存储方式了。其实,不管是一维数组还是多维数组,它们在内存中都是以这种规则为基调进行数据的存储的
在遍历数组这个操作时,我们非常需要知道数组元素的个数。 如果按照下面的方法来写,可能会出现一个弊端:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for(int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
设想一下,如果一个大型的程序,遇到了某些状况,需要更改这个数组元素的大小。之后你就改了,但是可怕的事情发生了,你之前所用的所有遍历数组,乃至给函数传参时,用的都是常量的数组大小(比如上述数组的“10”),这样的话得修改的猴年马月啊!所以这种写法存在一定的弊端。
那么我们该如何解决这个问题呢? 那就得请出本知识点的主角“sizeof”操作符。
sizeof操作符是C语言的一个关键字,是可以计算类型或者变量的大小的,其实sizeof也可以计算数组的大小。单位是字节。
举个例子(让读者们理解的更加深刻):
这里解释一下,为什么结果会出现40? 其实很简单,这是个整型数组,里面存放着10个整型数据,每个整型数据的大小为4个字节。因此,结果就为10*4 == 40。单位是字节。
由上述的例子,我们受到一些启发,sizeof既可以计算整个数组的大小还可以计算数组里面单个元素的大小。那么我们将这两个相除,不就可以求得数组元素的个数了吗?
下面上代码:
用上述的做法就在改变数组大小的前提上,不需要在其他地方在更改数组元素的大小了。我们直接抛给编译器进行计算。
回顾之前的例子,我们可以这样进行优化:
结果依然能够正确的输出,并且灵活性大大增加。 以后在代码中需要数组元素个数的地方就不用固定写死了,使用上面的计算,不管数组怎么变化,计算出的大小也就随着变化了。
这个就是sizeof运算符的用处之一!希望读者们能够用这种方式进行编写。
在创建变量或者数组的时候,给定一些初始值,被称为初始化。
那二维数组是如何初始化呢?像一维数组一样,也是使用括号进行初始化的。
int arr1[3][5] = {1,2};
int arr2[3][5] = {0};
这里就不再多赘述不完全初始化的细节了,如果有不理解的读者可以看上面一维数组的初始化。
int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
int arr4[3][5] = {{1,2},{3,4},{5,6}};
int arr5[][5] = {1,2,3};
int arr6[][5] = {1,2,3,4,5,6,7};
int arr7[][5] = {{1,2}, {3,4}, {5,6}};
当我们掌握了如何二维数组的创建和初始化后,那我们怎么使用二位数组呢?
其实⼆维数组访问也是使⽤下标的形式的,⼆维数组是有⾏和列的,只要锁定了⾏和列就能唯⼀锁定数组中的⼀个元素。
C语⾔规定,⼆维数组的⾏是从0开始的,列也是从0开始的,如下所⽰:
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
图中的最左侧的数字表示行号,第一行的数字表示列号,都是从0开始的。 比如:我们说第3行,第1列,就能快速定位出3。
#include<stdio.h>
int main()
{
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
printf("%d\n", arr[4][0]);
return 0;
}
访问二维数组的单个元素我们已经知道了,那如何访问整个二维数组呢?
其实我们只需要按照一定的规律生成我们所需的所有的行号和列号就可以了;以上一段代码的arr数组为例,行号的选择范围为0 ~ 2,列号的选择范围为0 ~ 4,所以我们可以借助循环生成我们所需要的所有下标:
#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 //遍历行
//输入
for(i = 0; i < 3; i++) //产生行号
{
int j = 0;//遍历列号
for(j = 0; j < 5; j++) //生成列号
{
printf("%d ", arr[i][j]); //输出数据
}
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;
for(i = 0; i < 3; i++)
{
int j = 0;
for(j = 0; j < 5; j++)
{
printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
}
return 0;
}
从输出的结果来看,每⼀⾏内部的每个元素都是相邻的,地址之间相差4个字节,跨⾏位置处的两个元素(如:arr[0][4]和arr[1][0])之间也是差4个字节,所以⼆维数组中的每个元素都是连续存放的。
了解清楚⼆维数组在内存中的布局,有利于我们后期使⽤指针来访问数组的学习!!!
在本文章中,我给读者们介绍了数组是什么、数组的类型、一维数组和二维数组。
希望这篇文章能够帮助读者们学习C语言。让我们一起进步吧!!!✌️✌️✌️