C语言 数组(一维数组 · 二维数组)

一、一维数组的创建和初始化

1.1 数组的创建:

数组是一组相同类型元素的集合。数组的创建方式:

type_t	arr_name 	[const_n];
// type_t 	指数组的元素类型
// arr_name 	数组的名称
// const_n 	这是一个常量表达式,用来指定数组的大小

数组创建的实例:

	int arr01[10];

	int i = 10;
	int arr02[i]; //数组是否可以正常创建?

	float arr03[3];
	double a04[50];

注:数组创建的时候,[ ]中要给一个常量才可以,不能使用变量。

1.2 数组的初始化:

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

	int arr1[10] = { 1,2,3 };
	int arr2[] = { 1,2,3,4 };
	char arr3[3] = { 'a',98,'c' };
	char arr4[] = { 'a','b','c' };
	char arr5[] = "abcdef";

数组创建的时候,不指定数组大小就可以初始化,数组的元素个数根据初始化的内容来确定。
但是对于下面的代码,要区分内存中如何分配。

	char ch1[5] = { 'b','i','t' };
	char ch2[] = { 'b','i','t' };
	char ch3[] = "bit";
	
	printf("%d\n", strlen(ch1));
	printf("%d\n", strlen(ch2));
	printf("%d\n", strlen(ch3));


如图,strlen( ) 函数只是计算字符串大小,初始化只有三个字符,为什么中间那个输出15呢?

我们开启调试查看一下三个 ch 字符数组的情况。

  1. 第一个 ch 字符数组,初始化五个空间,使用三个后,其他没有使用的空间默认 ’ \0 ’ 结束标志,所以计算数组元素个数,显示为3。
  2. 第二个 ch 字符数组,没有初始化空间,那就根据数组元素个数分配空间。定义三个字符元素,但是没有给出 ’ \0 ’ 结束标志,所以数组计算长度没有及时结束,一直在内存中遇到某个 ’ \0 ’ ,程序才结束。
  3. 第三个 ch 字符串数组,同样没有初始化空间,但是这里提供的是字符串数组,字符串末尾自带 ’ \0 ’ ,所以正常结束,显示为3。

二、一维数组的使用

对于数组的使用,我们之前介绍了一个操作符:[ ] ,下标引用操作符。它其实就是数组访问的操作符。

//数组的使用
	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]);
	}

小结:

  1. 数组是使用下标来访问的,下标是从0开始。
  2. 数组的大小可以通过计算获得。

三、 一维数组在内容中的存储

接下来我们探讨下数组在内容中的存储。

//数组在内存中的存储
	int i = 0;
	int arr[10] = { 0 };
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
		printf("&arr[%d] = %p\n", i, &arr[i]);
	}

输出结果如下:
在这里插入图片描述

仔细观察输出结果,我们会发现:

  1. 数组的每个元素间距都是相差4,这是因为我们定义的是int类型的数组。
  2. 随着数组下标的增长,元素的地址,也会有规律的递增。

由此可以得出结论:数组在内存中是连续存放的。


四、二维数组的创建和初始化

4.1 二维数组的创建

  1. 二维数组是两个[ ],第一个[ ]控制行数,第二个[ ]控制列数(每行上有几个元素)。

  2. 可以在{ }里面套个{ },用来初始化每列上的元素。

  3. 可以省略第一个[ ],这样程序会根据第二个[ ]判断每行有几个元素,然后进行初始化。
    但是第二个[ ]不能省略。

//二维数组的初始化
	int arr1[3][4] = { 1,2,3,4 };
	int arr2[3][4] = { {1,2},{3,4} };
	int arr3[][4] = { 1,2,3,4 };
	int arr4[][4] = { {1,2},{3,4} };

4.2 二维数组的使用

