C语言入门学习——数组


数组就是内存中的一组连续的存储空间,用于存储一组连续的数据,是相同类型的集合。

一维数组

一维数组的创建

一维数组的定义:
类型名 变量名[常量表达式 ]
注:数组创建, [ ] 中要给一个常量才可以,不能使用变量

int arr[10];
类型名 变量名[常量表达式]
或者
int n = 10int arr2[n];
第二种要看编译器是否支持

一维数组的初始化

数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值

int arr1[10] = { 0 };
int arr2[10] = {1,2,3};
int arr3[ ]  = {1,2,3,4};
字符数组
char ch1[ ] = {'a','b','c'};
char ch2[5] = {'a','b','c'};
char ch3[ ] = "abc";
char ch4[5] = "abc";

上述是一些初始化的区别

  1. arr1定义了10个元素,但暂时不需要赋值使用,所以先都给0,以免生成随机数造成影响
  2. arr2和arr3是不完全初始化其中:
  3. arr2定义了10个元素但是只给前三个元素赋初始值,剩余的元素全为0
  4. arr3则是根据元素个数,确定数组大小
  5. ch1也是根据初始化赋予元素的个数确定数组的大小
  6. ch2则是赋予了前三个元素,后面自动补\0 即(a,b,c,\0,\0)
  7. ch3也是根据初始化元素的个数确定大小,但不同的是,他会自动在后面生成一个\0结束符,因为这是字符串形式
  8. ch4同ch2,剩余的空位补\0

由上可知:

  1. 数组不完全初始化时,剩余的会补0(\0)
  2. 当没确定元素个数时可以通过赋予的初始值确定
  3. 字符串的形式会自动在后面生成一个结束符,所以定义数组存放字符串时,比须大于元素的个数

一维数组的使用

假如要对数组的所有元素按顺序赋值,那如何引用呢,需要对 [ ] 下标引用操作符进行操作,如:

int arr[10] = { 0 };			
int i;
for(i = 0; i < 10; i++)			
{
	arr[i] = i+1;
}								//10[arr]是等价的

运行后数组值为:1,2,3,4,5,6,7,8,9,10
由此可知,下标是从0开始的,[ ]可以对数组的元素进行访问

int arr1[] = {23,54,56,65,44,33};
sizeof(arr1)/sizeof(arr1[0])
//arr1放的是数组总地址
//arr1[0]放的是数组的首元素地址

当没有确定元素个数时,这个代码可以求出元素的个数(字符串会多一个结束符)

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

那么数组是如何存储的,请看代码

int arr1[10] = {1,2,3,4,5,6,7,8,9,10};
int sz = sizeof(arr1)/sizeof(arr1[0]);
int  *p = &arr1[0];	//把首元素的地址,存到指针p里												
	for(i=0; i<sz; i++)				
	{
		printf("&arr1[%d] = %p <===> %p\n",i,&arr1[i],p+i);			
	}	//每个地址相差4
//p+1:+1加的是单元格,即向后移动1 个位置表示指针变量指向下一个数据元素的首地址
//例如 int型 就是4个字节大小,就指向这4个字节的首地址,具体的地址大小要看原来指针指向的数据类型是什么,char*就是指向char的 int*就是指向int的

输出如下:
在这里插入图片描述
而当把 int *p = &arr1[0] 改为 char *p = &arr1[0]
在这里插入图片描述
可以发现 当指针p的类型变为char,数组地址从4字节的单元格变为了1字节的单元格,所以指针+1加的是单元格,是下一个位置,并不是让存的地址+1

观察输出结果可知
随着数组下标的增长,元素的地址,也在有规律的递增。 由此可以得出结论:数组在内存中是连续存放的,存放的总大小却决于数据类型与元素个数。

二维数组

二维数组的创建

二维数组的定义:

int arr[10][5];
类型名 变量名[常量表达式][常量表达式]

可以理解为10行5列

二维数组的初始化

int arr[3][5] = {1,2,3,4,5,6};
int arr1[3][5] = {{1,2},{3,4},{5,6}};
int arr2[][5] = {1,2,3,4,5,6};
int arr3[][5] = {{1,2},{3,4},{5,6}};

以上均为不完全初始化
arr :先给第一行赋值,1——5,6在第二行首,剩下的补0
arr1:把1和2放在第一行前两列,3和4放在第二行前两列,5和6放在第三行前两列
arr2:可以不确定行,但必须确定列,当第一行五列赋值之后,6在第二行剩下的补0,所以确定为2行5列
arr3:把1和2放在第一行前两列,3和4放在第二行前两列,5和6放在第三行前两列,可以确定行数是3

二维数组的使用

和一维数组同理

