C语言数组

数组是用来存储一组相同类型的元素的集合.
假设我们要存储100个int类型的值,虽然我们可以定义100个整型变量,但这样会显得啰嗦,此时我们就可以利用数组来解决这个问题

1.一维数组的创建

数组的创建符合该表达式: type_t arr_name[const_n];
type_t :数组存储数据的类型
arr_name:数组名
[const_n]:C99之前只能是一个常量表达式,用来指定数组的大小

int a[10];
char b[10];
float c[20];
int count = 10;
int d[count];//这个在VS上是不支持的

上述int d[count];创建一个数组在C99之前是不支持的,C99之后引入了变长数组的概念,才支持

2.一维数组的初始化

我们以整型数组为例子

int a[10]={0,1,2,3,4,5,6,7,8,9};//完全初始化
int b[10]={1,2,3};//不完全初始化,后面元素默认补0
int c[10]={0}//不完全初始化,这样可以将数组整体赋值为0
int d[]={0}//不指定数组长度赋值,必须对数组进行初始化,初始化的个数就是数组的实际个数
//该数组里只有一个0
int e[]={1,2,3};//该数组有三个元素分别为1,2,3
int f[]//这种初始化是不允许的
char s[]="abc";//字符数组独有的初始化方式,实际个数为4,会多存储一个'\0'
char g[]={'a','b','c'};//这样就能初始化一个只含abc三个字符的字符数组
char h[]={97,98,99};//当然这样也是可以的,存储一个字符对应的Ascill码值

3.一维数组的使用

(1)一维数组的访问是通过下标的方式,切记下标是从0开始的
(2)数组的长度是可以计算出来的-> sizeof(arr)/sizeof(arr[0]);
sizeof(arr)计算的是整个数组所占字节数,sizeof(arr[0])计算的是数组第一个元素所占的字节数,两者相除,就是数组的个数

下面来看数组的使用:

#include <stdio.h>
int main()
{
	int a[10];
	for (int i = 0;i < sizeof(a) / sizeof(a[0]);i++)
	{
		printf("%d ", a[i]);
	}
}

在这里插入图片描述
可以看到我们确实访问了数组,但为什么打印出来是一些随机值呢,这是因为我们的数组是一个局部变量,局部变量是在栈区存储的,他们在创建时,如果不初始化,会默认初始化为随机的值,所以我们在使用局部变量时,尽量初始化赋值.

4.一维数组在内存中的存储

我们来看一段程序

#include <stdio.h>
int main()
{
	int a[10] = {1,2,3,4,5,6,7,8,9,10};
	for (int i = 0;i < sizeof(a) / sizeof(a[0]);i++)
	{
		printf("&a[%d] = %p\n", i,&a[i]);
	}
}

在这里插入图片描述
我们看到上述每个元素与每个元素的存储都相差4,这是因为一个int在计算机中是按照4个字节来存储的,所以我们可以得出一个结论
一维数组在计算机中是连续存储的,且随着下标的增长,在计算机内存中的地址越来越高

5.二维数组的创建

int a[3][4];//创建一个3行4列的int二维数组
char b[3][5];//创建一个3行5列的char二维数组
double c[2][2];//创建一个2行2列的double二维数组

6.二维数组的初始化

二维数组可以看作,里面的元素是一个一维数组的数组

int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};//可以看作有三个一维数组
//每一个一维数组有四个元素
int b[3][4]={0,1.2,3,4,5,6,7,8,9,10,11}//这样初始化,会首先将每一个一维数组放满
//再放其他的一维数组,如果有剩余位置,用0填充
int c[][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}}//注意二维数组在初始化的过程中
//行可以省略,列一定不能省略

7.二维数组的使用

二维数组和一维数组的访问一样,通过[ ]下标运算符,只需要给出下标就可以访问
直接上案例

#include <stdio.h>
int main()
{
	int a[3][4] = { {0,1,2,3},{4,5,6,7},{8,9,1,2} };
	for (int i = 0;i < 3;i++)
	{
		for (int j = 0;j < 4;j++)
		{
			printf("%d ", a[i][j]);
		}
		printf("\n");
	}
}

在这里插入图片描述

8.二维数组在内存中的存储

在这里插入图片描述

可以看出来每个元素之间也是相差4个字节,也就证明了。二维数组和一维数组一样,在内存中是连续存储的,并不是我们想象的按行列存储
在这里插入图片描述
正因为在内存中是连续存放的,所以必须知道有多少列,才能知道从哪里开始是下一行

9.数组越界

