一、数组的作用
当我们需要定义多个数据的时候
例如:
需要1000个char 型的变量,若使用基本的数据类型,会十分的繁琐!
如:char a1,a2.........a1000;//需要定义从a1 到 a1000 , 1000个变量!
若是使用数组,仅需
char a[1000];
便可以解决问题
- 数组:
- 一组具有 相同数据类型 的(有序)的数据集合
二、数组的定义
- 数组的定义一般形式:
- 数据类型 数组名 [整形表达式]
- 例如:char a [1000];
- 数据类型:表示数组所存储数据的基本类型
- 数组名:与变量名字的定义规则相同,只能使用 字母、数字、下划线,变量开头只能使用字母或者下划线
- 整形表达式:需要 元素的个数
三、一维数组在内存中的分配
数组是一组具有相同数据类型的(有序)的数据集合
当我们定义了一个数组,就在内存中开辟了一块连续的空间用于存储某一类数据类型的数据
- 例1:
- char a[5]; 与 int a[5];
- 在内存空间的情况,如图所示:
查看数组开辟的内存空间地址如下:
#include<stdio.h>
void main()
{
//char a[5];
int a[5];
//char型 int型 数组在内存中的地址
int i;
for(i=0;i<5;i++)
{
printf("a[%d]的地址 = %p\n",i,&a[i]);
}
}
输出如图所示:(左char a[5]; 右int a[5];)
四、数组的初始化
由上面数组在内存中的分配,可以得知,当一个数组定义好了之后,系统要对应划分一块连续的内存空间。
因此,不论如何元素个数都是要确定的,区别只是在于是人为确定好了,还是由系统帮你确定好。
两种初始化方式:
一、确定元素个数
二、缺省元素个数
- 确定元素个数:
- 根据元素个数,划分对应的内存
- 1、定义并且清空数组(数组里面全部清0):
- char a[100] = {0};
- int a[100] = {0};
- 2、定义数组并整体初始化:
- char a[100] = {'a','b','c','d'};//结尾没有'\0'
- char a[100] = {"abcd"};//结尾有'\0',作为字符串的结尾
- char a[100] = "abcd";
- int a[100] = {1,2,3,4,5,6};//前面6个数据赋值
- 3、对单独某个元素初始化:
- char a[100] ; a[0] = 1;
- int a[100] ; a[0] = 1;
- 缺省元素个数:
- 1、根据存储数据的个数,由系统来确定元素的个数,划分对应的内存。
- char a[] = {'a','b','c','d'};//相当于划分4个char型的内存空间
- int a[] = {1,2,3,4,5,6,7,8,9};//相当于划分9个int型的内存空间
- 例1:
- 确定元素个数 与 缺省元素个数 划分的内存对比
- 如:int a[100] = {1,2,3,4,5,6,7,8,9}; 与 int b[] = {1,2,3,4,5,6,7,8,9};
- 代码如下:
#include<stdio.h>
void main()
{
//确定元素个数
int a[100] = {1,2,3,4,5,6,7,8,9};
//缺省元素个数
int b[] = {1,2,3,4,5,6,7,8,9};
printf("sizeof(a) = %d,共有%d 个int型数据\n", sizeof(a), sizeof(a)/sizeof(int));
printf("sizeof(b) = %d,共有%d 个int型数据\n", sizeof(b), sizeof(b)/sizeof(int));
}
输出结果,如图所示:(数组 a 为确定元素个数,数组 b 为缺省元素个数)
- 例2:
- 在打印时候,使用 %s 格式打印或者使用strlen()函数的时候,在遇到'\0'的时候结束
- 在第4个元素中,赋值为'\0'
- 测试代码如下:
#include<stdio.h>
#include<string.h>
void main()
{
//定义一个char 型数组
char a[10] = {'a','b','c','d','e','f','g'};
//将第4个元素替换成'\0'
a[3] = '\0';
printf("%s\n",a);
printf("strlen(a) = %d\n",strlen(a));
}
输出结果,如图所示:
五、数组中数据的取用
储存在数组中的数据,一般有两种取用方法:
一、使用下标取数据
二、使用*(引用符,取数据符)获取数据
- 使用下标:
- 如:
- char a[10] = {'a','b','c','d'};
- printf("a[2] = %c", a[2]);
- 使用*(引用符,取数据符):
- 如:
- char a[10] = {'a','b','c','d'};
- printf("a[2] = %c", *(a+2));
- 两种方式相对比:使用下标的方式较为直观,更建议使用。
六、二维数组
在计算机中,二维数组的空间地址也是连续的。
不管是二维,三维,还是N维计算机只是当做一堆内存在处理
- 二维数组的定义与初始化:
- 定义:
- 与一维数组相同
- int a[2][2];
- 初始化:
- 一、确定元素个数:
- 1、给二维数组整体赋值:
- int a[3][3] = {{1,2,3} , {4,5,6} , {7,8,9}};
- 2、让系统自动填充数据:(根据地址连续的特性)
- int a[3][3] = {1,2,3,4,5,6,7,8,9};//可拆分为 a[3] 、 int [3]
- 3、缺失的整体赋值:
- int a[3][3] = {{1,2} ,{5} , {9}};//没有被赋值的元素,系统默认填充0 -> int a[3][3] = {{1,2,0} ,{5,0,0} , {9,0,0}};
- int a[3][3] = {1,2,3,4};//根据地址连续的特性,前面的会先赋值,后面没有赋值的元素,系统默认填充0
- => int a[3][3] = {1,2,3,4,0,0,0,0,0,0};
- 二、缺省元素个数:
- 1、根据定义“列数”以及“数组内总的数据”来进行分组,并且划分对应内存:
- int a[][3] = {1,2,3,4,5,6,7,8,9};//相当于一个 int a[3][3] = {{1,2,3} , {4,5,6} , {7,8,9}};
- int a[][3] = {1,2,3,4};//相当于一个 int a[2][3] = {{1,2,3} , {4,0,0}};
- 例1:
- int a[2][2]; 相当于 int a[4];
- 在内存空间中的分配情况,如图所示:
- 例2:
- 计算机只是将 数组 当做一堆 内存 处理的直接证明
- 用一个char 型的数组 来表示一个 int 型的数据。
- 如: 定义 char a[4]; 用char a[4] 来表示 一个 int b = 65535; 代码如下:
#include<stdio.h>
void main()
{
//int 型 数据
int b = 65535;
//char 型 数组
unsigned char a[4];//char 型 数组
//以8位二进制位一个存储单元
//即一个地址的存储空间为1个字节
//1个int 型数据占4个字节
//1个char 型数据占1个字节
a[0] = 0xff;
a[1] = 0xff;
a[2] = 0x00;
a[3] = 0x00;
//将a 的指针类型强制转化成 int型,再取值
printf("char a[4] = %d\n",*((int *)a) );
}
输出结果,如图所示:
- 例3:
- 数组的空间地址是连续的证明,以及计算机只是将数组当做一堆内存处理的间接证明
- 如:
- int a[2][2] = {1,2,3,4}; // 此时 a[1][1] = 4;
- 如果访问 a[0][3] 呢?
- 此时为“越界访问”,若是没有超过系统给数组划分的空间还好,若是超出了划分的空间,则十分的危险!
#include<stdio.h>
void main()
{
int a[2][2] = {1,2,3,4};
printf("a[1][0] = %d\n",a[1][0]);//第三个元素
printf("a[0][2] = %d\n",a[0][2]);
printf("a[1][1] = %d\n",a[1][1]);//第四个元素
printf("a[0][3] = %d\n",a[0][3]);
}
输出结果,如图所示:
可以发现,a[1][0] 与 a[0][2] 输出的结果相同, a[1][1] 与a[0][3] 输出的结果相同
七、数组的一些注意事项
- 一维数组:
- 1、地址的几个表达方式:
- 如:char a[100];
- 首地址:a == &a[0]
- 地址:a+1 == &a[1]
- 2、取用数组中的元素,用[ ]数组下标,或者使用*(引用符)
- 如:char a[100];
- 元素:a[10] 、*(a+10)
- 二维数组:
- 1、地址的几个表达方式:
- 如:char a[3]3];
- 首地址:a == a[0] == &a[0][0]
- 地址:a+1 == a[1] == &a[1][0]
- 注意:a[0]+1 == &a[0][1]
- a[1]+1 == &a[1][1]
- 可以这么理解:
- 如:char a[2][2] 相当于 a[2] (数据的分组),char [2] (数据类型的个数) 组合在一起
- 其中 a[0] 对应 2个char 型数据 ,a[1] 也对应 2个char型数据
- 而a 又相当于 数组的首地址,所以a+1 , 相当于由 a[0] 组偏移到 a[1] 组
- 其中a[0] 组中,又包含了2个char 型数据,所以 相当于偏移了2个char 型数据的地址。
- 下面的例子会详细解释。
- 注意:如 int a[3][] = {1,2,3,4,5,6,7,8,9}; 是错误的,因为没有类型系统是不会分配的。
- 可以如此看: a[3] , int [ ] //没有数据类型或者说没有数据类型的个数。
- 例1:
- 二维数组的地址表达方式,以及地址的偏移量。
- 代码如下:
#include<stdio.h>
void main()
{
//定义二维数组
char a[2][2];
int b[2][2];
//打印地址:
printf("a = %p , a[0] = %p , &a[0][0] = %p \n",a,a[0],&a[0][0]);
printf("a+1 = %p , a[1] = %p , &a[1][0] = %p \n",a+1,a[1],&a[1][0]);
printf("========================================================\n");
printf("b = %p , b[0] = %p , &b[0][0] = %p \n",b,b[0],&b[0][0]);
printf("b+1 = %p , b[1] = %p , &b[1][0] = %p \n",b+1,b[1],&b[1][0]);
}
输出结果,如图所示:
- 可以发现:
- a == a[0] == &a[0][0]
- a+1 == a[1] == &a[1][0]
- b == b[0] == &b[0][0]
- b+1 == b[1] == &b[1][0]
- 而且,对应不同数据类型的数组,地址的偏移量为 定义数据类型的个数 * 对应数据类型所占的字节数