c语言-数组-基本知识

目录

1.1一维数组创建:

1.2一维数组初始化

1.3一维数组的使用

1.4一维数组在内存中的存储

2.1二维数组的创建

2.2二维数组的初始化

2.3二维数组的使用

2.4二维数组在内存中的存储

3.数组越界


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语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的, 所以我们在写代码时,最好自己做越界的检查。同样的,二维数组的行和列也存在越界问题,要多多注意。

以上就是数组的一些基本知识,如有错误,还请指正。

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值