不管是一维数组还是二维数组,在对元素进行访问时,都有自己的索引范围。数组越界访问,编译器不会给你报错,最多只是提示,这就要求我们程序员在访问数组时,注意数组的索引,不能超过n-1(n为数组长度)

#include <stdio.h>
int main()
{
	int a[5] = { 1,2,3,4,5 };
	for (int i = 0;i <=5;i++)
	{
		printf("%d ", a[i]);
	}
}

在这里插入图片描述
如图这就是访问数组越界造成的结果,虽然程序仍然可以启动(这是因为C语言并没有对数组越界做出禁止),但是越界的位置打印出随机值,这是因为数组下一个位置的内存空间会被附上随机值造成的结果.

10.数组作为函数参数

10.1冒泡排序

冒泡排序就是相邻两个元素进行比较,如果前面大于后面的元素,则交换两个数,每一趟冒泡排序可以确定1个最大数,假设有十个数,那么要进行9趟冒泡排序

#include <stdio.h>
int main()
{
	int a[10];
	printf("请输入10个待排序的数\n");
	int sz = sizeof(a) / sizeof(a[0]);
	for (int i = 0;i < sz;i++)
	{
		scanf("%d", &a[i]);
	}

	//冒泡排序
	for (int i = 0;i < sz - 1;i++)
	{
		for (int j = 0;j < sz - i - 1;j++)
		{
			if (a[j] > a[j + 1])
			{
				int tmp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = tmp;
			}
		}
	}

	//打印排序后的数组
	for (int i = 0;i < sz;i++)
	{
		printf("%d ", a[i]);
	}
}

在这里插入图片描述
那么现在有一个想法,我们希望将这个排序的功能封装成一个函数,在以后只需调用就可以给我们排序,如下

#include <stdio.h>
void Bubble_sort(int arr[])
{
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0;i < sz - 1;i++)
	{
		for (int j = 0;j < sz - i - 1;j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int a[10];
	printf("请输入10个待排序的数\n");
	int sz = sizeof(a) / sizeof(a[0]);
	for (int i = 0;i < sz;i++)
	{
		scanf("%d", &a[i]);
	}

	//冒泡排序
	Bubble_sort(a);
	//打印排序后的数组
	for (int i = 0;i < sz;i++)
	{
		printf("%d ", a[i]);
	}
}

在这里插入图片描述
运行结果如图所示,可以看到,这样并没有达到我们的要求,并没有对数组进行排序,那么问题出在哪里呢
其实就在于我们将数组名当作函数参数传递时,数组名的本质其实是指针,一个指针的大小在32位机器上是4个字节,所以冒泡排序中的sizeof(arr)/sizeof(arr[0])就等于4/4,也就是1,所以下面循环根本没有执行,那么我们应该如何解决这个问题,其实很简单,只需要将数组的长度也传入函数中即可,如下:

#include <stdio.h>
void Bubble_sort(int arr[],int n)
{
	for (int i = 0;i < n - 1;i++)
	{
		for (int j = 0;j < n - i - 1;j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int a[10];
	printf("请输入10个待排序的数\n");
	int sz = sizeof(a) / sizeof(a[0]);
	for (int i = 0;i < sz;i++)
	{
		scanf("%d", &a[i]);
	}

	//冒泡排序
	Bubble_sort(a,sz);
	//打印排序后的数组
	for (int i = 0;i < sz;i++)
	{
		printf("%d ", a[i]);
	}
}

在这里插入图片描述
这样就可以很好地解决这个问题

10.2数组名

我们有时候会疑惑arr有时是数组首地址,有时候又是整个数组,其实我们只需要记住两个特例
(1)在用sizeof()计算数组有多少字节时计算的是整个数组的大小
(2)利用&arr计算数组的内存地址时,计算的是整个数组的内存地址
其他所有情况都是数组元素的首地址
第一点很好理解,重点来看第二点

#include <stdio.h>
int main()
{
	int a[10];
	printf("%p\n", a);
	printf("%p\n", &a[0]);
	printf("%p\n", &a);
	printf("%p\n", a + 1);
	printf("%p\n", &a[0]+1);
	printf("%p\n", &a+1);
}

在这里插入图片描述
如图我们可以看到数组名等于第一个元素的首地址等于&a,这可能就有人会问,不是说&a计算的是整个数组的大小吗,别急,计算的确实是争个数组的大小,但是,他们刚开始都指向数组的首地址,给他们分别加一就能看出端倪.
a+1==&a[0]+1这两个都是跳过四个字节的大小(int型数组),而&a+1则跳过了40个字节,可见&a计算的是整个数组的大小.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值