C语言中数组专题

当你有很多类型相同的数据,一一给这些数据创建变量来存储会很麻烦,这时我们可以创建一个数组,将相同类型的数据存储在一起。

数组的概念

数组是一组存放类型相同的元素的集合;

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

数组分为一维数组和多维数组,多维数组常见的一般是一维数组和二维数组。

一维数组

数组创建

一维数组基本模板

type arr_name[常量值]

type表定的是数组中存放的数据类型,也表明这是一个什么类型的数组,type即类型有int整型,char字符型,float浮点型等等。

arr_name指的是数组名,随便取,一般在工作中,命名有意义对工作有意义。

[ ]中的常量值可以指定数组的大小,比如我想创建一个整形数组,能存30个元素可以int arr[30]。

一维数组的基本概论

由数据类型的意义到数组类型的意义到数组的基本概念

 为什么会有数据类型,或者说数据为什么要区分类型,高度抽象的不谈,具体方面以我目前对C语言的理解,之所以要有数据类型,是因为不同类型的数据在内存中存储方式有不同,不同类型的数据在内存申请的空间不同,基于以上这两点,那么不同的数据类型对内存大小的占用与调用权限也不同。例如在现在普遍的编译器上,int类型的数据占4个字节的内存,char类型的数据占1个字节。

补充知识:内存的基本单位是字节Byte,1字节等于8bit即比特,1bit等于1个二进制0或1。1个字节的大小能放下8位的二进制数。

千字节:1KB=1024 Byte 

兆字节:1MB=1024KB

吉字节:1GB=1024MB

太字节:1TB=1024GB

拍字节:1PB=1024TB

再大自己搜。。。。。

而数组作为类型相同数据元素的集合,那么上述所说数据类型的意义也是数组类型的意义。

上个代码,看看不同类型的一维数组在内存中的存储

如上图,我创建了一个整型数组要用它放10个元素,我给它的大小是10,然后给它初始化10个元素,我想要看看它在内存中是怎么存储的,及占用了多少空间,每个元素占用多少。

(我发现一个例子就能把许多知识点讲一遍)

于是我创建一个变量i,用for循环让它加到9,然后每加一次,就调用一次数组并取其地址打印出来,用for循环并定义变量i(作为数组下标),使i加到9进而调用数组用以完成目的(如打印其元素或地址)的操作叫遍历数组, 

而i叫数组的下标,数组的调用可以通过下标来执行。那为什么上图明明有10个元素,而下标确是9,那是因为下标的调用是从0开始的,如下代码一一对应

int arr[10]={1,2,3,4,5,6,7,8,9,10}
      下标: {0,1,2,3,4,5,6,7,8, 9}

而通过下标调用。

如我要打印数组种的10,可以

include<stdio.h>
int main()
{
    printf("%d",arr[9]);
   
     return 0;
}

数组的初始化

创建数组时,给定一个初始值叫数组的初始化

int arr[5]={1}//不完全初始化,其它项会被初始化为零

int arr[5]={1,2,3,4,5}//完全初始化

回到正题,我遍历了数组,并打印了所有元素的地址,来看看每个元素的地址有什么区别,进而可以看出一个整型数组的元素在内存中的存储的方式与所占空间。

 然后我们可以看到每个地址都相差4个字节空间的大小,这说明一个整型元素占4个字节,同时也说明数组在内存中是连续存放的。

更直观一点,我们可以将int 类型改为每个元素占一个字节的char类型看看。这样能更直观看到数组在内存中是连续存放的。

补充一下:地址怎么看,地址是十六进制,由于二进制的地址在64位环境下有64位,不好阅读,所以一般都换成十六进制。十六进制逢十六进一,A,B,C,D,E,F分别对应10 11 12 13 14 15。

地址是怎么生成的?,32位地址与64位地址又是怎么回事?

CPU访问内存中的某个字节的空间,必须知道这个字节空间在内存的位置,而内存很大,必须要给内存分配地址叫编址就像一栋居民楼,每户都有个门牌号,方便管理,也方便亲朋好友来访。

计算机的编址并不是把每个字节的地址记录下来,而是通过硬件设计完成。

硬件编址也是如此,首先必须理解,计算机有很多的硬件单元,硬件单元之间相互独立,通过“线”
来连接并可以互相通信。

CPU与内存之间也有大量数据交互,也要用线连接。

现在我们关注一组生成地址的线叫地址总线

32位的机器有32根地址线,每根线通过高低电平来生成0或1有两态,那么两根线可表示4种含义,即生成4个不同的地址编号,由此类推32位的机器能生成2的32次方个地址编号。同理64位机器能生成2的64个地址编号。现在的计算机大都是64位,同时又能使用32位的系统或软件。

