一维数组
数组是由数据类型相同的一系列元素组成。
一维数组的创建和初始化
数组的创建
type_t arr_name[const_int_n];
float f[100]; // 含有100个float类型元素的数组。
char c[200]; // 含有200个char类型元素的数组。
int i[250]; // 含有250个int类型元素的数组。
type_t
,表示数组内元素的数据类型。arr_name
, 表示数组名。const_int_n
,表示数组大小,必须是整型常量表达式。
变长数组
C99之前的标准前,创建数组时只能在方括号[]
中使用整型常量表达式。注意:sizeof
表达式被视为整型常量,#define
定义的标识符常量也是常量,而const
修饰的常变量在C语言中被视为具有常属性的变量。
在C99中引入了变长数组的概念,允许变量出现在[]
。(前提编译器支持C99)
#define NUM 10
const int a = 1;
int b = 1;
int arr[10]; // 合法
int arr1[5 * 2]; // 合法
int arr2[sizeof(int) * 1]; // 合法
int arr3[NUM]; // 合法
int arr6[-1]; // 不合法,数组大小必须大于0
int arr7[1.5]; // 不合法,数组
int arr4[a]; // C99前不支持
int arr5[b]; // C99前不支持
数组的初始化
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。
int arr[10] = {
1,2,3,4,5,6,7,8,9,10};
float f[3] = {
1.0,2.0,3.0};
// 字符数组初始化的两种方式
char arr2[5] = {
'a','b','c','d'};
char arr3[5] = "abcd"; // 字符串字面量默认尾部添加\0,\0占有位置
...
不完全初始化
当初始化的元素个数小于数组大小时,未被赋值的元素默认初始化为0。
int arr[10] = {
1,2,3}; //不完全初始化
char arr[5] = {
'a','b','c'};
char arr[5] = "abc";
字符数组内赋整型
- 给字符数组内赋值数字整型,如果在ASCII码值范围内,则会被解析成ASCII值对应的字符。
char arr[3] = {
'a',98,'c'};
不指定元素个数
如果在创建数组时,不指定元素个数,则必须初始化,数组的大小由初始化的元素个数决定。
int arr[] = {
1,2,3 };
char arr1[] = {
'a','b','c' };
char arr2[] = "abc"; // 默认添加\0
arr1
和arr2
同样初始化为abc
,但是元素的个数却不相同,从调试结果看出 arr2
默认在末尾添加了一个\0
, 这也是双引号引起的字符串字面量的特点。
从输出结果可以看到,以字符串格式打印两个数组的内容,arr1
数组没有\0
结束标志,所以在打印完abc后会继续打印随机值,直到遇到\0
结束。
再对比strlen()
函数和sizeof
操作符的结果,可以看出sizeof
计算的数组所占空间的大小,初始化为3个元素则占3个byte,而strlen()
计算字符串长度时是以\0
为结束标志,并且不统计\0
。
数组未初始化
如果数组未初始化,直接访问数组获得的值会是内存相应位置上的现有值。(系统不同,输出的结果不同)
int main()
{
int arr[10];
int i = 0;
printf("%2s%14s\n",'i','arr[i]');
for(i = 0;i < 10;i++)
{
printf("%2d%14d\n",i,arr[i]);
}
return 0;
}
上面提到数组属于自动存储类别,指的是这些数组在函数内部声明,且声明时未使用static关键字。
不同的存储类别由不同的属性,对于一些其他存储类别的变量和数组。如果在声明时未初始化、编译器会自动把它们设置未0。
指定初始化器
指定初始化器是C99中新增的一个特性,利用该特性可以指定数组中哪个元素被初始化。
在C99之前,如果只想初始化一个下标非0的元素,必须要将它之前的元素全部初始化。
// 例如初始化下标为2个元素
int arr[5] = {
0,0,3};
而在C99中规定,可以在初始化的{}
中使用带[]
的下标,来指明要初始化数组中的哪个元素。
int arr[5] = {
[2] = 3 };
在使用指定初始化器时还应该注意两点
指定初始化器
之前如果有未初始化的元素,而之后也有元素,那么之后的元素将按照指定初始化器的下标往后继续排列。指定初始化器
可以覆盖前面已经被初始化元素的值。
int main()
{
int arr[10] = {
1,2,[4]=5,6,7,8,9,10,[0]=3};
return 0;
}
从调试信息可以看到,arr[2]
、arr[3]
未初始化,指定初始化器[4]
后面的值,从arr[4]
往后排列,而arr[0]
的指定初始化器[0]
覆盖了。
一维数组的使用
要使用数组中的元素,需要通过[]
下标引用操作符,并在其中指定数组的下标来访问元素,数组的下标从0开始,到数组大小 - 1 结束。
在之前我们简单的学习过指针变量和解引用操作符*
,而其实数组变量和下标引用操作符[]
和它们很相似,数组的变量名是数组第一个元素的地址,而下标引用操作符[]
相当于*(数组名 + 下标)
通过解引用找到对应下标的元素。
int main()
{
int arr[10] = {
1,2,3,4,5,6,7,8,9,10 };
printf("%d %d", arr[0], arr[9]);
return 0;
}
数组元素赋值
- 声明数组后,如果未初始化,可以使用循环遍历数组来给数组中的每个元素赋值。
int main()
{
int arr[10];
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for(i = 0;i<sz;i++)
{
arr[i] = i;
}
return 0;
}
- 而如果想获取数组中每个元素的值也可以通过这种方式。
int main()
{
int arr[10];
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
// 赋值
for (i = 0; i < sz; i++)
{
arr[i] = i;
}
// 获取
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]); // 将循环变量作为数组的下标
}
return 0;
}
- 字符数组可以使用
%s
以字符串格式打印数组。
int main()
{
char arr[] = "abcdefg";
printf("%s\n",arr);
return 0;
}
注意:C语言中不允许把数组作为一个单元赋给另外一个数组,初始化以外也不允许使用花括号{}
的形式来赋值。
int main()
{
int arr1[5] = {
1,2,3,4,5</