引言
当需要储存一组相同类型的数据的时候,为他们一一创建变量是比较麻烦的,这时我们就可以使用数组来储存。
数组分为一维数组和多维数组,其中多维数组最常见的是二维数组。
一维数组
声明
type_t arr_name[const_n];
type_t 是数组中元素的类型,例如:int double char
arr_name 是数组名,数组名是数组首元素的地址(有两个例外)
const_n 是数组元素的个数。且必须是常量
- 样例:
int arr[5];
int 类型,数组名是 arr,数组元素个数是5的数组。
double A[7];
double 类型,数组名是 A,数组元素个数是7的数组。
char str[9];
char 类型,数组名是 str,数组元素个数是9的数组。
初始化
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。
- 完全初始化
数组中的所有数值全部进行初始化
int arr[5] = { 1,2,3,4,5 };
char str[3]={ 'a','b','c' };
char str[3]={ 'a',98,'c' };
char 类型的数据是以ASCII值的形式存储的 - 不完全初始化
对于初始化数组时只有部分内容被初始化,编译器会将剩余部分全部初始化成0。char类型的0是以\0的形式存储。
int arr[10] = { 1,2,3 };
char str[10] = { 'a','b','c' };
- 不指定数组元素个数的数组初始化
当数组没有明确给出大小时,编译器会根据初始化值的个数自动设定大小。
int arr[] = { 1,2,3,4 };
char arr[] = "abc";
特殊情况
arr1 和 arr2 在内存上的区别:
char arr1[] = "abc";
char arr2[3] = {'a','b','c'};
我们通过编译器的监视窗口可以显示两个数组的区别
从监视结果上看:
arr1 比 arr2 多开了一个 char 类型的空间,用来存放 \0。
常见初始化错误
int arr[3] = { 1,2,3,4 };
当初始化数值超过数组元素个数时,系统会发生错误。
int arr[3]; arr = { 1,2,3 };
不能通过赋值语句数组进行初始化。
大小
在使用数组时,经常需要计算数组元素的数目,我们可以通过关键字 sizeof 实现。具体代码如下:
int main()
{
int arr[] = { 1,2,3,4,5 };
int sz = sizeof(arr)/aizeof(arr[0]);
printf("%d\n",sz);
return 0;
}
sizeof 的作用是计算内容所占字节的大小,我们只需求出数组所占总字节大小除以数组中一个元素所占的字节大小就可以计算出数组中元素的数目。
sizeof(数组名),可以计算整个数组的大小,这里的数组名表示整个数组。
使用(下标访问)
数组是可以随意访问内部的各个元素的,访问时只需要使用下标引用操作符:[ ]即可。数组的下标是从 0 开始的,也就是第一个元素的下标是 0,第二个元素的下标是 1,以此类推。
遍历数组:
int main()
{
int arr[5] = { 1,2,3,4,5 };
int i = 0;
int sz = sizeof(arr) / aizeof(arr[0]);
for(i = 0;i < sz;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
存储
我们可以打印数组每个元素的地址来确定数组中元素的储存方式
代码如下:
int main()
{
int arr[5] = { 1,2,3,4,5 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; ++i)
{
printf("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
若&数组名,取出的是整个数组的地址,数组名表示整个数组
运行结果如下:
根据运行结果我们可以看出,数组中相邻数值之间的差值都是一个 int 的大小,四个字节,这证明数组中的元素在内存中是按照顺序连续存储的。
图示如下:
二维数组
声明
type_t arr_name[const_ROW][const_COL];
type_t 是数组中元素的类型,例如:int double char
arr_name 是数组名,数组名是数组首元素的地址(有两个例外)
const_ROW 是数组元素的行个数。且必须是常量
const_COL 是数组元素的列个数。且必须是常量
- 样例:
int arr[3][4];
int 类型,数组名是 arr,数组行是3,列是4的数组。
double A[5][7];
double 类型,数组名是 A,数组行是5,列是7的数组。
char str[4][3];
char 类型,数组名是 str,数组行是4,列是3的数组。
初始化
- 直接初始化
数组中的数值按照顺序进行进行初始化
int arr[3][4] = {1,2,3,4};
- 用 { } 分割行进行初始化
{ } 用来分割行,{ } 里面的第一个 { } 的元素是第 0 行的元素,第二个 { } 的元素是第 1 行的元素,以此类推。
int arr[3][4] = {{1,2},{4,5}};
- 不指定数组行数的数组初始化
当数组没有明确给出行数大小时,编译器会根据初始化值的个数自动设定行的大小。
数组的行可以不明确给出,但是列的大小必须明确给出。
int arr[][4] = {{2,3},{4,5}};
若没有完全初始化,剩余部分编译器自动初始化为0。
大小
计算方法与一维数组相同:
一维数组大小计算方法
使用
二位数组访问数组中的元素也是通过下标进行访问。
数组的遍历:
int main()
{
int arr[3][4] = { 0 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
arr[i][j] = i * 4 + j;
}
}
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("%2d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
存储
我们可以打印数组每个元素的地址来确定数组中元素的储存方式
代码如下:
int main()
{
int arr[3][4] = { 0 };
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
arr[i][j] = i * 4 + j;
}
}
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("&arr[%d][%d] = %p\n", i,j,&arr[i][j]);
}
}
return 0;
}
若&数组名,取出的是整个数组的地址,数组名表示整个数组
运行结果如下:
根据运行结果我们可以看出,数组中相邻数值之间的差值都是一个 int 的大小,四个字节,这证明数组中的元素在内存中是按照先存储满一行,再存储下一行的形式存储的。
图示如下: