一.数组的定义
数组:一组相同元素的集合
type_t arr_name[const_n];
type_t : 数组的元素类型
arr_name : 数组的名称
const_n : 常量表达式,用来指定数组的大小
下面是一个例子:
int main()
{
int arr1[10];
char arr2[10];
float arr3[5];
return 0;
}
这是一个局部的变量,这些局部的变量默认是存放在栈区,默认值是随机的。
二.数组的初始化
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。
完全初始化VS不完全初始化
int main()
{
int arr0[10] = {1,2,3,4,5,6,7,8,9,10};
int arr1[10] = { 1,2,3 };
return 0;
}
观察这个代码,我们可以发现 arr0 和 arr1 初始化的内容不太一样,第一个初始化完完全全填入了10个值,arr1则只填入了几个值,而非全部的值。
这就是完全初始化和不完全初始化。
当我们进行不完全初始化时,剩余未指定的元素默认为0
我们可以通过监视窗口看看它们的值。
数组的大小依据初始化内容来定
数组在创建的时候如果想不指定数组的确定的大小就得初始化。数组的元素个数根据初始化的内容来确定 。
我们可以通过监视窗口看看它们的值。
一个需要区分的点
但是对于下面的代码要区分,内存中如何分配。
int main()
{
char arr4[] = "abc";
char arr5[3] = { 'a','b','c' };
return 0;
}
C语言中的单引号表示字符的字面量
C语言中的双引号表示字符串的字面量
'a'表示字符字面量,在内存中占1个字节,'a'+1表示'a'的ASCII码加1,结果为'b'
"a"表示字符串字面量,在内存中占2个字节,"a"+1表示指针运算,结果指向"a"结束符'\0'
一个需要注意的点
//int count = 10;
//int arr2[count];
//这种写法,在一些编译器中可以实现
//注:数组创建,在C99标准之前,[]中要给一个常量才可以,不能使用变量。
// 在C99标准支持了变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化
三.一维数组的使用
[ ],下标引用操作符。它其实就数组访问的操作符。
数组是利用下标和下标引用操作符进行对数组元素的访问。
如下是一个例子:
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", arr[5]);
return 0;
}
打印数组中的内容。
需要注意的是,arr[i]访问的下标可以为变量,但定义的时候不可以。
int main()
{
int arr[10] = { 0 };//数组的不完全初始化
//计算数组的元素个数
int sz = sizeof(arr) / sizeof(arr[0]);
//对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
int i = 0;//做下标
for (i = 0; i < 10; i++)
{
arr[i] = i;
}
//输出数组的内容
for (i = 0; i < 10; ++i)
{
printf("%d ", arr[i]);
}
return 0;
}
运行的结果:
一个思考点:为什么是int sz = sizeof(arr) / sizeof(arr[0]);
因为一个整型(int)占4个字节,数组里面有10个int,则sizeof(arr)有40个字节,其中一个元素sizeof(arr[0])是4个字节,所以得出数组的元素个数。
另一个思考点:数组在内存中是连续存放的。
我们通过编写代码来观察其是连续存放的
//%p打印地址
int main()
{
int arr[10] = { 1,2,3,4,5 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
我们观察其地址:
这个编码是16进制的,我们可以观察到它的后两位是连续的(一个字节是4个字符,一个字节挨着一个字节)。
我们不仅观察到它是连续的,同时也可以观察得到它是从低地址到高地址的。
四.二维数组的创建
int arr[3][4] = { 0 }
第一个[ ]中的代表的是行,第二个[ ]中代表的是列
二维数组中如果有初始化,行可以省略但列不能省略。
//数组创建
int arr[3][4];
char arr[3][5];
double arr[2][4];
int arr[][4];
五.二维数组初始化
int arr[4][5] = { {1,2,3,4,5},{1,2,3,4,5},{2,3,4,5,6},{0,1,2,3,4} };
int arr[4][5] = { {1,2,3,4,5},{1,2,3},{2,3,4,5},{0} };
int arr[4][5] = { 1,2,3,4,5,6,7,8,9,4,5,6,7,2,3,1,};
我们可以编写代码打印一个看看,如下:
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++)
{
printf("%d ", arr[i][j]);
}
}
return 0;
}
二维数组填满换行,填不满则用0补充。
为什么说行可以没有,列必须有?因为他是按照填满一行换另一行,则其必须要有列。通过每一行列的个数可以判断行的个数。
六.二维数组的使用
二维数组下标的行和列均是从0开始的。
以下是一个例子
int main()
{
int arr[4][5] = { {1,2,3,4,5},{3,4,5,6,7},{2,3,4,5,6},{0,1,2,3,4} };
printf("%d\n", arr[1][4]);
return 0;
}
我们可以看看代码的运行结果。
同时,我们也需要了解,二维数组在内存中也是连续存放的。( 类似如下3*4数组)
也可以这么来看, 二维数组是一个一维数组的数组,把一个一维数组看成一个元素。
七.数组越界
数组的下标是有范围限制的,因此,在使用数组时,要防止数组下标超出边界(要确保下标是有效的值)。
如果数组有n个元素,起始从0开始,最后一个下标为n-1
C语言本身越界编译器不报错,但并不意味着程序是正确的,因为其不会检查数组下标是否使用得当
同时,在C的标准中,使用越界下标的结果是未定义的,这意味着程序看上去可以运行,但是运行结果很奇怪,或者异常终止。
// 数组越界
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i <= 10; i++)
{
//当i等于10的时候,越界访问了
printf("%d\n", arr[i]);
}
return 0;
}
运行结果: