C语言学习笔记——数组

一、数组的作用

当我们需要定义多个数据的时候

例如:

需要1000个char 型的变量,若使用基本的数据类型,会十分的繁琐!

如:char a1,a2.........a1000;//需要定义从a1 到 a1000 , 1000个变量!

若是使用数组,仅需

char a[1000];

便可以解决问题

  • 数组:
  • 一组具有 相同数据类型 的(有序)的数据集合

二、数组的定义

  • 数组的定义一般形式:
  • 数据类型  数组名 [整形表达式]
  • 例如:char a [1000];
  •  
  • 数据类型:表示数组所存储数据的基本类型
  • 数组名:与变量名字的定义规则相同,只能使用 字母、数字、下划线,变量开头只能使用字母或者下划线
  • 整形表达式:需要 元素的个数

三、一维数组在内存中的分配

数组是一组具有相同数据类型的(有序)的数据集合

当我们定义了一个数组,就在内存中开辟了一块连续的空间用于存储某一类数据类型的数据

  • 例1:
  • char a[5]; 与 int a[5];
  • 在内存空间的情况,如图所示:

查看数组开辟的内存空间地址如下:

扫描二维码关注公众号,回复: 4882937 查看本文章
#include<stdio.h>
void main()
{
	//char a[5];
	int a[5];

	//char型 int型 数组在内存中的地址
	int i;
	for(i=0;i<5;i++)
	{
		printf("a[%d]的地址 = %p\n",i,&a[i]);
	}
}

输出如图所示:(左char a[5]; 右int a[5];)

四、数组的初始化

由上面数组在内存中的分配,可以得知,当一个数组定义好了之后,系统要对应划分一块连续的内存空间。

因此,不论如何元素个数都是要确定的,区别只是在于是人为确定好了,还是由系统帮你确定好。

两种初始化方式:

一、确定元素个数

二、缺省元素个数

  • 确定元素个数:
  • 根据元素个数,划分对应的内存
  • 1、定义并且清空数组(数组里面全部清0):
  • char a[100] = {0};
  • int a[100] = {0};
  • 2、定义数组并整体初始化:
  • char a[100] = {'a','b','c','d'};//结尾没有'\0'
  • char a[100] = {"abcd"};//结尾有'\0',作为字符串的结尾
  • char a[100] = "abcd";
  • int a[100] = {1,2,3,4,5,6};//前面6个数据赋值
  • 3、对单独某个元素初始化:
  • char a[100] ; a[0] = 1;
  • int a[100] ; a[0] = 1;
  • 缺省元素个数:
  • 1、根据存储数据的个数,由系统来确定元素的个数,划分对应的内存。
  • char a[] = {'a','b','c','d'};//相当于划分4个char型的内存空间
  • int a[] = {1,2,3,4,5,6,7,8,9};//相当于划分9个int型的内存空间
  • 例1:
  • 确定元素个数 与 缺省元素个数 划分的内存对比
  • 如:int a[100] = {1,2,3,4,5,6,7,8,9}; 与 int b[] = {1,2,3,4,5,6,7,8,9};
  • 代码如下:
#include<stdio.h>
void main()
{
	//确定元素个数
	int a[100] = {1,2,3,4,5,6,7,8,9};

	//缺省元素个数
	int b[] = {1,2,3,4,5,6,7,8,9};

	printf("sizeof(a) = %d,共有%d 个int型数据\n", sizeof(a), sizeof(a)/sizeof(int));
	printf("sizeof(b) = %d,共有%d 个int型数据\n", sizeof(b), sizeof(b)/sizeof(int));
}

输出结果,如图所示:(数组 a 为确定元素个数,数组 b 为缺省元素个数)

  • 例2:
  • 在打印时候,使用 %s  格式打印或者使用strlen()函数的时候,在遇到'\0'的时候结束
  • 在第4个元素中,赋值为'\0'
  • 测试代码如下:
#include<stdio.h>
#include<string.h>
void main()
{
	//定义一个char 型数组
	char a[10] = {'a','b','c','d','e','f','g'};
	//将第4个元素替换成'\0'
	a[3] = '\0';

	printf("%s\n",a);
	printf("strlen(a) = %d\n",strlen(a));
}
	

输出结果,如图所示:

五、数组中数据的取用

储存在数组中的数据,一般有两种取用方法:

一、使用下标取数据

二、使用*(引用符,取数据符)获取数据

  • 使用下标:
  • 如:
  • char a[10] = {'a','b','c','d'};
  • printf("a[2] = %c",    a[2]);
  •  
  • 使用*(引用符,取数据符):
  • 如:
  • char a[10] = {'a','b','c','d'};
  • printf("a[2] = %c",   *(a+2));
  •  
  • 两种方式相对比:使用下标的方式较为直观,更建议使用。

六、二维数组

在计算机中,二维数组的空间地址也是连续的。

不管是二维,三维,还是N维计算机只是当做一堆内存在处理

  • 二维数组的定义与初始化:
  • 定义:
  • 与一维数组相同
  • int a[2][2];
  •  
  • 初始化:
  • 一、确定元素个数:
  • 1、给二维数组整体赋值:
  • int a[3][3] = {{1,2,3} , {4,5,6} , {7,8,9}};
  • 2、让系统自动填充数据:(根据地址连续的特性)
  • int a[3][3] = {1,2,3,4,5,6,7,8,9};//可拆分为      a[3]   、 int [3]
  • 3、缺失的整体赋值:
  • int a[3][3] = {{1,2} ,{5} , {9}};//没有被赋值的元素,系统默认填充0 ->   int a[3][3] = {{1,2,0} ,{5,0,0} , {9,0,0}};
  • int a[3][3] = {1,2,3,4};//根据地址连续的特性,前面的会先赋值,后面没有赋值的元素,系统默认填充0
  • =>   int a[3][3] = {1,2,3,4,0,0,0,0,0,0};
  • 二、缺省元素个数:
  • 1、根据定义“列数”以及“数组内总的数据”来进行分组,并且划分对应内存:
  • int a[][3] = {1,2,3,4,5,6,7,8,9};//相当于一个 int a[3][3] = {{1,2,3} , {4,5,6} , {7,8,9}};
  • int a[][3] = {1,2,3,4};//相当于一个 int a[2][3] = {{1,2,3} , {4,0,0}};
  • 例1:
  • int a[2][2]; 相当于 int a[4];
  • 在内存空间中的分配情况,如图所示:

  • 例2:
  • 计算机只是将 数组 当做一堆 内存 处理的直接证明
  • 用一个char 型的数组 来表示一个 int 型的数据。
  • 如: 定义 char a[4];  用char a[4] 来表示 一个 int b = 65535;  代码如下:
#include<stdio.h>
void main()
{	
	//int 型 数据
	int b = 65535;
	//char 型 数组
	unsigned char a[4];//char 型 数组

	//以8位二进制位一个存储单元
	//即一个地址的存储空间为1个字节
	//1个int 型数据占4个字节
	//1个char 型数据占1个字节
	a[0] =  0xff;
	a[1] =  0xff;
	a[2] =  0x00;
	a[3] =  0x00;

	//将a 的指针类型强制转化成 int型,再取值
	printf("char a[4] = %d\n",*((int *)a) );
}

输出结果,如图所示:

  • 例3:
  • 数组的空间地址是连续的证明,以及计算机只是将数组当做一堆内存处理的间接证明
  • 如:
  • int a[2][2] = {1,2,3,4};  // 此时 a[1][1] = 4;
  • 如果访问 a[0][3] 呢?
  • 此时为“越界访问”,若是没有超过系统给数组划分的空间还好,若是超出了划分的空间,则十分的危险!
#include<stdio.h>
void main()
{	
	int a[2][2] = {1,2,3,4};

	printf("a[1][0] = %d\n",a[1][0]);//第三个元素
	printf("a[0][2] = %d\n",a[0][2]);
	printf("a[1][1] = %d\n",a[1][1]);//第四个元素
	printf("a[0][3] = %d\n",a[0][3]);
}

输出结果,如图所示:

可以发现,a[1][0] 与 a[0][2] 输出的结果相同, a[1][1] 与a[0][3] 输出的结果相同

七、数组的一些注意事项

  • 一维数组:
  • 1​​​​​、地址的几个表达方式: 
  • 如:char a[100];
  • 首地址:a  == &a[0]
  • 地址:a+1  == &a[1]
  • 2、取用数组中的元素,用[ ]数组下标,或者使用*(引用符)
  • 如:char a[100];
  • 元素:a[10]  、*(a+10)
  •  
  • 二维数组:
  • 1、地址的几个表达方式:
  • 如:char a[2][2];
  • 首地址:a  == a[0]  == &a[0][0]
  • 地址:a+1 == a[1] == a[0]+1 == &a[1][0]
  •  
  • 可以这么理解:
  • 如:char a[2][2] 相当于 a[2] (数据的分组),char [2] (数据类型的个数) 组合在一起 
  • 其中 a[0] 对应 2个char 型数据 ,a[1] 也对应 2个char型数据
  • 而a 又相当于 数组的首地址,所以a+1 , 相当于由 a[0] 组偏移到 a[1]  组
  • 其中a[0] 组中,又包含了2个char 型数据,所以 相当于偏移了2个char 型数据的地址。
  • 下面的例子会详细解释。
  •  
  • 注意:如 int a[3][] = {1,2,3,4,5,6,7,8,9}; 是错误的,因为没有类型系统是不会分配的。
  • 可以如此看: a[3]  , int [ ] //没有数据类型或者说没有数据类型的个数。
  • 例1:
  • 二维数组的地址表达方式,以及地址的偏移量。
  • 代码如下:
#include<stdio.h>
void main()
{	
	//定义二维数组
	char a[2][2];
	int b[2][2];

	//打印地址:
	printf("a = %p ,   a[0] = %p , &a[0][0] = %p \n",a,a[0],&a[0][0]);
	printf("a+1 = %p , a[1] = %p , &a[1][0] = %p \n",a+1,a[1],&a[1][0]);
	printf("========================================================\n");
	printf("b = %p ,   b[0] = %p , &b[0][0] = %p \n",b,b[0],&b[0][0]);
	printf("b+1 = %p , b[1] = %p , &b[1][0] = %p \n",b+1,b[1],&b[1][0]);
}

输出结果,如图所示:

  • 可以发现:
  • a     == a[0]  ==  &a[0][0]
  • a+1 == a[1]  ==  &a[1][0]
  • b     == b[0]  ==  &b[0][0]
  • b+1 == b[1]  ==  &b[1][0]
  • 而且,对应不同数据类型的数组,地址的偏移量为 定义数据类型的个数  * 对应数据类型所占的字节数

猜你喜欢

转载自blog.csdn.net/laifengyuan1/article/details/86172669