第五讲:数组

目录

1.数组的概念

2.一维数组的创建和初始化

2.1 数组创建

2.2 数组的初始化

2.3 数组的类型

3.一维数组的使用

3.1数组下标

3.2 数组元素的打印

3.3 数组的输入

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

5.sizeof计算数组元素个数

6.二维数组的创建

6.1 二维数组的概念

6.2 二维数组的创建

7.二维数组的创建

7.1 不完全初始化

7.2 完全初始化

7.3 按照行初始化

8.二维数组的使用

8.1 二维数组的下标

8.2 二维数组的输入和输出

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

10.数组练习

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

10.2 练习二:二分查找

11.本章代码


1.数组的概念

数组是一组相同类型元素的集合;从这个概念中我们就可以发现2个有价值的信息:

  • 数组中存放的是1个或者多个数据,但是数组元素个数不能为0。
  • 数组中存放的多个数据,类型是相同的。

数组分为⼀维数组和多维数组,多维数组⼀般⽐较多⻅的是⼆维数组。

2.一维数组的创建和初始化

2.1 数组创建

⼀维数组创建的基本语法如下:

type arr_name[常量值];

type表示类型(比如:char、int...),arr_name表示数组名,[常量值]表示数组元素。

存放在数组的值被称为数组的元素,数组在创建的时候可以指定数组的⼤⼩和数组的元素类型

比如·:

int math[10];

就可以表示存储一个班10人的数学成绩。

2.2 数组的初始化

那数组如何初始化呢?数组的初始化⼀般使⽤⼤括号,将数据放在⼤括号中。

//完全初始化

int arr[3]={1,2,3};

//不完全初始化

int arr[3]={1,2};

//错误初始化

int arr[3]={1,1,2,3};//初始化项太多

2.3 数组的类型

去掉数组名留下的就是数组的类型,比如:

int arr[1];

int arr1[2];

int arrr2[3];

arr数组的类型是int [1]

arr1数组的类型是int [2]

arr2数组的类型是int [3]

3.一维数组的使用

3.1数组下标

C语⾔规定数组是有下标的,下标是从0开始的,假设数组有n个元素,最后⼀个元素的下标是n-1,下标就相当于数组元素的编号,如下:

举个例子:

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

(后面的代码省略头文件#include<stdio.h>哈)

3.2 数组元素的打印

只要利用for循环,将数组所有元素的下标打印出来就可以了,如下:

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]);//从arr[0]-arr[9]循环打印。
	return 0;
}

3.3 数组的输入

数组的输入其实也是有一样的道理,如下:

int main()
{
	int arr[10] = {0};//注意写法arr[10],不要省略[10]
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		scanf("%d", &arr[i]);
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

结果:

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

有了前⾯的知识,我们其实使⽤数组基本没有什么障碍了,如果我们要深⼊了解数组,我们最好能了 解⼀下数组在内存中的存储。

利用前面学的知识,用%p来依次打印数组元素的地址:

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

上图我们可以看到:

随着下标的增长,地址也是由小到大变化的,并且地址从C到0到4到8(C在16进制中表示12),每两个相邻的元素都相差4(因为一个整形是4个字节)。

数组在内存中是连续存放的!

5.sizeof计算数组元素个数

在遍历数组的时候,我们经常想知道数组的元素个数,那C语⾔中有办法使⽤程序计算数组元素个数吗? 这时候我们就可以使⽤sizeof。

sizeof在C语言中是一个关键字,前面我们写过用sizeof来计算类型长度和变量大小,单位是字节。其实,sizeof也可以计算数组的大小。

比如:

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

sizeof(arr):表示计算整个数组所有元素的大小

sizeof(arr[0]):表示计算一个元素的大小,单位字节

输出结果:10,表示数组有10个元素

补充:

问打印的结果是什么?

int main()
{
    char arr[] = "welcome to NC";
    int sz = sizeof(arr) / sizeof(arr[0]);
    printf("%d", sz);
    return 0;
}

结果为14,因为这里arr是一个字符串,字符串包含了\0,sizeof会算上\0,所以结果为14

以后在代码中需要数组元素个数的地⽅就不⽤固定写死了,使⽤上⾯的计算,不管数组怎么变化,计 算出的⼤⼩也就随着变化了。

6.二维数组的创建

6.1 二维数组的概念

前⾯学习的数组被称为⼀维数组,数组的元素都是内置类型的(内置类型指的是C语言本身具有的类型),如果我们把⼀维数组做为数组的元素,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称为多维数组。

6.2 二维数组的创建

那我们如何定义⼆维数组呢?语法如下:

type arr_name[常量值1][常量值2];

比如:

int arr[3][4];

解释:上述代码中出现的信息

  • 3表⽰数组有3⾏
  • 4表⽰每⼀⾏有4个元素
  • int表⽰数组的每个元素是整型类型
  • arr是数组名,可以根据⾃⼰的需要指定名字

7.二维数组的创建

同理一维数组:

7.1 不完全初始化

//不完全初始化

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

int arr2[2][5]={0};

7.2 完全初始化

int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};

7.3 按照行初始化

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

注意:初始化的时候可以省略行,但不能省略列。

因为如果省略行,可以根据一行有多少个元素(列)来知道有多少行。

8.二维数组的使用

8.1 二维数组的下标

当我们掌握了⼆维数组的创建和初始化,那我们怎么使⽤⼆维数组呢?

其实⼆维数组访问也是使⽤下标的形式的,⼆维数组是有⾏和列的,只要锁定了⾏和列就能唯⼀锁定数组中的⼀个元素。

C语⾔规定,⼆维数组的⾏是从0开始的,列也是从0开始的,如下所⽰:

int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};

图中最右侧绿⾊的数字表⽰⾏号,第⼀⾏蓝⾊的数字表⽰列号,都是从0开始的,⽐如,我们说:第2 ⾏,第4列,快速就能定位出7。

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

8.2 二维数组的输入和输出

其实我们只要能够按照⼀定的规律产⽣所有的⾏和列的数字就⾏;以上⼀段代码中的arr数组为例,⾏ 的选择范围是0~2,列的取值范围是0~4,所以我们可以借助循环实现⽣成所有的下标。

int main()
{
	int arr[3][5] = { 0 };
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
		for (j = 0; j < 5; j++)
			scanf("%d", &arr[i][j]);
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");//最好给for循环后面打上()
	}
	return 0;
}

结果如下:

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

同理一维数组

int main()
{
	int arr[3][4] = { 0 };
	int i = 0;
	int j = 0;
	for(i = 0; i < 3;i++)
		for(j=0;j<4;j++)
	printf("%p\n", &arr[i][j]);
	return 0;
}

结果如下:

从输出的结果来看,每⼀⾏内部的每个元素都是相邻的,地址之间相差4个字节,跨⾏位置处的两个元素(如:arr[0][3]和arr[1][0])之间也是差4个字节,所以⼆维数组中的每个元素都是连续存放的!

10.数组练习

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

分析:其实就是要两个数组,利用数组的下标进行两个数组的交换

int main()
{
    int i = 0;
    char arr1[] = "####################";
    char arr2[] = "welcome to NC!!!!!!!";
    printf("%s\n", arr1);
    for (i = 0; i < 10; i++)//一次交换2个,所以只需要交换一半次就可以了
    {
        arr1[i] = arr2[i];
        arr1[19 - i] = arr2[19 - i];
        printf("%s\n", arr1);
    }
    return 0;
}

代码优化:上面的代码是知道了arr1和arr2的元素个数都为20,那如果不知道呢?

这里就可以用刚刚讲的sizeof来计算数组的元素个数,改进如下

//改进1

int main()
{
    int i = 0;
    char arr1[] = "######################";
    char arr2[] = "welcome to NC!!!!!!!!!";
    int sz = sizeof(arr1) / sizeof(arr1[0]);
    printf("%s\n", arr1);
    for (i = 0; i < sz/2; i++)
    {
        arr1[i] = arr2[i];
        arr1[sz -2- i] = arr2[sz-2 - i];//改为sz-2,因为数组下标从0开始;并且要减去字符串的\0
        printf("%s\n", arr1);
    }
    return 0;
}

如果想要动态的感觉还可以使用Sleep(1000)单位是毫秒,sleep(1000)表示睡眠1000毫秒,即一秒。不过要包含头文件#include <windows.h>

此外还可以使用system("cls");用来清屏

最终改进如下:

#include <windows.h>
#include <stdio.h>
int main()
{
	int i = 0;
	char arr1[] = "######################";
	char arr2[] = "welcome to NC!!!!!!!!!";
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	printf("%s\n", arr1);
	for (i = 0; i < sz/2; i++)
	{
		Sleep(1000);
		system("cls");
		arr1[i] = arr2[i];
		arr1[sz -2- i] = arr2[sz-2 - i];
		printf("%s\n", arr1);
	}
	return 0;
}

当然,还可以使用其他方法来写:

#include<string.h>
#include <windows.h>
#include <stdio.h>
int main()
{
	char arr1[] = "######################";
	char arr2[] = "welcome to NC!!!!!!!!!";
	printf("%s\n", arr1);
	int left = 0;
	int right = strlen(arr1) - 1;
	for (; left <= right; left++, right--)
	{
		Sleep(1000);
		system("cls");
		arr1[left] = arr2[left];
		arr1[right] = arr2[right];
		printf("%s\n", arr1);
	}
	return 0;
}

补充strlen是求字符串长度的,不会将\0计算进去。使用strlen需要包含头文件#include<string.h>

10.2 练习二:二分查找

在⼀个有序的数组中查找指定的数字n,很容易想到的⽅法就是遍历数组,但是这种⽅法效率⽐较低。

⽐如我买了⼀双鞋,你好奇问我多少钱,我说不超过300元。你还是好奇,你想知道到底多少,我就让你猜,你会怎么猜?你会1,2,3,4...这样猜吗?显然很慢;⼀般你都会猜中间数字,⽐如:150,然后看⼤了还是⼩了,这就是⼆分查找,也叫折半查找。

思路:

  1. 确定被查找的范围
  2. 确定被查找范围的左右下标
  3. 根据左右下标确定中间元素的下标
  4. 将确定的中间元素的下标和目标元素下标比较,没找到,就根据大小关系确定新的查找范围;找到了,就结束。

分析:比如1,2,3,4,5,6,7,8,9,10个数如何二分查找,找到数字7呢?我们知道这10个数的下标是0到9,那么数字7就是下标6。既然是二分查找,我们可以用下标相加再除以2,那么第一次找到的就是下标为4的数组元素(即(0+9)/2),但是下标4在目标下标6的左边,所以这时候我们让下标5(即下标4的后面一位)加下标9再除二,即得下标7,此时下标7在目标下标6的右边,所以再一次折半查找,用(5+6(下标7的上一位))/2即得下标5.下标5在下标6的左边,所以再一次折半查找,即((6+6)/2)可以得到目标下标6。

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int target = 7;
	int left = 0;//left代表左下标
	int sz = sizeof(arr) / sizeof(arr[0]);
	int right = sz - 1;//right代表右下标数
	int find = 0;
	while (left != right)
	{
		int mid = (left + right) / 2;
		if (arr[mid] > target)
		{
			right = mid - 1;
		}
		if (arr[mid] < target)
		{
			left = mid + 1;
		}
		else
		{
			find = 1;
			break;
		}
	}
	if (1==find)
		printf("找到了\n");
	else
		printf("找不到\n");
	return 0;
}

11.本章代码

编程代码C5: 第五讲的所有代码 (gitee.com)


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值