C语言之数组的基本知识

C语言之数组的基本知识在没接触数组之前,同学们用的都是定义一个一个变量来存放数据,但是这样就有一个缺陷,如果数据量很大的时候,比如有50个学生的成绩需要录入进去,那么定义50一个变量将会非常耗费时间,而且用scanf()函数输入数据的时候也很麻烦。intstu1,stu2,stu3,…,stu50;scanf("%d%d%d%d…",&stu1,&stu2,&s…

大家好,又见面了,我是你们的朋友全栈君。

在没接触数组之前,同学们用的都是定义一个一个变量来存放数据,但是这样就有一个缺陷,如果数据量很大的时候,比如有50个学生的成绩需要录入进去,那么定义50一个变量将会非常耗费时间,而且用scanf()函数输入数据的时候也很麻烦。

int stu1, stu2, stu3, ..., stu50;
scanf("%d %d %d %d ...",&stu1, &stu2, &stu3, ..., &stu50);

那么在C语言中有没有一种东西可以处理上面的数据呢?
当然有啦,数组这时候就出现了。
数组

数组是数据结构(我们大一下学期会专门学习这一章节),它可以存储一个固定大小的相同类型元素的顺序集合。<摘自百度>
有几个关键字要注意一下:
1:固定大小,
2:相同类型,
3:顺序集合。
要理解数组就得理解这三个关键字,我接下来一个一个对这个关键字进行讲解。

一:数组.固定大小

我们定义一个数组的时候,都必须事先告诉编译器这个数组的长度是多少,好让编译器给我们分配长度大小的内存空间,用来存放数据。
比如第一个例子,我想存放 50 个学生的成绩,或者存放一年每个月的销售额. 那么数组的定义是这样的:

double ArrStu[50];   //Array:数组
double Sales[12];    //一年十二个月,所以长度是12

观察下上面的两个数组,可以注意到数组(在这里先是一维数组)定义的基本格式是:

DataType ArrName[ size ];
//datatype 数据类型,如 int, long, float, double...
//ArrName 数组的名字,这里起名的方式跟变量名字的起法是一样的。
//size 数组的大小,这里的大小是固定的。
//[] 下标运算符,如我们要索引第2个元素,那么就是 Arr[1];

二:数组.数据类型

这里的数据类型就是上面提到的 datatype 。 一旦你确定了数组是何种类型的,那么你存放的数据就应该是这种类型的。
你不可以定义了 int 类型的数组,却用来存放浮点数,虽然可以编译通过,但是会得不到我们想要的结果。
如:

int arr[2];     //定义一个长度为2的int类型的数组
arr[0] = 12.5;  //赋值
arr[1] = 14.8;

运行结果如图:
在这里插入图片描述
int型,以%d的格式控制符输出,就会只保留整数部分,小数点后面的全部截断,所以输出的结果是12 14.

三:数组.顺序集合

假如我们定义了一个长度为 10 的数据,操作系统就会为其分配连续的十个内存地址。
这些地址用来存放地址,每一个地址所占的字节是数组的数据类型所决定的。
如int类型的每一个地址占据着4个字节,double类型的8个。

在这里插入图片描述
这里我用了取地址符将数组每一个元素的地址给显现出来,可以注意到各个元素之间的地址相差了4,为啥是4而不是别的呢?这是因为一个我一开始定义的数据类型是int类型的。
这里补充下内存地址的理解:

1:内存地址只是一个编号,代表一个内存空间。
2:内存地址也是内存当中存储数据的一个标识,并不是数据本身,通过内存地址可以找到内存当中存储的数据。<相当于通过你身份证上的地址信息,可以找到你的家乡一样.>
3:你也可以把计算机内存想象成一条长街上一间间房子,每间房子上面都有且只有一个唯一的编号,房子可以存放数据。

如这里的首元素的内存编号是 5240768,第二个元素的内存编号是 5240772,
这里也需要知道一点,这里的编号,只是该数据存放的首地址,只需要知道首地址就可以获取整个地址的值。
其他:

一 : 数组定义时候的方括号 [] 和 花括号里面的常量
上面我介绍了数组的定义方式和例子,如: int arr[10]这里的10表示整个数组长度为常量10[ ]也叫做下标运算符,如上面介绍的那样,你要索引哪个元素,就直接写该元素所在的位置即可。
这里要强调一点,数组的
下标(index)
的范围是 0 ~ size – 1
下标下界是0,上界是 size – 1 如果应用不当,就会出现越界的错误。
在现在的学习阶段,方括号里面的内容必须是一个常量,而不能出现像

int n;
int arr[n];

二:数组的初始化
数组的初始化是在其定义的时候就应该执行的,如,为5个已经知道的整形数据进行排序,那么:

//正确
int ArrNum[5] = { 
    43, 65, 32, 774, 899 };
//而不能用下面这种方式
int ArrNum[5];
ArrNum[5] = { 
    43, 65, 32, 774, 899 };

因为对于 ArrNum[5] = 来说,这是一个赋值操作,将右值赋值给左值,一切常数、字符和字符串都是右值。在这里 { 43, 65, 32, 774, 899 }; 并不是右值的一种,所以这是错误的。
另一个错误是,ArrNum[5] 下标为 5 这个元素实际上并不存在的。原因上面 “其他,第一点”有讲述,这也属于数组的越界

有数字类型的数组初始化,也有字符类型数组的初始化。 例如

//方式一,单个单个元素的赋值,用单引号引起来每一个字符
char Name1[9] = { 
   'H','y','d','r','o','g','e','n'};  //H2

//方式二,直接用双引号,将字符串赋给变量Name2
char Name2[9] = "Hydrogen";
char Name2[9] =  { 
   "Hydrogen"}; 						//

在这里插入图片描述

三:数组的越界
这里讲的数组长度存在一个上界,一旦超过了这个界限会如何?
前面讲述到了,一旦数组定义完毕,系统就会为其分配它长度大小的空间地址。
而一旦超过了这个大小,就会发生一些未知的错误,也就是所谓的越界
这里用一个例子来说明下越界后数组内部的值的情况:
在这里插入图片描述
由运行结果可以知道,当数组的下标超过了上界后,其后面的值都是不确定的。


以上是数组的三个要素和一些补充,既然有数组了,我们如何为其赋值呢?总不可能采取:

scanf("%d %d %d...", &arr[0], &arr[1], &arr[2]...);

这样冗长的表达式吧。
考虑到数组当中,如果要对数组其中的某一个元素赋值的话,我们可以利用对应的下标索引出。即:

arr[0] = 23;
arr[1] = 44;
arr[2+3] = 412;  //方括号里面可以有加减操作
arr[2*3] = 32;   //也可以有乘除
arr[n--] = i;    //也可以是变量(变量的值对于数组来说有意义。)
...
arr[size-1] = 90;

在结合前面学习到的循环结构,是否可以将两者结合起来呢?
答案当时是可以的。
C语言中,循环有三种:

for( 表达式1; 表达式2; 表达式3) { 
    语句块; }
while(表达式){ 
     语句块; }
do { 
    语句块; }while(表达式);

每一个循环结构都需要一个循环变量来对其进行控制,如 i, k, j 每一个循环体,
对于循环变量来说:
1:其值都需要提前指定其大小(循环从哪里开始)
2:循环变量的上限(也就是循环到什么时候结束)
3:循环变量是如何改变的(如每次执行完循环体后,循环变量自增1,或是自增2…)
对于循环结构的 for 和 while 来说,执行第三步,都是在执行循环体后在执行的。
对于do-while()结构来说,无条件的执行一次。

讲到这里,很自然的就可以将循环结构和数组联系起来了。
对于数组的赋值,由于其下标可以用任意小于其上界的数字进行索引,那么我就可以借助一个循环变量 i , 来对其进行元素的索引。
可以这样理解:一个数组定义好了,在内存中已经分配了连续的空间地址,这个相当于一条街上连续的几户人家定了同一个公司的牛奶,然后每次配送员,只需要携带定的数量牛奶,一个接着一个送过去就可以了。
用代码写出来如下:
在这里插入图片描述
这里的循环变量 i 从 0 开始,也就是索引数组的第一个元素,即其下标为0的元素。
循环体的内容是将数据写入对应下标,每次执行完循环体后,循环变量自增1,即转到数组的下一个下标。这样循环执行,直到循环结束位置。

那对于字符数组呢?
字符数组有三种输入方式
一:用循环结构一个字符一个字符输入
在这里插入图片描述
二:调用gets()函数
C语言之数组的基本知识
三:调用scanf()函数
在这里插入图片描述
这里注释掉的两种输出方式都没啥问题,但是有个前提是有结束符号。
细心的人可能注意到了我这里第一种方式多了一行

arr[i] = '\0';

‘\0’是啥?有啥作用?
这个就是我上面提到的结束符号,输出的时候告诉编译器我这里结束啦,不可以再往后结束啦。
对于gets(), scanf(); 两个函数,在你输入字符串结束后,会自动在字符串结尾加上’\0’,这个是编译器帮你做到的,无需担心。<缓冲区和scanf的缺陷参见上一篇内容>
但是对于getchar();函数来说,却没有这个功能,它仅仅只是从缓冲区读取字符给你,也就是说,在最后你需要自己加上一个结束标记。


以上是一维数组的一些基本知识,以及一些补充。
对于二维数组来说,它的定义比一维的多了一个方括号:

int Arr[4][4]; 

一维数组像一条线一样,只有长度;二维数组有行,有列,可以看成有长和宽的矩形一样。
数据大小就是LH,如上面的二维数组,长度就是44=16。
在内存分配上面,是否也是按照二维的样式来分配呢?答案是否定的,它分配内存也是开辟了连续字节的。
在这里插入图片描述

这里首内存地址编号是:9828620
尾内存地址编号是: 9828680 < 9828620 + 15 * 4 = 9828680)(减去首地址这个元素)
可以看到这也是连续分配的。
值得注意的是,在输入,输出二维数组的时候,需要用到双重循环。
一维数组需要一层循环,二维两层,三维三层。
对于二维数组的理解,可以结合一维来。(二维比一维多了“行” 这个元素)。
在后面的学习中,可以将数组和指针联系起来,在更后续的学习中,可以联系到数据结构里面,这里以后学习到了自然会明白。

(如有错误,欢迎指出)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/157321.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 信号带宽和信道带宽_信号带宽大于信道带宽

    信号带宽和信道带宽_信号带宽大于信道带宽信号带宽:一个信号可以分解为一系列不同频率正余弦函数的加权和。带宽,就是那些对应的加权非零部分对应的三角函数的频率宽度。信号频谱的宽度,也就是信号的最高频率分量与最低频率分量之差。例如,比如我们学过的sin(x)函数,就是一个信号,sin(x)是一个三角函数,所以其若用傅里叶级数表示,加权非零部分就是该信号本身。其对应的信号的带宽就是1HZ.(因其只有一个频率)。再例如:一个由数个正弦波叠加成的方…

    2022年10月11日
    4
  • python中二维列表取值_python二维元组元素的提取

    python中二维列表取值_python二维元组元素的提取直接切片是不行的:&gt;&gt;&gt;a=[[1,2,3],[4,5,6]]&gt;&gt;&gt;a[:,0]#尝试用数组的方法读取一列失败TypeError:listindicesmustbeintegersorslices,nottuple我们可以直接构造:&gt;&gt;&gt;b=[i[0]…

    2025年7月1日
    7
  • c语言中的short是什么意思_c语言中short占几个字节

    c语言中的short是什么意思_c语言中short占几个字节Java中没有Int32,Int64,,只有int,short,longJava中int就代表Int32,short就代表Int16,long就代表Int64首先,几个基本的关键字:Int16=short,占2个字节.-32768~32767Int32=int,占4个字节.-2147483648~2147483647Int64=long,占8个字…

    2026年1月28日
    5
  • python中的set(),zip()以及map()函数

    python中的set(),zip()以及map()函数set、zip和map函数均为python的内置函数。(1)set()用法:set(interable)用来创建一个无序不重复元素的集合。可以对其进行集合的一系列操作,例如求差集、并集和补集,利

    2022年7月5日
    21
  • HttpCanary下载_网页自我介绍模板

    HttpCanary下载_网页自我介绍模板前言首先,我们无论学习哪个框架,都要带着问题,带着思考去学习思考1:HttpRunner是什么?思考2:HttpRunner的设计模式是什么?思考3:为什么我们要学习HttpRunner?他的

    2022年7月30日
    8
  • EXCUTE方法executeUpdate「建议收藏」

    EXCUTE方法executeUpdate「建议收藏」“Execute”是JAVA语言的一种,作用是执行动态的SQL语句或非运行时创建的PL/SQL块,动态创建和执行SQL语句。Execute语句的方法1方法executeQuery用于产生单个结果集的语句,例如SELECT语句。被使用最多的执行SQL语句的方法是executeQuery。这个方法被用来执行SELECT语句,它几乎是使用最多的SQL语句。2方法executeUp…

    2022年10月20日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号