目录
1.1一维数组创建:
数组,是一组多个相同类型元素的集合,数组创建方式为:
数组元素类型 数组名称 [数组大小];
例如:
int arr[10];
这句话的意思是创建一个整形数组,大小为10,数组名为arr
那有人可能会想,如果数组大小写成变量,那多方便啊
int s = 10;
int arr[s];
但是,在C99标准之前,[] 中要给一个常量才可以,不能使用变量。在C99标准支持了变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化。
1.2一维数组初始化
既然创建了数组,那我们最好养成一个给数组初始化的好习惯,我们来看一下数组初始化的多种方法。
#include<stdio.h>
int main() {
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
int arr3[] = { 1,2,3,4,5 };
int arr4[10] = { 1,2,3,4,5 };
char arr5[10] = { 'a','b','c','d' };
char arr6[] = { 'a','b','c','d' };
char arr7[] = "abcd";
char arr8[10] = "abcd";
return 0;
}
调用监视窗口我们可以看到
arr1是完全初始化,给所有元素都赋值,arr2里边全都是0,说明这种初始化会使数组中所有元素变成相同的。arr3里边只有5个元素,说明数组在初始化时可以省略[ ]中的数组大小,数组大小会根据你写入数组的元素自行调整。arr4是不完全初始化,我们可以看到除了我们输入的元素,其他元素均为0,并且arr5也是不完全初始化,除了输入的元素也都是0,再看arr6和arr7,我们会发现,arr6里边的元素多了一个‘\0’,而'\0'是字符串结束的标志,也就是说,用%s输出arr6的话会在输出abcd后会输出随机值,arr8里虽然有10个元素,但是用%s输出仍然只会输出abcd,因为'\0'才是字符串结束标志,可以看到,arr8之后元素均为\0,
1.3一维数组的使用
对于数组,[ ] 是下标引用操作符。它其实就数组访问的操作符。
我们来看一段代码:
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[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;
}
其中sz = sizeof(arr) / sizeof(arr[0])是用来计算数组中有多少元素的,我们使用sizeof操作符计算整个数组的大小,用它除以arr[0](即一个数组元素的大小),即可得到数组里有多少个元素。
我们可以看到在上面的代码里,我们使用[ ]来访问数组元素,访问数组元素,我们使用的叫做下标,要注意:数组的下标是从0开始的。
1.4一维数组在内存中的存储
接下来我们来看看一维数组在内存中究竟是如何存储的
#include <stdio.h>
int main()
{
int arr[10] = {0};
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;
}
我们使用%p打印每个数组元素的地址,我们可以看到:
arr[0]到arr[1],地址从90变到了94,之后也都是每次跳过四个字节(地址显示为16进制数字),随着数组下标的增加,数组元素的地址也在增加,我们可以画出地址在内存中的大概图为:
其中每个小方格是四个字节,可以存放一个int类型的值,其他类型数组根据自身数据类型不同,结构也不同,比如char数组每个小方格是一个字节,存放一个字符等等。
我们再看一段代码
#include <stdio.h>
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = &arr[0];
for (i = 0; i < sz; ++i)
{
printf("%p --------- %p\n",&arr[i],(p+i));
}
for (i = 0; i < sz; ++i)
{
printf("%d --------- %d\n", arr[i], *(p + i));
}
return 0;
}
我们使用int* p =arr[0]获得数组首元素的地址,根据上边的知识,int数组每次跳过4个字节,所以p+1里的1其实跳过了四个字节,我们可以清楚的看到,这样打印出的地址和&arr[i]是一样的,同时也可以使用*(p+i)的方式来访问数组里的元素。
2.1二维数组的创建
二维数组的创建和一维数组没什么区别,我们来看一下
int arr1[3][4];
char arr2[3][5];
double arr3[2][4];
arr1是一个int类型的二维数组,它有三行四列,arr2是一个char类型的二维数组,它有三行五列,arr3是一个double类型的二维数组,它有两行四列,我们可以把他们认为是一个矩阵,行和列也都是从0开始。
2.2二维数组的初始化
我们再看一下二维数组的初始化,这个和一维数组稍微有点不同
#include <stdio.h>
int main() {
int arr1[3][4] = { 1,2,3,4 };
int arr2[3][4] = { {1,2},{4,5} };
int arr3[][4] = { {2,3},{4,5} };
int arr4[][2] = { 1,2,3,4,5,6,7,8,9 };
return 0;
}
我们可以看到,arr1里分为了三组,第一组里有4个元素:1,2,3,4,其他元素都默认为0,arr2我们看到,它的第一组元素里有1,2,第二组元素里4,5,同样其他元素默认为0,arr3被分为两组,我们注意到,arr3的第一个[ ]里没有写数组的大小,说明二维数组的行号可以省略,但是列号不能省略,行号会根据你输入的元素进行自动调整,arr4也证实了这个说法,被分为了5组,最后一组元素的9之后也是默认为0。
2.3二维数组的使用
#include <stdio.h>
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("%d ", arr[i][j]);
}
}
return 0;
}
我们看到,二维数组的使用和一维数组一样,也是使用下标进行访问 。
2.4二维数组在内存中的存储
#include <stdio.h>
int main()
{
int arr[3][4];
int i = 0;
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;
}
我们发现,二维数组和一维数组一样,在内存里也是连续的,而且,这个二维数组被分成三组,第二组紧跟在第一组后边,第三组也紧跟在第二组后边,我们可以画出二维数组在内存中的存储图大概是
我们可以把二维数组看成多个连续的一维数组。
我们这样想:二维数组名加行号就是一个新的一维数组名,比如arr[1][4],这是一个叫做arr[1]的一维数组,大小为[4]。
#include <stdio.h>
int main()
{
int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
int i = 0;
int* p = &arr[0][0];
for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
{
int j = 0;
for (j = 0; j < sizeof(arr[0]) / sizeof(arr[0][0]); j++)
{
printf("%d ",arr[i][j]);
}
}
printf("\n");
for (i = 0; i < sizeof(arr) / sizeof(arr[0][0]); i++) {
printf("%d ", *(p + i));
}
return 0;
}
同样的,在一维数组里使用的方法,在二维数组里也可以使用,我们用sizeof(arr)/sizeof(arr[0]) 计算二维数组有几行(用整个数组大小除以数组一行的大小),我们用sizeof(arr[0]) / sizeof(arr[0][0])计算数组一行有几个元素(用数组一行的大小除以数组一个元素的大小),我们用sizeof(arr) / sizeof(arr[0][0])来计算整个数组有多少元素(用整个数组大小除以一个元素的大小),可以看到,我们选用*p得到二维数组的首元素地址,也得到了和一维数组一样的效果,打印出了数组的元素,同样也可以打印地址,这里就不举例了。
3.数组越界
数组的下标是有范围限制的。 数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的, 所以我们在写代码时,最好自己做越界的检查。同样的,二维数组的行和列也存在越界问题,要多多注意。
以上就是数组的一些基本知识,如有错误,还请指正。