C语言之“ 数组 ”

喜欢草莓熊的bear 2024-09-01 10:05:01 阅读 70

          🌹个人主页🌹:喜欢草莓熊的bear

             🌹专栏🌹:C语言基础


目录

前言

一、数组

二、一维数组

2.1 一维数组的创建和初始化

数组创建

数组初始化

数组类型

2.2 一维数组的使用

数组下标

数组打印

数组输入

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

三、sizeof计算数组元素个数

四、二位数组

4.1 二维数组的概念

4.2 二维数组的创建

4.3 二维数组的初始化

不完全初始化

完全初始化

按照行初始化

初始化时省略行,但是不能省略列

4.5 二维数组的使用

4.6 二维数组的输入和输出

4.7 二维数组的储存

五、C99中的变长数组

六、二分查找

总结


前言

本期给大家介绍的数组主要内容包括:数组的一些概念、了解一维数组、二维数组。

一、数组

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

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

数组中存放的多个数据,类型是相同的。

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

二、一维数组

2.1 一维数组的创建和初始化

数组创建

语法形式如下:

<code>1 type arr_name[常量值];

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

type

指定的是数组中存放数据的类型,可以是:

char

short

int

float

等,也可以⾃

定义的类型

arr_name

指的是数组名的名字,这个名字根据实际情况,起的有意义就⾏。

[]

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

⽐如:我们现在想存储某个班级的20⼈的数学成绩,那我们就可以创建⼀个数组,如下:

int math[20];

char ch[8];

double score[10];

数组初始化

有时候,数组在创建的时候,我们需要给定⼀些初始值值,这种就称为初始化的。

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

//完全初始化

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

//不完全初始化

int arr2[6] = {1};//第⼀个元素初始化为1,剩余的元素默认初始化为0

//错误的初始化 - 初始化项太多

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

数组类型

数组也是有类型的,数组算是⼀种⾃定义类型,去掉数组名留下的就是数组的类型。

如下:

int arr1[10];

int arr2[12];

char ch[5];

arr1数组的类型是 int [10]

arr2数组的类型是 int[12]

ch 数组的类型是 char [5]

2.2 一维数组的使用

学习了⼀维数组的基本语法,⼀维数组可以存放数据,存放数据的⽬的是对数据的操作,那我们如何使⽤⼀维数组呢?

数组下标

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

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

在C语⾔中数组的访问提供了⼀个操作符 [] ,这个操作符叫:下标引⽤操作符。

有了下标访问操作符,我们就可以轻松的访问到数组的元素了,⽐如我们访问下标为7的元素,我们就可以使⽤ arr[7]

,想要访问下标是3的元素,就可以使⽤

arr[3]

,如下代码:

<code>#include <stdio.h>

int main()

{

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

printf("%d\n", arr[7]);//8

printf("%d\n", arr[3]);//4

return 0;

}

执行结果:

数组打印

接下来,如果想要访问整个数组的内容,那怎么办呢?

只要我们产⽣数组所有元素的下标就可以了,那我们使⽤for循环产⽣0~9的下标,接下来使⽤下标访问就⾏了。

如下代码:

<code>#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("%d ", arr[i]);

}

return 0;

}

输出的结果:

数组输入

明⽩了数组的访问,当然我们也根据需求,⾃⼰给数组输⼊想要的数据,如下:

<code>#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++)

{

scanf("%d", &arr[i]);

}

for(i=0; i<10; i++)

{

printf("%d ", arr[i]);

}

return 0;

}

 

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

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

依次打印数组元素的地址:

<code>#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;

}

输出结果我们看看:

从输出的结果我们分析,数组随着下标的增⻓,地址是由⼩到⼤变化的,并且我们发现每两个相邻

元素之间相差4(因为⼀个整型是4个字节)。所以我们得出结论:数组在内存中是连续存放的。这就 为后期我们使⽤指针访问数组奠定了基础(在讲指针的时候我们在讲,这⾥暂且记住就⾏)。

 

三、sizeof计算数组元素个数

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

答案是有的,可以使⽤sizeof。

sizeof

中C语⾔是⼀个关键字,是可以计算类型或者变量⼤⼩的,其实

sizeof

也可以计算数组的

⼤⼩。

⽐如:

<code>#include <stido.h>

int main()

{

int arr[10] = {0};

printf("%d\n", sizeof(arr));

return 0;

}

这⾥输出的结果是40,计算的是数组所占内存空间的总⼤⼩,单位是字节。

