【C语言】7. 数组

一、数组的概念

数组是⼀组相同类型元素的集合,一般存放的是一个或者多个数据。数组分为一维数组与多维数组,多维数组使用较多的一般是二维数组。

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

1、数组的创建

⼀维数组的语法:type arr_name[常量值]

存放在数组内的值被称为数组的元素,数组在创建的时候可以指定数组的⼤⼩和数组的元素类型。
①:type 是数组中存放数据的类型,如 char、short、int、float 等或者⾃定义的类型。
②: arr_name 是数组名,起的有意义即可。
③:[ ] 中的常量值⽤来指定数组⼤⼩。

例如:我们想存储某个班级20⼈的数学成绩,那我们就可以创建⼀个数组:int math[20]

同样也可以根据需要创建其他类型大小的数组,如下:

char ch[8];
double score[10];

2、数组的初始化

数组在创建的时候,有时需要进行初始化,那么数组是怎样初始化的呢?实际上数组的初始化就是将数据放在大括号中。

初始化一般分为完全初始化和不完全初始化,像int arr1[5] = { 1,2,3,4,5 }就是完全初始化,元素个数等同于数组大小;而int arr2[5] = { 1 }就是不完全初始化,元素个数小于数组大小。

3、数组的类型

数组也是有类型的,一般去掉数组名后剩下的就是数组的类型。例如int arr1[10]的类型就是int [10]

三、⼀维数组的使⽤

学会了⼀维数组的基本语法后,我们知道⼀维数组是可以存放数据的,而存放数据的⽬的是对数据进行操作,那我们如何使⽤⼀维数组呢?

1、数组的下标

C语⾔规定数组是有下标的,下标从0开始,假设数组有n个元素,那么最后一个下标就是n-1,而每一个下标都依次对应一个元素。
例如:数组int arr[10] = {1,2,3,4,5,6,7,8,9,10} 的下标就是0到9,依次对应10个元素。

在C语⾔中对于数组的访问还提供了⼀个下标引⽤操作符:[ ]
如果想访问一个元素,那么就可以对其下标使用[ ]从而进行访问。

例如:想打印数组元素4和8。

#include<stdio.h>

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

运行结果:

可以看到,如果想要访问元素4和8,那么我们只需要针对其下标3和7进行访问即可。

2、数组的输出

那么如果想要访问整个数组的内容,只需要产⽣数组所有元素的下标,再使⽤下标进行访问就⾏了。

#include<stdio.h>

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

运行结果:
在这里插入图片描述

3、数组的输⼊

如果我们想在数组输入自己想要的数据该怎么办呢?实际上和上面是一样的,先产生下标,再对下标对应的元素输入数据。

#include<stdio.h>