而在我们打印的地址中,因为是64位即有64个0和1,编译器把它转换成十六进制。所以地址如上图那么长,现在我们将64位改成32位即叉86看看。就会发现地址变短了。

回到正题,我们解释了如何看地址问题得出了数组在内存中是连续存放的,同时还知道一个整型占4个字节,字符型占1个字节,这使得数组类型变的有意义。

现在我们有一种方式求数组的长度即占内存的多少和每个元素占内存的大小及元素个数,单位是字节

sizeof关键字

sizeof是C语言的一个关键字,是可以计算类型或变量的大小的,同理sizeof也可以计算数组的大小。

 

还是之前的那图,我为了方便,一次性把所有的案例代码敲了

我们可以看到sizeof(arr)计算的是整型数组的大小,结果40。我又让它除以10即元素个数可以看到每个元素大小是4。然后在用数组的长度除以一个元素的大小可得10。

char类型同理

补充:前面我们说过不同的数据类型对内存大小的占用与调用权限也不同

来看一下例子

我又加了两行代码,我想打印数组的地址,于是我尝试用数组名打印,再用数组名加1看看会发生什么。

我们会看到整形数组名arr的地址,与arr+1的地址相差4字节。同时我们还发现数组名arr的地址不时元素1的地址吗?是这样的,数组名是数组首元素的地址。然后加1跳过4字节是第二个元素的地址。

现在换成char类型

这就发现char类型的数组名加1跳过1字节。

二维数组

有一维数组,那么也会有二维数组

type arr_name[常量值][常量值]

type作为上文提过的数组类型自不必说,arr_name是数组名也不多说

来看的常量值,它们决定数组的大小,与一维数组相比,二维数组多了一个常量值产生行,可以看成要多少行一维数组。

int arr[1][5]=int arr[5]

二维数组与一维数组对比

第一个常量值决定行,有多少行。第二个常量值决定列,即一行有几个元素。

int arr[3][5]={1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7}
//三行五列,有三行,每行有5个元素

二维数组的初始化

int arr[3][5]={1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7}
//三行五列,有三行,每行有5个元素
//完全初始化

int arr1[3][5]={1,2}
int arr2[3][5]={0}
//不完全初始化

int arr3[3][5]={{1,2},{3,4},{5,6}}
//按行初始化

int arr[][5]
//补充:数组创建时大小可以没规定行,但不能没有列

二维数组的使用 

二维数组的下标

int arr[3][5]={1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7}
//三行五列,有三行,每行有5个元素
1#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;
}

 结果

遍历二维数组

用for循环产生行号,用嵌套for循环产生列

二维数组在内存中存储

我们打印二维数组的地址,发现二维数组的元素在内存中也是连续存放的,性质与一维数组并无二异。感兴趣的可自己尝试,作者累了就不展开写了

c99的变长数组

一般数组大小是固定的,在创建之初,就给定了大小,例如arr[5],arr[5+3],arr[3][5]。定长数组有时在项目需求不是很明确时会造成空间浪费,c99的变长数组给了我们一个新思路,如果数组大小是变量呢?

例如

#include<stdio.h>
int main()
{
   int n = 0;
   scanf("%d",&n);
   int arr[n]={0};

   return 0;

}

遗憾的是vs2022的编译器不支持变长数组。苹果系统的好像编译器可以。另外小熊C++的集成开反环境支持变长数组

数组练习

有一个有趣的效果可以用数组实现,初学的小伙伴可以用来在同学面前装逼用(前提是你同学也是刚开C语言课没多久,哈哈)

这是一串星星**************,现在我要让星星重两边向中间显示出happy everyday。

思路:我们可以弄两个数组,一个存星星****************(注意星星数应与字符串数相同),一个存happy everyday,然后再弄两个变量作下标来调用数组,两个变量分别是left=0(字符左边),right=strlen(arr1-1),让左边加加,right减减

(strlen是一个可以计算字符串大小的库函数,为什么要-1,因为在数组中字符串后边往往隐藏了结束符\0,这是happy everday\0在数组中的样子,不能把\0算上字符串长度)

然后把逐步把字符串数组传给星星数组并打印

 

效果。但然这还包含了window系统的命令,Sleep可以设置显示频率单位是毫秒,system是清理屏幕上的信息,没有它是这样

然后使用window库的命令要包含window.h。如果用不了它可以把声明放在第一行试试。

也可以看看window的目录有没有包含在里面,调试——属性

 

 如果没有就添加

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

清宁长欢

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

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

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

打赏作者

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

抵扣说明:

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

余额充值