在实际的程序设计和代码编写中,经常会用到大批同类型的数据,比如某个班学生的成绩等,为方便解决这类问题,C语言提供了数组这一数据结构,这里的数据结构,可理解为数据的存放和管理方式。程序经常使用同类型的数据,比如要处理某个班级的学生成绩信息,如果只有几个学生,我们可以使用几个同类型变量,比如:int mark0, mark1, mark2, mark3, mark4;
这样,便可以存放5个学生的成绩,但如果是几百人几千人呢?肯定不能一直这样写下去,所以,如何合理组织大量同类数据是个问题。
合理组织的含义包括:
(1)为每个数据分配存储空间。
(2)每个数据应当有唯一的标识符进行读写和查找。
在这种应用背景下,数组应用而生,成功地解决了上述问题。
数组是可以在内存中连续存储多个元素的结构
数组是数据类型相同的数据元素的集合。
声明一个数组时,编译器为数组分配内存存储空间,值得注意的是:数组占据的内存空间是连续的,这样,很容易计算数组占据的内存大小和每个元素对应的内存首地址,举例来说,对一个大小为N,类型为short的数组,其占据的内存大小为:
N * sizeof(short)=N * 2
如果说第1个元素在内存中的地址为p,那么第M个元素(M小于N)在内存中的地址可表示为:
p+(M-1) * sizeof(short)
这充分体现了数组的有序性。
按数据类型分类 | 整型数组,字符型数组,指针数组等 |
---|---|
按照维度分类 | 一维数组,二维数组,多维数组 |
一维数组也称向量,是相同数据类型的变量的集合
一维数组声明的基本格式为:类型 数组名[数组元素个数]
① 数组名,与变量名一样,必须遵循标识符命名规则。
② 数组元素个数,必须用方括号括起来,不能是圆括号,必须是常量。
③ 数组的下标是元素相对于数组起始地址的偏移量,所以下标从0开始编号。
④ 根据上面一点得出,
数 组 的 最 大 下 标 = = 元 素 个 数 − 1 数组的最大下标==元素个数-1 数组的最大下标==元素个数−1
要防止下标越界的错误发生。如果越界,编译器有时并不会报错,但这可能引起程序的崩溃。
#include
int main()
{
int a1 = 1;
int a2 = 2;
int a3 = 3;
//如何定义(产生)一个数组
int arrayInt[3];
arrayInt[0] = 1;
arrayInt[1] = 2;
arrayInt[2] = arrayInt[1] * 3;
//arrayInt[3] 下标越界
float arrayFloat[3];
//arrayFloat[3] = { 1.1,1.3,1.4 };
//printf("%f", arrayFloat[3]);错误的打印
double arrayDouble[3];
char arrayChar[3];
return 0;
}
在数组使用之前一定要对数组进行初始化,当不小心在赋值前便使用了数组元素,这时,因为初始化时内存单元内容的不确定,程序输出的结果往往是不可预料的。
不仅仅是数组,在声明创建一个变量后马上对其初始化是个良好的习惯,能有效减少各种意想不到的错误。
一维数组初始化形式:
类型 数组名[大小]={初始化列表};
注意点 | 代码示例 |
---|---|
若对数组中所有的元素都进行了初始化(即全部初始化),可以不用指定数组的大小,系统将自动根据赋值个数来确定数组的大小 | int x[]={1,2,3,4,5,6}; |
若只对数组中的部分元素赋值(即部分初始化),则系统会自动为其他元素赋值为0 | int x[10]={1,2,3}; |
若只声明数组,而不为数组赋值,则数组中的元素值是不确定的 | int x[10]; |
数组大小只能是常量 | int size=10; int x[size]; 此代码不合法 |
/*
数组的初始化
1.直接在定义的时候初始化
1.1 全部初始化
1.2 局部初始化的问题 默认值数字类都是0 字符为'\0'
2.当数组完全被初始化的时候,数组长度可以省略
3.人为初始化
循环去做,习惯采用for处理数字类的数组,用while循环处理字符类数组
数组长度必须是常量!!!
*/
#include
int main()
{
int arrayInt[3] = { 1,2,3 };
//arrayInt[0]=1;
//arrayInt[1]=2;
//arrayInt[2]=3;
float arrayFloat[3] = { 1.1 }; //默认值数字类都是0
char arrayChar[3] = { 'A' }; //默认为\0
int array[] = { 1,2,3 }; //默认推断数组长度为3
//char fileName[] = "ILoveyou";
int num[3];
for (int i = 0; i < 3; i++)
{
scanf("%d", &num[i]); //一维数组的初始化
}
for (int i = 0; i < 3; i++)
{
printf("%d\t", num[i]);
}
//经典错误!
//int length;
//scanf("%d", &length);
//int arrayL[length];
//下面是几个比较怪异的写法.
int cArray['A']; //int cArray[65];
int arrayNum[68 - 'A']; //int cArray[3];
return 0;
}
字符类数组是数据类型为字符型的数据元素的集合。
#include
int main()
{
//用%c去操作字符数组进行初始化
char cArray[10];
for (int i = 0; i < 10; i++)
{
scanf("%c", &cArray[i]);
}
for (int i = 0; i < 10; i++)
{
putchar(cArray[i]); //打印字符
}
return 0;
}
要记住字符数组和字符串是两码事,虽然打印出来看不出来区别,但是字符串比字符数组多了’\0’
用字符数组存储字符串:
char str[] = "ABC"; //字符串的长度为可见长度+1
char str1[] = { 'A','B','C' }; //字符数组
printf("str1=%s\n", str1); //要用'%s'需str1 ={'A','B','C','\0' }
char str2[] = { 'A','B','C','\0' }; //和str是等效的
//常见错误
//char str3[3] = "ABC";
字符串的用法:
#include
int main()
{
char inputData[20];
//用的是数组首地址
//%s: 从首地址打印到'\0'结束
scanf("%s", inputData); //scanf弊端:不能接收空格
//数组名表示的每一个数组的首地址
//scanf("%s", &inputData[0]);//等效写法
puts(inputData); //puts函数自带换行
printf("可以接受空格的输入:");
setbuf(stdin, NULL); //清空缓冲区
gets_s(inputData, 20); //gets(数组名+数组长度)可以接收空格
puts(inputData);
//格式打印
sprintf(inputData, "%d", 123);
puts(inputData);
return 0;
}
数组对应着一片内存区域,从较高层次上看,数组可以看成是一个特殊的大“变量”,同类型的变量之间可以相互赋值,可以比较大小,可以作运算,那数组可否进行这些操作呢,答案是否,即使是同类型、同样大小的数组,下列操作也是非法的:
(1)用一个已经初始化的数组对另一个数组赋值,即使是元素类型相同,数组大小相同,这样的用法也是不允许的。
(2)对数组进行整体输入输出。
printf和scanf不支持对普通数组进行整体输入输出,必须以元素为单位进行操作,但对字符数组来说,可以通过“%s”进行整体输入或输出,这部分内容将在后面介绍。
(3)数组比较。
(4)数组整体运算。
1.为什么有一维数组?
为了批处理(起名字,存数据,操作数据) 2.了解数组长相? 内存连续+变量有规律 3.如何定义(产生)一个数组? 类型 数组名[数组长度]; 类型:数据类型 注意点:数组长度,不代表数组下标,代表的是数组长度 数组最大的下表:数组长度-1 4.如何去使用数组: 和普通变量一样使用 数组名[数组下表]; 5.数组是多个变量名有规律并且内存连续的变量的集合 所以不能直接操作