二维数组的使用也是通过下标的方式。

	int arr1[3][4] = { 0 };
	int i = 0;
	//外层for,第一个[]控制行数
	for (i = 0; i < 3; i++) {
		int j = 0;
		//内层for,第二个[]控制列数
		for (j = 0; j < 4; j++) {
			//二维数组赋值
			arr1[i][j] = i * 4 + j;
		}
	}
	//输出二维数组
	for (i = 0; i < 3; i++) {
		int j = 0;
		for (j = 0; j < 4; j++) {
			printf("arr1[%d][%d] = %d\n", i, j, arr1[i][j]);
		}
	}

五、 二维数组在内存中的存储

像一维数组一样,我们尝试打印二维数组的每个元素。

//二维数组在内层中的存储
	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]);
		}
	}

我们取二维数组地址输出,发现二维数组在内存中存储的地址也是连续的。
所以二维数组也是线性存储的,不是像矩阵那样有行有列。


六、数组作为函数参数

我们在编写代码的时候,有时候会把数组作为参数传递给函数,例如:我们现在要实现一个冒泡排序的函数,能把一个整型数组排序。

冒泡排序:把一个乱序的数组进行排序。
将数组的第一个元素和第二个元素对比,如果第一个元素比第二个大,就交换位置;然后第二个位置的元素和第三个位置的元素比较,前一个大就交换位置…一直到走完这一趟,会发现数组最后一个元素是数组中最大的元素。接下来就是下一趟比较,重复上述操作…

动图演示:

在这里插入图片描述

了解了冒泡排序,让我们回到数组作为函数参数,设计个能完成冒泡排序的函数。

6.1 冒泡排序函数的错误设计

//方法1:
#include <stdio.h>
void bubble_sort(int arr[])
{
	int sz = sizeof(arr)/sizeof(arr[0]);//这样对吗?
  	int i = 0;
	for(i=0; i<sz-1; i++)
	{
    	int j = 0;
    	for(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 arr[] = {3,1,7,5,8,9,0,2,4,6};
	 bubble_sort(arr);//是否可以正常排序?
  	 for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
	 {
   	 	printf("%d ", arr[i]);
 	 }
  	 return 0;
}

方法1,出现问题。调式我们发现,bubble_sort函数内部的sz是1。就是没有成功计算出数组大小,导致函数不能完成排序。

难道数组作为函数参数的时候,不是把整个数组传递过去?


6.2 数组名是什么?

让我们取数组名的地址看一下。

	int arr[10] = { 1,2,3,4,5 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	printf("%d\n", *arr);


看下输出结果,我们可以发现,数组名和数组首元素地址是一样的。数组名就是数组首元素地址

但是若数组名是首元素地址,那么我们计算一下数组名。

	int arr[10] = { 1,2,3,4,5 };
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(arr[0]));


为什么输出的结果是:40和4?不是说两个的地址是一样的吗?

因为 数组名是数组首元素的地址。两个例外

  1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
  2. 取地址符号&。&数组名的组合,取出的是数组的地址。&数组名,数组名表示整个数组。

除了这两种情况之外,所有的数组名都表示数组首元素的地址。


6.3 冒泡排序函数的正确设计

之前我们简单的把数组名作为函数参数传递过去,实际上只是把数组首元素地址传递过去而已。
所以之后我们在sizeof()计算数组大小

int sz = sizeof(arr) / sizeof(arr[0])
只是把传递过来的数组(实际上是数组首元素地址),除于数组首元素地址。
自己除于自己,结果sz等于1.
//冒泡排序
//bubble_sort方法
void bubble_sort(int arr[], int sz) {
	int i = 0;
	for (i = 0; i < sz - 1; i++) {
		int j = 0;
		for (j = 0; j < sz - i - 1; j++) {
			if (arr[j] > arr[j + 1]) {
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}

//main方法
	int i = 0;
	int arr[] = { 3,1,7,5,8,9,0,2,4,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);
	for (i = 0; i < sz; i++) {
		printf("%d\n", arr[i]);
	}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值