3

探秘C语言数组:解锁高效数据管理与多维空间编程技巧" - Betty’sSweet

 6 months ago
source link: https://www.cnblogs.com/bett/p/18031360
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
pFp8UCq.jpg

✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:C语言学习
贝蒂的主页:Betty‘s blog

前面贝蒂给大家介绍了选择结构与循环结构,今天,贝蒂准备给大家介绍C语言中一个非常重要的结构——数组

1. 数组的定义

数组到底是什么呢,顾名思义就是很多数的集合,其大致满足下面两个条件:

  1. 这些数的类型必须相同。

  2. 这些数在内存中必须是连续存储的。

  • 换句话说,数组就是在内存中连续存储的具有相同类型的一组数据的集合。
  • 数组分为⼀维数组多维数组,多维数组⼀般⽐较多⻅的是⼆维数组。

2. 一维数组

2.1创建与初始化

(1) 创建

一维数组的定义方式如下:

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

  1. 类型说明符就是我们常用的存储类型(char int float double....),当然也可以自定义类型。

  2. 数组名就是我们为其取的名字,最好简单易懂,方便别人阅读。

  3. [] 中的常量值是⽤来指定数组的⼤⼩的,这个数组的⼤⼩是根据实际的需求指定就⾏

  • 注意:在C99之后C语言语法是支持变长数组的,即[]中可以是未知数,但是VS2022编译器是不支持的。
int arr[5];//表示此时数组arr中有 5 个元素,每个元素都是 int 型变量
char arr2[6];
float arr3[7];
double arr4[1 + 4];//也可以是一个表达式

(2) 初始化

有时候,数组在创建的时候,我们需要给定⼀些初始值,这种就称为初始化。那数组如何初始化呢?数组的初始化⼀般使⽤⼤括号,将需要初始化的数据放在⼤括号中。

初始化分为两种:完全初始化不完全初始化

int arr1[4] = { 1,2,3,4 };//完全初始化
int arr2[4] = { 1,2,3 };//不完全初始化,剩余元素默认为0
char arr3[10] = "hello ";//初始化字符串
int arr4[];//错误初始化
3371071-20240224173253462-1890601899.png
  • 如果进行初始化,可以不在[]声明有几个元素,数组会默认初始化几个元素,数组大小就是几个元素,但是不初始化就一定要声明有几个元素,否则就会报错。

2.2 数组输入和输出

(1) 数组下标

C语⾔规定数组是有下标的,下标是从0开始的(而不是1),假设数组有n个元素,最后⼀个元素的下标是n-1,例如:int arr[10]={1,2,3,4,5,6,7,8,9,10},其下标如下图所示:

arr 1 2 3 4 5 6 7 8 9 10
下标 0 1 2 3 4 5 6 7 8 9

(2) 输入

其实数组输入和我们平常输入差不多,只是输入对象换成了数组。

int main()
{
	int arr[10];
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		scanf("%d", &arr[i]);//循环像数组中输入元素
	}
	return 0;
}

(3) 输出

输出也是同理,我们可以利用循环输出其数组的每一个元素。

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);//循环输出
	}	
	return 0;
}

2.3 数组的内存存储

(1) 数组名

C语言规定数组名表示首元素地址,也就是说arr==&arr[0],我们可以通过以下代码来证明:

int main()
{
	int arr[2] = { 1,2 };
	if (arr == &arr[0])
	{
		printf("地址相同\n");
	}
	else
	{
		printf("地址不相同");
	}
	return 0;
}
3371071-20240224173253874-944105233.png
(2) 数组元素的存储

我们知道了数组名表示首元素的地址之后,那么接下来我们可以探究数组每个元素在内存中又是怎样存储的呢,我们将其每个元素的地址打印出观察。

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

输出结果:

img

从上述地址观察,地址是由⼩到⼤变化的,90,94,98......每次的增量是4,并且我们发现每两个相邻的元素之间相差4(因为⼀个整型是4个字节),就可以很容易得出结论:数组在内存中存储是连续的,理解到这一点,就能为以后指针的学习打好基础。

arr 1 2 3 4 5 6 7 8 9 10
下标 0 1 2 3 4 5 6 7 8 9

2.4 一维数组例题

题目:求任意十个整数的和与平均数。

思路:我们可以先将十个数输入一个数组中,然后循环求其和,在求平均数。

  • 注意:虽然是是个整数,但是最后结果可能是浮点数。

代码参考如下:

int main()
{
	int arr[10];
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		scanf("%d", &arr[i]);//循环输入
	}
	int sum = 0;//和
	for (i = 0; i < 10; i++)
	{
		sum += arr[i];
	}
	float avr = sum / 10.0;
	printf("这十个数和为%d平均数为%.1f", sum,avr);
	return 0;
}

3. 二维数组

前⾯我们学习的数组被称为⼀维数组,数组的元素都是内置类型的,如果我们把⼀维数组做为数组的元素创建数组,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称为多维数组

3.1 创建与初始化

(1) 创建

二维数组定义的一般形式为:

  1. 类型说明符 数组名[ 常量表达式][ 常量表达式];
  • 类比一维数组的定义,只不过二维数组第一个常量表达式表示行,第二个常量表达式表示列