int main()
{
	int i,sz1,sz2;
	int arr1[][5] = {{1,2},{3,4},{5,6}};

	sz1=sizeof(arr1[0])/sizeof(arr1[0][5]);	
	//可求列大小:用第一行的总长度 除以 第一行每其中一列的长度 = 列的长度
	printf("%d\n",sz1);
	sz2 = sizeof(arr1)/sizeof(arr1[0]);		
	//可求行大小:用总大小除 一行的总大小 = 行的长度
	printf("%d\n",sz2);
	for(i = 0; i< sz2; i++)
	{
		int j = 0;
		for(j = 0; j < sz1; j++)
		{
			printf("%d ",arr1[i][j]);
		}
		putchar('\n');
	}
	return 0;
}

在这个代码中可以通过
sizeof(arr)/sizeof(arr[0]) 求出行数
总数组大小 除以 首行的大小 等于 行的数量
sizeof(arr[0])/sizeof(arr[][0]) 求出列数
首行的大小 除以 首行首列的大小 等于 列数

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

二维数组在内存中的存储如下:

int main()
{
	int i;
	int arr1[][5] = {{1,2},{3,4},{5,6}};
	for(i = 0; i< 3; i++)
	{
		int j = 0;
		for(j = 0; j < 5; j++)
		{
			printf("&arr1[%d][%d] = %p\n",i,j,&arr1[i][j]);
		}
	}
	return 0;
}

在这里插入图片描述
观察输出结果可知:
二维数组也是是连续存放的
随着下标变化二维数组的地址也是由低到高的

了解了二维数组,三维数组也是同理,就是[ ] [ ] [ ] 三个操作符
可以先把二维数组看作一个整体当作一维数组 在与三维数组结合
实际中三维及以上数组用的很少。

数组作为函数参数

在调用函数时,数组可以作为参数传递
示例1:二分查找法
通过下标找到其元素

int find(int temp[],int t,int sz)
{
	//int sz = sizeof(arr)/sizeof(arr[0]); 结果是1
	int first = 0;
	int end = sz-1;
	int mid = 0;
	while(first <= end)
	{
		mid = first+(end - first)/2;
		if(temp[mid] > temp[t])
		{
			end = mid - 1;
		}
		else if(temp[mid] < temp[t])
		{
			first = mid + 1;
		}
		else
		{
			return temp[mid];
		}
	}	
}
int main()
{
	int arr[] = {1,2,3,4,5,6,7};
	int sz = sizeof(arr)/sizeof(arr[0]);
	printf("%d\n",find(arr,0,sz));
	return 0;
}

如上所示:假如将int sz = sizeof(arr)/sizeof(arr[0]); 放到find函数里计算,结果为1,而在主函数里结果为7。所以可知,当数组作为参数时,传递的是首地址。

示例2:冒泡排序法

void bubble_sort2(int *arr,int sz)
{
	int i,j;
	for(i = 0;i < sz-1;i++)
	{
		for(j = 0;j<sz-1-i;j++)
		{
			if(arr[j]<arr[j+1])
			{
				int temp;
				temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;
			}
		}
	}
}
int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int i;
	int sz = sizeof(arr)/sizeof(arr[0]);
	bubble_sort2(arr,sz);
	for(i = 0; i < 10; i++)
	{
		printf("%d",arr[i]);}
	return 0;
}

上述代码同理,传递的是数组的首地址,数组本质上是指针,所以是传递首地址后通过指针访问数组上的元素

总结

int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	printf("%d\n",sizeof(arr));				//40
	putchar('\n');

	printf("%p\n",arr);						//数组的首地址
	printf("%p\n",arr+1);					//数组下一个元素的地址

	putchar('\n');

	printf("%p\n",&arr);					//数组的总地址,			相当于对*p,&p求指针的大小
	printf("%p\n",&arr+1);					//下一个数组的总地址,		指针的总地址+1 相当于 有开辟了一个新的同样大小的指针

	putchar('\n');

	printf("%p\n",&arr[0]);					//数组第一个元素的地址
	printf("%p\n",&arr[0]+1);				//数组下一个元素的地址
	return 0;
}

由上可知:

  1. 数组名传递的是首地址但有两个例外
    (1)sizeof(数组名) 不是首地址,此处代表整个数组,计算的是整个数组大小
    (2)&数组名 不是首地址,此处代表整个数组,取出的是整个数组地址

  2. sizeof求的是有效元素个数(包括\0)

  3. strlen求的是字符串长度,从首元素开始计算,遇见‘\0’停止

  4. 初始化后空余的元素会被补 0(\0)

  5. 二维数组不能没有列标

  6. 数组在内存中,是连续存放的

  7. 随着数组下标的增长,地址是由低到高变换的

  8. 注意数组越界问题 即[ ]里的表达式常量不能比数组总元素个数小

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值