C语言学习笔记之数组

文章详细介绍了数组的概念,包括一维数组的初始化、引用以及二维数组的创建、初始化和应用。提到了数组作为函数参数时的传递方式,并通过冒泡排序的示例进行了说明。此外,还讨论了数组名在不同情况下的含义及其内存存储特性。
摘要由CSDN通过智能技术生成

目录

一、一维数组

1、一维数组的初始化

2、一维数组的引用

二、二维数组

1、二维数组的初始化

2、二维数组的应用

 三、数组作为函数参数传参

四、 关于数组名


先补个概念:数组是什么

数组是一组具有相同类型的数据的集合,在一个数组中构成该数组的成员称为数组元素。

一、一维数组

一维数组是由一个下标的数组元素组成的数组。它的定义格式如下:

类型说明符 数组名[常量表达式]

int arr1[10];
char arr2[10];
float arr3[10];
double arr4[10];
//下面的写法不可行
int n=5;
int arr5[n];//即使你预先赋值,它仍然不是常量表达式

常量表达式 可以是整型常量、符号常量;但不能是0、负数、浮点数、变量。常量表达式的值就是数组的元素个数。

1、一维数组的初始化

数组在创建的时候我们要给定一些纸进行初始化。注意观察等号后面是数字,字符,字符串三种情况格式的区别哦。

int arr1[10]={1,2,3};//不完全初始化,默认剩下七个元素的值为0
char arr2[10]={'a','b','c'};//不完全初始化,默认剩下七个元素的值为0
//char arr2[10]={'a',98,'c'};这里面的98其实还是'b'(ASCII码表)
char arr3[10]="abc";//不完全初始化,默认剩下6个元素的值为0,别忘了第四个字符是'\0'哦
char arr4[]="abcdef";//这种情况可以省略常量表达式,电脑知道[]里面放的是7

 测测之前的知识:

char arr4[]="abcdef";
printf("%d\n",sizeof(arr4));
printf("%d\n",strlen(arr4));

 两个分别输出什么呢?

答案:7   6

为什么呢?

sizeof是计算数组arr4所占空间的大小,里面包含'\0'。

strlen是求字符串的长度,遇到'\0'停止,'\0'不算在字符串里面(也就是说是求'\0'之前的字符个数)

两者的区别:

strlen:只能针对字符串求长度;是库函数;需要引用头文件

sizeof:计算变量、数组、类型的大小,单位是字节;是关键字

看个例子加深印象:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcd";
	char arr2[] = { 'a','b','c','d' };
	printf("%d\n", sizeof(arr1));
	printf("%d\n", sizeof(arr2));
	printf("%d\n", strlen(arr1));
	printf("%d\n", strlen(arr2));
	return 0;
}

 答案:

5

4

4

随机值

前三个我们不奇怪,但是第四个咋是个随机值呢。我们刚刚说过strlen遇到'\0'停止,但问题是你arr2 里面没有'\0'啊,所以继续在内存里面找,什么时候找到'\0'什么时候停止,所以是随机值。

2、一维数组的引用

每一个数组元素都是一个变量,他们可以被赋值也可以被使用。前面那么多的代码,不知道你们有没有发现有一个操作符[ ],这是下标引用操作符(其实就是数组访问操作符)。

注意下标从0开始的,也就是说加入一个数组有10个元素,那么它的下标只到9。

讲了那么多了我们有必要深入了解一下一维数组是怎么存储的。

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

我们先看看下面程序数组每个元素的地址:

 这些地址以16进制的形式打印(为什么16进制看我指针文章),回顾一下16进制:

1 2 3 4 5 6 7 8 9     a(10) b(11) c(12) d(13) e(14) f(15)

我们观察上面的地址,它们每一个地址之间正好差4字节,而4字节正好是一个整型元素的大小。

说了那么多只想告诉你一句话:数组在内存中是连续存放的。

二、二维数组

什么是二维数组?

当数组中的每个元素都带有两个下标时,这样的数组就称为二维数组。

二维数组的创建:

int arr1[3][4];//三行四列
char arr2[3][4];
double arr3[3][4];
float arr4[3][4];

1、二维数组的初始化

int arr1[3][4]={1,2,3,4,5};

首先看这样一个二维数组,它是怎么存放数据的呢?

打开VS监视器:

我们发现它是这样排列的:

1     2     3     4

5     0     0     0

0     0     0     0

 显而易见这也是一个未完全初始化的数组。

观察得知:数据是一行一行排列,一行放不完才会放到下一行里面。(行优先)

可以理解为每一行都是一个一维数组。

那有没有办法把某些指定数据放在第一行,而另一些数据放在其他行呢?

我们可以这样来写:

int arr1[3][4]={{1,2},{3},{4,5}};

打开监视器:

 

我们发现它是这样排列的:

1     2     0     0

3     0     0     0

4     5     0     0

前面我们学过:

int arr1[]={1,2,3,4];

这种情况可以省略[ ]的值,那二维数组能不能也这样呢?

 这种情况是错误的,因为你没有告诉编译器数组是几行几列,给这么5个数让我怎么排?