我们⼜知道数组中所有元素的类型都是相同的,那只要计算出⼀个元素所占字节的个数,数组的元素个数就能算出来。这⾥我们选择第⼀个元素算⼤⼩就可以。

#include <stido.h>

int main()

{

int arr[10] = {0};

printf("%d\n", sizeof(arr[0]));//计算⼀个元素的⼤⼩,单位是字节

return 0;

}

接下来就能计算出数组的元素个数:

#include <stido.h>

int main()

{

int arr[10] = {0};

int sz = sizeof(arr)/sizeof(arr[0]);

printf("%d\n", sz);

return 0;

}

这⾥的结果是:10,表⽰数组有10个元素。

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

四、二位数组

4.1 二维数组的概念

前⾯学习的数组被称为⼀维数组,数组的元素都是内置类型的,如果我们把⼀维数组做为数组的元

素,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称为多维数组。

4.2 二维数组的创建

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

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

例如:

int arr[3][5];

double data[2][8];

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

3表⽰数组有3⾏

5表⽰每⼀⾏有5个元素

int 表⽰数组的每个元素是整型类型

arr 是数组名,可以根据⾃⼰的需要指定名字

data数组意思基本⼀致。

4.3 二维数组的初始化

在创建变量或者数组的时候,给定⼀些初始值,被称为初始化。

那⼆维数组如何初始化呢?像⼀维数组⼀样,也是使⽤⼤括号初始化的。

不完全初始化

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

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

 

完全初始化

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

 

按照行初始化

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

 

初始化时省略行,但是不能省略列

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

4.5 二维数组的使用

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

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

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

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

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

<code>#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;

}

4.6 二维数组的输入和输出

访问⼆维数组的单个元素我们知道了,那如何访问整个⼆维数组呢?

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

<code>#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;

}

 

4.7 二维数组的储存

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

<code>#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;

}

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

 了解清楚⼆维数组在内存中的布局,有利于我们后期使⽤指针来访问数组的学习。

五、C99中的变长数组

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

<code>int arr1[10];

int arr2[3+5];

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

这样的语法限制,让我们创建数组就不够灵活,有时候数组⼤了浪费空间,有时候数组⼜⼩了不够⽤的。 C99中给⼀个变⻓数组(variable-length array,简称 VLA)的新特性,允许我们可以使⽤变量指定 数组⼤⼩。 请看下⾯的代码:

int n = a+b;

int arr[n];

上⾯⽰例中,数组

arr

就是变⻓数组,因为它的⻓度取决于变量

n

的值,编译器没法事先确定,只

有运⾏时才能知道

n

是多少。

变⻓数组的根本特征,就是数组⻓度只有运⾏时才能确定,所以变⻓数组不能初始化。它的好处是程 序员不必在开发时,随意为数组指定⼀个估计的⻓度,程序可以在运⾏时为数组分配精确的⻓度。有 ⼀个⽐较迷惑的点,变⻓数组的意思是数组的⼤⼩是可以使⽤变量来指定的,在程序运⾏的时候,根 据变量的⼤⼩来指定数组的元素个数,⽽不是说数组的⼤⼩是可变的。数组的⼤⼩⼀旦确定就不能再 变化了。 遗憾的是在VS2022上,虽然⽀持⼤部分C99的语法,没有⽀持C99中的变⻓数组,没法测试;下⾯是我在gcc编译器上测试,可以看⼀下

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

}

第⼀次测试,我给n中输⼊5,然后输⼊5个数字在数组中,并正常输出

第⼆次测试,我给n中输⼊10,然后输⼊10个数字在数组中,并正常输出

六、二分查找

在⼀个升序的数组中查找指定的数字n,很容易想到的⽅法就是遍历数组,但是这种⽅法效率⽐较低。 ⽐如我买了⼀双鞋,你好奇问我多少钱,我说不超过300元。你还是好奇,你想知道到底多少,我就让 你猜,你会怎么猜?你会1,2,3,4...这样猜吗?显然很慢;⼀般你都会猜中间数字,⽐如:150,然后看⼤了还是⼩了,这就是⼆分查找,也叫折半查找。

<code>#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");

return 0;

}

求中间元素的下标,使⽤

mid = (left+right)/2

,如果left和right⽐较⼤的时候可能存在问

题,可以使⽤下⾯的⽅式:

mid = left+(right-left)/2;


总结

重点理解数组的储存是连续的,还有对二维数组的理解。自己实现一下二分查找!!



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。