int main()
{
	int arr[5] = { 0 };
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");

	for (int i = 0; i < 5; i++)
	{
		scanf("%d", &arr[i]);
	}

	for (int i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

运行结果:

可以看到数组本来为空,在我们输入5个数据后,数组存放的也就是我们输入的数据了。

四、⼀维数组在内存中的存储

如果想要深⼊了解数组,那我们就要了解数组在内存中的存储。

我们可以在x86环境下打印5个数组元素的地址来进行观察:

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;
}

运行结果:

我们可以看到,数组元素随着下标的增大,地址也是逐渐变大的,而且每一次都增长4个字节(一个整型大小)。所以可以得出结论:数组在内存中是连续存放的

五、sizeof计算数组元素个数

我们知道sizeof关键字是可以计算类型或者变量⼤⼩的,其实 sizeof 也可以计算数组的⼤⼩,单位是字节。
例如:

#include<stdio.h>

int main()
{
	int arr[10] = { 0 };
	printf("%d\n", sizeof(arr));
	return 0;
}

运行结果:
在这里插入图片描述

这⾥我们计算的是整个数组的大小,总共40个字节。

我们⼜知道数组中所有元素的类型都是相同的,那么只要计算出⼀个元素的大小,再用数组总大小除一个元素的大小,即:sizeof(arr) / sizeof(arr[0]),最后得到的就是数组的元素个数了。

#include<stdio.h>

int main()
{
	int arr[10] = { 0 };
	int len = sizeof(arr) / sizeof(arr[0]);
	printf("%d\n", len);
	return 0;
}

运行结果:
在这里插入图片描述

六、⼆维数组的创建和初始化

1、⼆维数组的概念

2、⼆维数组的创建

二维数组的语法:type arr_name[常量值1][常量值2]

注:第一个常量值表示行数,第二个常量值表示列数

3、⼆维数组的初始化

二维数组与一维数组的初始方法一致,分为了完全初始化,不完全初始化和按行初始化。

①完全初始化:int arr[3][5] = { 1,2,3,4,5, 6,7,8,9,10, 11,12,13,14,15 }
表示二维数组有三行,每一行有五个元素。

②不完全初始化:int arr[3][5] = {1,2}
表示二维数组有三行,每一行有五个元素。

③按行初始化:int arr[3][5] = { {1,2},{3,4},{5,6} }

我们在初始化的时候还要注意一点:初始化可以省略行,但是不能省略列
例如: int arr[][5] = {1,2,3,4,5,6,7}

可以看到只要知道一行有几个元素,数据就会依次去占位,第一行满了就会进入下一行。

七、⼆维数组的使⽤

1、⼆维数组的下标

C语⾔规定,⼆维数组的⾏是从0开始的,列也是从0开始的,因此只要知道了行列的下标就可以定位出元素。例如int arr[3][5] = { 1,2,3,4,5, 6,7,8,9,10, 11,12,13,14,15 }

我们想要查找元素7,就可以分别找到其行列下标,在图中可以看到行下标为1,列下标位1。此时再使用下标引用操作符即可访问:

#include<stdio.h>

int main()
{
	int arr[3][5] = { 1,2,3,4,5, 6,7,8,9,10, 11,12,13,14,15 };
	printf("%d", arr[1][1]);
	return 0;
}

运行结果:
在这里插入图片描述

2、⼆维数组的输出

那如果想访问整个⼆维数组该怎么办呢?我们需要先产生行的下标,再在行的下标后面产生列的下标,再一一输出即可。

注:对于行的长度可以通过sizeof(arr) / sizeof(arr[0])来计算,对于列的长度可以通过sizeof(arr[0]) / sizeof(arr[0][0])来计算。

例如输出数组:int arr[3][5] = { 1,2,3,4,5, 6,7,8,9,10, 11,12,13,14,15 }

#include<stdio.h>

int main()
{
	int arr[3][5] = { 1,2,3,4,5, 6,7,8,9,10, 11,12,13,14,15 };
	int rows = sizeof(arr) / sizeof(arr[0]);
	int cols = sizeof(arr[0]) / sizeof(arr[0][0]);

	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

运行结果:

3、⼆维数组的输入

那么我们该怎么为二维数组输入数据呢?其实和二维数组输出数据一样,先产生行的下标,再在行的下标后面产生列的下标,再一一输入即可。

int main()
{
	int arr[3][5] = { 0 };
	int rows = sizeof(arr) / sizeof(arr[0]);
	int cols = sizeof(arr[0]) / sizeof(arr[0][0]);

	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			printf("%d ", arr[i][j]);
		}
	}

	printf("\n");

	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			scanf("%d", &arr[i][j]);
		}
	}

	printf("\n");

	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			printf("%d ", arr[i][j]);
		}
	}
	return 0;
}

运行结果:

可以看到二维数组本来没有数据,当我们输入之后,存放的就是输入的数据了。

八、⼆维数组在内存中的存储

像⼀维数组⼀样,我们想要深入了解二维数组,就需要了解⼆维数组在内存中的存储⽅式。

在x86环境下打印二维数组元素的地址:

#include<stdio.h>

int main()
{
	int arr[3][5] = { 1,2,3,4,5, 6,7,8,9,10, 11,12,13,14,15 };
	int rows = sizeof(arr) / sizeof(arr[0]);
	int cols = sizeof(arr[0]) / sizeof(arr[0][0]);
	
	for (int i = 0; i < rows; i++)
	{
		for (int j= 0; j < cols; j++)
		{
			printf("&arr[%d][%d]=%p\n", i, j, &arr[i][j]);
		}
	}
	return 0;
}

运行结果:

我们可以观察到,每⼀⾏元素地址依次递增4个字节,每一行地址也是依次递增4个字节,所以得出结论:⼆维数组中的每个元素也都是连续存放的

如图所⽰:

九、C99中的变⻓数组

在C99标准之前,数组⼤⼩只能指定为常量或者常量表达式。如int arr1[10]或者int arr2[3+5]。如果初始化时可以省略数组大小。
有时候数组⼤了会浪费空间,数组⼩了会不够用,存在着限制。

因此C99标准中出现了变⻓数组,允许我们将数组大小指定为变量。例如:int arr[n]。坏处是变⻓数组不能进行初始化,好处是程序在运⾏时可以根据变量的⼤⼩来指定数组的元素个数。

变长数组的使用:

#include<stdio.h>