前面在二维数组,我们把某些值再用[ ]括起来,达到把某些值按行分配的效果。

那么这里可不可以呢?

 也是不行的!

那到底有没有可以省略的呢?

有,列的表达式不可以省略

 好吧,这个{ }里面有3个{ },实际上告诉你我有三行了,那我们看看下面这张图:

 这张图我们没有告诉编译器有几行,但是我告诉有几列。

这个几列实际上就是告诉你一行有几个元素,上图告诉我们一行三个元素,现在有五个元素,先把第一行的三个元素填进去。

多了两个元素?

那就再来一行,为了与上一行的元素个数保持一致,补个0就完事了。

2、二维数组的应用

二维数组的使用也是通过下标:

每一行、每一列的下标都是从0开始的。

实操一下,把二维数组的所有元素打印出来:

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

先打印出每个元素的地址:

 和一维数组一样,每个地址之间相差4字节,也就是说二维数组在内存中也是连续存放的。

可别想象成这样排列的:

1     2     3     4

5     0     0     0

0     0     0     0

咱们在书写二维数组的时候这样写,但是他在内存中可是连续排列的。

 三、数组作为函数参数传参

我们在写代码的时候会将数组作为参数传给函数。(在我的C语言笔记函数-函数参数一节也有涉猎)

实践出真知,我们先写一个程序练练手:

将一个整型数组的元素进行升序排序(也就是冒泡排序)

冒泡排序的原理就是从首元素开始相邻两个元素比较大小,进行排序。

也就是说先第一个元素和第二个元素比较大小,第一个大的话和第二个元素交换位置。

然后第二个和第三个元素比较大小,第二个大的话,第二个元素和第三个元素交换位置.......

这一轮结束后,最大的元素能被放到最右边。

然后是下一轮继续交换,这一轮结束后,第二大的数能放在从右往左第二个位置。

继续交换.....

............

直到所有的数字被升序完成。

交换轮数和元素个数有关为n-1

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
void bubble_sort(int arr[], int m)
{
	int i;
	for (i = 0; i < m - 1; i++)
	{//每一轮冒泡排序
		int j = 0;
		for (j = 0; j < m -1-i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}
int main()
{
	int arr1[] = { 3,5,2,7,4,9,8,1 };
	int i = 0;
	//对arr1进行升序排列
	int sz = sizeof(arr1) / sizeof(arr1[0]);//确定元素个数,sz-1即为冒泡排序的轮次
	bubble_sort(arr1,sz);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

上面的代码挺长的,且看我慢慢分解

int sz = sizeof(arr1) / sizeof(arr1[0]);//确定元素个数,sz-1即为冒泡排序的轮次
//注意确定元素个数的语句要放在主函数里面计算,不能放在调用函数里面	
bubble_sort(arr1,sz);
//数组作为函数参数,传递的是首元素的地址
void bubble_sort(int arr[], int m)
//int arr[]和int* arr两者都可
for (i = 0; i < m - 1; i++)
//用循环实现多轮排序,排序的轮数比元素个数减一
for (j = 0; j < m -1-i; j++)//在每一轮内部进行比大小,换位置
		{//j < m -1-i是因为每一轮结束后,下一轮中比大小的次数比上一轮少一次
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}

这段代码的不足之处在于,如果给了一个有序数组,它还要一轮一轮的判断,所以我们优化一下

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
void bubble_sort(int arr[], int m)
{
	int i;
	for (i = 0; i < m - 1; i++)
	{//每一轮冒泡排序
		int order = 1;//order=1时有序,
		int j = 0;
		for (j = 0; j < m -1-i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
				order = 0;//说明还不完全有序
			}
		}
		if (order == 1)
		{
			break;
		}
	}
}
int main()
{
	int arr1[] = { 3,5,2,7,4,9,8,1 };
	int i = 0;
	//对arr1进行升序排列
	int sz = sizeof(arr1) / sizeof(arr1[0]);//确定元素个数,sz-1即为冒泡排序的轮次
	bubble_sort(arr1,sz);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

感觉这个博主讲的详细:冒泡排序算法(超级详细)

四、 关于数组名

我们常常将数组名是首元素地址,我们打印他们的地址看看:

 但是呢,凡是皆有例外:

有两种例外:

  • sizeof(数组名),这种时候数组名表示整个数组,计算的是整个数组的大小----字节
  • &数组名,代表取出整个数组的地址

    对于第二种例外,我们打印出来看看地址和首元素地址的区别:

嚯!看来这整个数组的地址咋和首元素地址一样啊?

真的一样吗?

前两种打印的是首元素的地址,而第三种打印的是数组的起始地址! 

假如在它们的地址上面+1,我们看看效果: 

 

 前两个都是:08->0C

首元素地址+1,1是整型占4字节,8+4=12(c)。

最后一个是:08->1C

计算可知两者相差20字节(16+4),正好是5个整数,对应数组里面的4个数,加上1。

(数组里面4个数是因为&arr的起始地址是首元素地址,不计入了)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值