数组概述
数组是构造数据类型之一,是具有一定顺序关系的若干个变量的集合。数组中各元素的数据类型要求相同,数组可以是一维的,也可以是多维的。
一维数组
注意:数组名是地址常量!!!注意是常量!!不能被修改!!
用代码进行测试:
#include<stdio.h>
int main(){
int i;
int a[6] = {1,2,3,4,5,6};
printf("该数组内存空间为%d\n",sizeof(a));//输出为24
printf("该数组的起始地址为%p\n",a);//应该注意到这里没有加取地址符,数组名本身就代表了地址
for(i=0;i<=5;i++){
printf("数组第%d个数为:%d\t",i+1,a[i]);
printf("数组元素地址为:%p\n",&a[i]);//这里就要加取地址符,因为不是数组名
}
return 0;
}
输出结果为:
该数组内存空间为24
该数组的起始地址为0xbfd0cb98
数组第1个数为:1 数组元素地址为:0xbfd0cb98
数组第2个数为:2 数组元素地址为:0xbfd0cb9c
数组第3个数为:3 数组元素地址为:0xbfd0cba0
数组第4个数为:4 数组元素地址为:0xbfd0cba4
数组第5个数为:5 数组元素地址为:0xbfd0cba8
数组第6个数为:6 数组元素地址为:0xbfd0cbac
要注意到:数组名本身就是地址,在输出数组首地址时,直接用数组名即可,不用再加取地址符号了~但只要不是求首地址,而是其它元素的地址,那么一定要加取地址符号&
一维数组的初始化
初始化方式:在定义数组时,为数组元素赋初值
int a[5] = {1,2,3,4,5};
说明:
1、数组不初始化,其元素值为随机数
2、对static数组元素不赋初值,系统会自动赋以0值
3、只给部分数组元素赋初值,那么剩余的元素会自动赋0值
注意事项
1、C语言对数组不作越界检查,使用时要注意:
int a[5]; a[5]=10; 这段代码并不会报错
2、关于用变量进行数组维数定义:
int i = 5; int a[i];
3、数组只能通过元素来访问,不能一次引用整个数组
如何求数组元素个数?
假设数组元素个数为n,即数组维数为n,那么
n = sizeof(数组名) / sizeof(数组类型)
因为 ↑是总内存,总长度 ↑是单个元素内存,单个长度
二维数组
例如 int a[3][4],float b[2][5]都是二维数组。
存放顺序:由于内存是一维的,但是仍要把二维数组放到一维的内存当中,这个时候只要按行序优先的原则存储即可。
比如:
int a[3][2]
0 a[0][0]
1 a[0][1]
2 a[1][0]
3 a[1][1]
4 a[2][0]
5 a[2][1]
深入理解:
由于二维数组就是一行一行存储的,所以完全可以把int a[3][2]的二维数组看成是三个一维数组:
三种赋初值实例:
#include<stdio.h>
int main(){
//三种方式给数组赋初值
int a[3][2] = {{1,2},{5,6},{9,10}};
int b[3][2];
int c[3][3];
int i,j;
int value = 1;
for(i=0;i<3;i++){
for(j=0;j<2;j++){
b[i][j] = 1;
}
}
for(i=0;i<3;i++){
for(j=0;j<3;j++){
c[i][j] = value++;
}
}
printf("数组a为:\n");
for(i=0;i<3;i++){
for(j=0;j<2;j++){
printf("%d ",a[i][j]);
}
}
printf("\n数组b为:\n");
for(i=0;i<3;i++){
for(j=0;j<2;j++){
printf("%d ",b[i][j]);
}
}
printf("\n数组c为 :\n");
for(i=0;i<3;i++){
for(j=0;j<3;j++){
printf("%d ",c[i][j]);
}
}
return 0;
}
输出结果为:
数组a为:
1 2 5 6 9 10
数组b为:
1 1 1 1 1 1
数组c为 :
1 2 3 4 5 6 7 8 9
当然了,在赋初始值的时候完全可以缺省一些数据
比如:
但是,二维数组在定义时只能缺省行值,不能缺省列值。
例如,使用C语言定义一个二维数组可以这样写:
int array[][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
这里省略了行数,因为编译器可以根据初始化的值自动推断出数组的行数为3。
然而,二维数组的列数在定义时必须明确指定。这是因为在内存中,二维数组的每一行是连续存储的,而列数确定了每一行的存储长度,所以在定义时必须指定列数,编译器才能正确分配内存空间。
因此,省略列数是不可以的,因为编译器无法确定每一行的长度。你可以理解为省略列数会导致数组的行长度无法确定,从而导致内存分配问题。
如果在定义时只用一个花括号呢?即int a[2][2] = {1,2}这种,那么就会从上到下,从左到右依次填充,剩下的补0。如图所示。
测试二维数组内存地址连续性
printf("\n数组a的元素地址分别为:");
for(i=0;i<3;i++){
for(j=0;j<2;j++){
printf("%p\t",&a[i][j]);
}
printf("\n");
}
printf("\n数组c的元素地址分别为:");
for(i=0;i<3;i++){
for(j=0;j<3;j++){
printf("%p\t",&c[i][j]);
}
printf("\n");
}
输出结果为:
数组a的元素地址分别为:0xbfd949ac 0xbfd949b0
0xbfd949b4 0xbfd949b8
0xbfd949bc 0xbfd949c0
数组c的元素地址分别为:0xbfd949dc 0xbfd949e0 0xbfd949e4
0xbfd949e8 0xbfd949ec 0xbfd949f0
0xbfd949f4 0xbfd949f8 0xbfd949fc
我们可以发现数组元素地址确实是一维连续的
测试二维数组名的作用以及是否可以拆分为一维数组
printf("输出a的地址:%p\n",&a);
printf("输出a[0]的地址:%p\n",&a[0]);
printf("输出a[1]的地址:%p\n",&a[1]);
printf("输出a[2]的地址:%p\n",&a[2]);
输出结果:
输出a的地址:0xbfbe55ac
输出a[0]的地址:0xbfbe55ac
输出a[1]的地址:0xbfbe55b4
输出a[2]的地址:0xbfbe55bc
对照上面a数组的地址:
数组a的元素地址分别为:0xbfbe55ac 0xbfbe55b0
0xbfbe55b4 0xbfbe55b8
0xbfbe55bc 0xbfbe55c0
我们可以发现二维数组名依然表示数组的起始地址,而且可以拆分为一维数组使用
测试二维数组所占内存空间
这里以int a[3][2]为例:
printf("数组a占用的内存总空间为:%d\n",sizeof(a));
printf("a[0]占用的内存空间为:%d\n",sizeof(a[0]));
输出结果为:
数组a占用的内存总空间为:24
a[0]占用的内存空间为:8
说明二维数组看作一维数组的数组名确实是可以当作正常数组名来用的,后续可能会以这个为基础来使用指针操作数组
多维数组
具有两个或两个以上下标的数组是多维数组