int main()
{
	int n = 0;
	scanf("%d", &n);
	int arr[n];
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &arr[i]);
	}

	for (int i = 0; i < n; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

可惜在vs2022上不支持这一种用法,因此无法运行。

十、数组练习

练习1:多个字符从两端移动,向中间汇聚

思路:双变量指向两个数组的首尾下标,while循环依次对两个数组的首尾分别进行赋值。

#include<stdio.h>
#include<string.h>
#include<windows.h>

int main()
{
	char arr1[] = { "welcome to world!" };
	char arr2[] = { "*****************" };
	int left = 0;
	int right = strlen(arr1) - 1;

	while (left <= right)
	{
		Sleep(1000);
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		left++;
		right--;
		printf("%s\n", arr2);
	}
	return 0;
}

运行结果:

练习2:⼆分查找

常规查找一个数,需要我们依次遍历每一个数,如果数的规模很大,效率就非常的低。而我们可以每次先查找中间的数,如果大了就查找另外一半边元素,小了同理,这样我们每次就可以省略掉一半需要查找的数据,效率直接大大提高了,这就叫做二分查找法!

思路:创建双变量指向数组首尾下标,再创建变量mid指向中间元素下标,while循环拿中间元素比较要查找的数,大了mid-1变成新的尾下标,小了mid+1变成新的首下标,直到找到要查找的数。

#include<stdio.h>

int main()
{
	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	int left = 0;
	int right = sizeof(arr) / sizeof(arr[0]) - 1;
	int mid = 0;

	int key ;
	printf("请输入你要查找的数:");
	scanf("%d", &key);
	int find = 0;//先假设没有找到
	while (left <= right)
	{
		mid = left + (right - left) / 2;
		if (arr[mid] > key)
		{
			right = mid - 1;
		}
		else if (arr[mid] < key)
		{
			left = mid + 1;
		}
		else
		{
			//找到了 跳出循环
			find = 1;
			break;
		}
	}

	if (find == 1)
	{
		printf("找到了,下标是%d\n",mid);
	}
	else
	{
		printf("没有找到\n");
	}
	return 0;
}

运行结果:

如果left和right都⽐较⼤的时候使用mid = (left+right)/2,他们的和可能会超出数据的最大范围,因此使用mid = left+(right-left)/2更加的安全。

内容概要:本文档详细介绍了在三台CentOS 7服务器(IP地址分别为192.168.0.157、192.168.0.158和192.168.0.159)上安装和配置Hadoop、Flink及其他大数据组件(如Hive、MySQL、Sqoop、Kafka、Zookeeper、HBase、Spark、Scala)的具体步骤。首先,文档说明了环境准备,包括配置主机名映射、SSH免密登录、JDK安装等。接着,详细描述了Hadoop集群的安装配置,包括SSH免密登录、JDK配置、Hadoop环境变量设置、HDFS和YARN配置文件修改、集群启动与测试。随后,依次介绍了MySQL、Hive、Sqoop、Kafka、Zookeeper、HBase、Spark、Scala和Flink的安装配置过程,包括解压、环境变量配置、配置文件修改、服务启动等关键步骤。最后,文档提供了每个组件的基本测试方法,确保安装成功。 适合人群:具备一定Linux基础和大数据组件基础知识的运维人员、大数据开发工程师以及系统管理员。 使用场景及目标:①为大数据平台建提供详细的安装指南,确保各组件能够顺利安装和配置;②帮助技术人员快速掌握Hadoop、Flink等大数据组件的安装与配置,提升工作效率;③适用于企业级大数据平台的建与维护,确保集群稳定运行。 其他说明:本文档不仅提供了详细的安装步骤,还涵盖了常见的配置项解释和故障排查建议。建议读者在安装过程中仔细阅读每一步骤,并根据实际情况调整配置参数。此外,文档中的命令和配置文件路径均为示例,实际操作时需根据具体环境进行适当修改。
在无线通信领域,天线阵列设计对于信号传播方向和覆盖范围的优化至关重要。本题要求设计一个广播电台的天线布局,形成特定的水平面波瓣图,即在东北方向实现最大辐射强度,在正东到正北的90°范围内辐射衰减最小且无零点;而在其余270°范围内允许出现零点,且正西和西南方向必须为零。为此,设计了一个由4个铅垂铁塔组成的阵列,各铁塔上的电流幅度相等,相位关系可自由调整,几何布置和间距不受限制。设计过程如下: 第一步:构建初级波瓣图 选取南北方向上的两个点源,间距为0.2λ(λ为电磁波波长),形成一个端射阵。通过调整相位差,使正南方向的辐射为零,计算得到初始相位差δ=252°。为了满足西南方向零辐射的要求,整体相位再偏移45°,得到初级波瓣图的表达式为E1=cos(36°cos(φ+45°)+126°)。 第二步:构建次级波瓣图 再选取一个点源位于正北方向,另一个点源位于西南方向,间距为0.4λ。调整相位差使西南方向的辐射为零,计算得到相位差δ=280°。同样整体偏移45°,得到次级波瓣图的表达式为E2=cos(72°cos(φ+45°)+140°)。 最终组合: 将初级波瓣图E1和次级波瓣图E2相乘,得到总阵的波瓣图E=E1×E2=cos(36°cos(φ+45°)+126°)×cos(72°cos(φ+45°)+140°)。通过编程实现计算并绘制波瓣图,可以看到三个阶段的波瓣图分别对应初级波瓣、次级波瓣和总波瓣,最终得到满足广播电台需求的总波瓣图。实验代码使用MATLAB编写,利用polar函数在极坐标下绘制波瓣图,并通过subplot分块显示不同阶段的波瓣图。这种设计方法体现了天线阵列设计的基本原理,即通过调整天线间的相对位置和相位关系,控制电磁波的辐射方向和强度,以满足特定的覆盖需求。这种设计在雷达、卫星通信和移动通信基站等无线通信系统中得到了广泛应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值