int arr[5][5];//创建五行五列的二维数组
char arr2[3][5];//字符型二维数组
float arr3[4][5];//浮点型二维数组

(2) 初始化

二维数组的初始化和一维数组的初始化类似,像⼀维数组⼀样,也是使⽤⼤括号初始化的。

int arr1[3][3] = { 1,2 };//不完全初识化
1 2 0
0 0 0
0 0 0
  • 不完全初始化剩下元素默认初始化为0。
int arr2[3][3] = { 1,2,3,4,5,6,7,8,9 };//完全初始化
1 2 3
4 5 6
7 8 9
int arr3[3][3] = { {1,2},{2,3} };//按照行初始化
1 2 0
2 3 0
0 0 0
  • 按行初始化,剩下未初始化的元素默认为0.
int arr4[][3] = { 1,2,3 };//省略行

​ 示意图:

int arr5[3][];//错误初始化
int arr6[][];//错误初始化
  • 二维数组规定只能省略行,不能省略列。

3.2数组的输入和输出

(1) 数组下标

⼆维数组访问和一维数组类似,也是使⽤下标的形式的,⼆维数组是有⾏和列的,只要锁定了⾏和列就能唯⼀锁定数组中的⼀个元素。C语⾔规定,⼆维数组的⾏是从0开始的,列也是从0开始的,例如:int arr[3][3]={1,2,3,4,5,6,7,8,9,10};

行/列 0 1 2
0 1 2 3
1 4 5 6
2 7 8 9

(2) 输入

分别循环输入行和列,思路大致和输入一维数组相同。

int main()
{
	int arr[3][3] = {0};
	int i = 0;
	for (i = 0; i < 3; i++)//输入行
	{
		int j = 0;
		for (j = 0; j < 3; j++)//输入列
		{
			scanf("%d", &arr[i][j]);
		}
	}
	return 0;

}

(3) 输出

输出自然也与一维数组大致相同,利用循环依次输出。

int main()
{
	int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 3; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");//输出一行后换行
	}
	return 0;
}
3371071-20240224173254740-689026008.png

3.3 二维数组的存储

(1) 数组名

二维数组的数组名也是一个地址,那和一维数组的数组名有何不同呢,其实二维数组的数组名表示的是第一行的地址,但可能大家还是有下面的疑惑:

int main()
{
	int arr[3][3] = { 0 };
	printf("%p,%p\n", arr,&arr[0][0]);
	return 0;
}
3371071-20240224173255106-1733194622.png

为什么明明二维数组名代表的是第一行的地址,那么为什么和第一个元素的地址相同呢,其实和字符串的存储一样,如果将所有地址表示出来,太浪费内存,而数组在内存中是连续存储的,所以找到首元素的地址,就能找到一行中所有元素的地址。所以就以首元素地址代表第一行的地址

(2) 二维数组元素的存储

像⼀维数组⼀样,我们如果想研究⼆维数组在内存中的存储⽅式,我们也是可以打印出数组所有元素的地址的。代码如下:

int main()
{
	int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 3; j++)
		{
			printf("arr[%d][%d]=%p ",i,j, &arr[i][j]);
		}
		printf("\n");//输出一行后换行
	}
	return 0;
}

​ 输出如下:

img

通过对上面地址的观察,我们知道二维数组也是在内存中连续存储的,并且arr[0][2]和arr[1][0]的地址之间也差4个字节(byte),所以内存存储如下:

arr 1 2 3 4 5 6 7 8 9
下标 0,0 0,1 0,2 1,0 1,1 1,2 2,0 2,1 2,2

3.4 二维数组例题

题目:输入六个数到2行3列的二维数组arr中, 将二维数组arr1中的数组元素转置,即行列互换,存储到3行2列的二维数组arr2中,输出二维数组arr2中的数组元素。

思路:就是循环输入,在转置(行与列交换),最后输出。

代码如下:

int main()
{
	int arr1[2][3];
	int arr2[3][2];
	int i = 0;
	int j = 0;
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 3; j++)
		{
			scanf("%d", & arr1[i][j]);
		}
	}
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 3; j++)
		{
			arr2[j][i] = arr1[i][j];//转置
		}
	}
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 2; j++)
		{
			printf("%d ", arr2[i][j]);
		}
		printf("\n");
	}
	return 0;
}

4. 变长数组

4.1概 念

在C99标准之前,C语⾔在创建数组的时候,数组⼤⼩的指定只能使⽤常量、常量表达式,或者如果我们初始化数据的话,可以省略数组⼤⼩。

int arr1[10];
char arr2[4];
int arr3[] = {1,2,3};
  • 但是这样的语法限制,让我们创建数组就不够灵活,有时候数组⼤了浪费空间,有时候数组⼜⼩了不够⽤,所以在C99中给⼀个变⻓数组(variable-length array,简称VLA)的新特性,允许我们可以使⽤变量指定数组⼤⼩

4.2用法

int n;
scanf("%d",&n);
int arr1[n];
  • 变⻓数组的根本特征,就是数组⻓度只有运⾏时才能确定,所以变⻓数组不能初始化。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK