C语言中的百宝箱——数组(2)

欢迎来到白刘的领域   Miracle_86.-CSDN博客

系列专栏  C语言知识

先赞后看,已成习惯

   创作不易,多多支持!

这里是白刘,书接上文,我们讲到了一维数组,以及sizeof关键字。今天我们来介绍一下数组的其它一些知识。

目录

 一、二维数组

1.二维数组的概念

2.二维数组的创建

3.二维数组的初始化

不完全初始化

完全初始化

按行初始化

二、二维数组的使用

1.二维数组的下标

2.二维数组的输入和输出

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

三、C99中的变长数组

四、二分查找


 一、二维数组

1.二维数组的概念

之前我们学习的都是一维数组,它的元素都是内置的,但是如果我们突发奇想,把一维数组当作数组的元素,那这个时候就出现了二维数组。同理,其它多维数组都是如此。

2.二维数组的创建

基本的形式如下:

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

首先,和一维数组一样,type代表数组元素的类型;arr_name是数组名;中括号里放常量,常量1代表行,常量2代表列。

eg:

int arr[3][5];
char data[4][30];

3.二维数组的初始化

二维数组的初始化有好多种,比如:不完全初始化、完全初始化、按照行初始化。

不完全初始化

这种初始化没有把数组的位置全填满,未填满的位置用0占位,eg:

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

完全初始化

这种初始化把数组位置全占满了,eg:

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

按行初始化

如果我们想指定某个位置是某个元素的时候,这时候就可以用按行初始化,eg:

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

初始化的时候,我们可以省略行,但是不能省略列,eg:

int arr5[][5] = {1,2,3};
int arr6[][5] = {1,2,3,4,5,6,7};
int arr7[][5] = {{1,2}, {3,4}, {5,6}};

二、二维数组的使用

1.二维数组的下标

我们刚刚讲了常量1是行,常量2是列,那我们有了行和列,就能确定元素位置,进而我们就能对其操作。在C语言中,二维数组的行和列都是从0开始的。

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

绿色代表行号、蓝色代表列号。比如说我想找到“7”,我只需要输出arr[2][4]即可:

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

我们来看结果:

2.二维数组的输入和输出

刚刚我们成功访问了一个元素,那再结合我们访问整个一维数组的经验,访问整个二维数组是不是也变得简单了。我们可以使用两层循环,第一层循环来控制行,第二层控制列。理论存在,实践开始。

#include <stdio.h>
int main()
{
 int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
 int i = 0;//遍历⾏
 //输⼊
 for(i=0; i<3; i++) //产⽣⾏号
 {
     int j = 0;
     for(j=0; j<5; j++) //产⽣列号
     {
         scanf("%d", &arr[i][j]); //输⼊数据
     }
 }
 //输出
 for(i=0; i<3; i++) //产⽣⾏号
 {
     int j = 0;
     for(j=0; j<5; j++) //产⽣列号
     {
         printf("%d ", arr[i][j]); //输出数据
     }
     printf("\n");
 }
 return 0;
}

来看执行结果:

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

我们在一维数组那里学到了,一维数组是随着下标数增加,地址由小变大。那二维数组是否也是如此呢?

我们来操作看看:

#include <stdio.h>
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++)
     {
         printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
     }
 }
 return 0;
}

来看结果:

还是观察,我们可以发现,二维数组每个元素依旧是连续存放的

如下:

了解其布局后,便于我们以后介绍指针在数组中的访问。

三、C99中的变长数组

在C99之前,数组的大小只能用常量以及常量表达式,但是在C99中添加了变长数组(variable-length array,简称 VLA)这样一个特性,允许变量指定数组大小。

废话不多说,直接上代码:

int n = a+b;
int arr[n];

变长数组的特性就是数组长度未知,只有在运行的时候才可能会确定,所以长数组不可以初始化。好处是程序员不必在开发时为数组初始化一个估计值。但是变长数组不代表着数组的大小可以随时随地变化,比较迷惑,变量可以变,但是一旦确定下来数组的大小,数组就不能变了。

在VS2022中,编译器不支持变长数组,但是在gcc中,可以使用,eg:

#include <stdio.h>
int main()
{
 int n = 0;
 scanf("%d", &n);//根据输⼊数值确定数组的⼤⼩
 int arr[n];
 int i = 0;
 for (i = 0; i < n; i++)
 {
     scanf("%d", &arr[i]);
 }
 for (i = 0; i < n; i++)
 {
     printf("%d ", arr[i]);
 }
 return 0;
}

第一次,我把5赋给n,然后输入5个元素,并且输出

第二次,我把10赋给n,然后输入10个元素,并且输出

来看执行结果:

四、二分查找

在一个升序的数组中查找n,我们首先想到的可能是,挨个遍历,一个一个找。但是这种方法在某些特定情况,比较麻烦。比如说,白刘戴了一块金表,让我们猜多少钱,白刘说不超过三万块钱。那我们还能一个一个遍历吗,从一开始慢慢猜?显然不合理,一般我们可以折半去猜,比如说猜个15000,白刘说少了,再猜22500,又大了......是不是比从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 key = 7;//要找的数字
 int mid = 0;//记录中间元素的下标
 int find = 0;
 while(left<=right)
 {
     mid = (left+right)/2;
     if(arr[mid]>key)
     {
         right = mid-1;
     }
     else if(arr[mid] < key)
     {
         left = mid+1;
     }
     else
     {
         find = 1;
         break;
     }
 }
 if(1 == find )
     printf("找到了,下标是%d\n", mid);
 else
     printf("找不到\n");
}

首先这个数组必须是有序的,这点很重要,即使无序也咩关系,我们后面会学到排序函数。

然后我们找到数组的两端的下标以及数组中间的下标(不用管奇数还是偶数)中间下标将数组分为两部分。

然后放入循环,判断要找的数在哪部分,然后重新规定左右两端的下标,直到找到那个数为止。亦或者,如果没有那个数,也要跳出循环。

跳出循环的条件我们可以想象一下,就像左右两边分别有两辆小车,然后集体往中间开,如果其中一个小车碰到目标,则重新定起点,距离目标远的那个从中间下标开,直到小车相遇(中间即是目标)。没找到的话,两个车会擦肩而过,这个时候我们就退出循环。

求中间下标的时候,有时候我们不用加在一起然后再除以2,这样容易数太大了,造成数据丢失

如上图,我们可以先将两者作差,然后把差值一分为二,分给两端。也就是:

mid = (left+right) / 2

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Miracle_86.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值