数组、字符、字符串

  • 前言
  • 数组
    • 什么是数组
    • 如何定义一个数组
    • 计算机如何储存数组
    • 数组的使用
    • 由一维向高维拓展
    • 数组的初始化
  • 字符、字符串
    • 什么是字符,字符串
    • 字符、字符串的输入与输出
      • 关于格式转换符
      • ASCLL码
  • 结语

前言

在之前的学习中,我们初步知晓了如何去定义一个整数型的变量,但是,当我们需要的变量数目增加时,单个的定义就已经不能满足我们的开发了,这时,就需要使用数组来直接划分一块连续的内存区域来方便我们储存数据

数组

什么是数组

数组可以存储一个固定大小的相同类型元素的顺序集合

你可以将我们C++中所有的数据类型比作房子的户型,而单个的变量就像独立小别墅,只能容纳一个户型。而数组就如同现代电梯公寓,在同一栋楼中,可以容纳多个相同的户型。而我们对数组中单个元素的访问,就相当于我们去访问公寓内某个特定的楼层的特定户型

如何定义一个数组

从上面可以类比得知,我们在定义数组值,必须给数组起一个合理的名字,并且要指定数组的大小,就如同修房子,我们不仅要对楼栋编号,而且要计划好楼层的数目
代码如下

int a[100];

在这一行代码中,我们定义了一个名字叫做a的整型 一维 数组,并且规定了其能容纳100个整型变量

计算机如何储存数组

在此之前,我们应该知道,C++各种数据类型占用的字节数与二进制位数,并且应当了解1Byte = 8b,1KB=1024B,1MB=1024KB,1GB=1024MB

然后,我们会有这么一张表

常见变量类型 占用字节 占用位
bool 1 8
char 1 8
short 2 16
int 2~4 16~32
long 4 32
long long 8 64
float 4 32
double 8 64

在这里特别提醒,int并不是任何时候都是占4字节,在早期16位电脑或者如今一些MCU上,int是占用2字节

这里附上一张int类型数组的内存占用图片

可以看出,在int类型的数组中,我们的程序在内存中划分了一块连续的空间,并且以四个Byte为一组,分配给数组中的每一个元素
同样,我们也可以用代码访问内存地址来直观的看到

#include<cstdio>
using namespace std;
int arr[10];
int main()
{for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)printf("&arr[%d] = %p\n", i, &arr[i]);return 0;
}

运行结果(结果不一定相同):

&arr[0] = 000000000040c040
&arr[1] = 000000000040c044
&arr[2] = 000000000040c048
&arr[3] = 000000000040c04c
&arr[4] = 000000000040c050
&arr[5] = 000000000040c054
&arr[6] = 000000000040c058
&arr[7] = 000000000040c05c
&arr[8] = 000000000040c060
&arr[9] = 000000000040c064--------------------------------
Process exited after 0.04451 seconds with return value 0
请按任意键继续. . .

sizeof实际上是获取了数据在内存中所占用的存储空间,以字节为单位来计数

数组的使用

任何东西都是拿来用的,如果不能很好的使用这些工具,那么工具便失去了其存在的意义
但是,在使用数组之前,我们应该明白以下几个概念,再此,我们以定义数组**int a[10]**为例
1:int 声明了我们定义的数组的变量类型,在这里时整型
2:方括号前的字母a,表示了我们的数组名称叫做a,这里名称大家可以随意取名,但是要注意符合C++变量名的规范
3:后面的[10]表示我们定义的这个数组可以容纳10个int类型变量
4:当我们想要调用数组内的某一个元素时,我们应该在调用时加上数组的下标,例如,我们要调用a数组的第5个元素,那么,我们应该使用a[4]
5:在调用数组元素时,我们应该特别注意,我们定义的时候,方括号内表示的是元素个数,但是在调用时,方括号内是元素下标,而数组的下标是从0开始而非1,这也就是为什么在上面,我们调用第5个元素,数组下标却为4的原因,如果我们调用a[10],这是第11个元素,但我们的数组有且只有10个元素,这时,我们就访问到了不存在于数组中的一个内存地址,我们将其称为数组下标越界
6:为了防止我们的数组在实际使用中出现越界这种尴尬情况,我们一般会将数组的大小多开5~10,例如,我们只需要10000个元素,但我们的数组可以开10010个元素来防止越界

学习了理论,我们就可以进行实际的操作了
例如,我们需要统计某位同学的高考成绩,这里以全国卷为例,我们依次输入语文、数学外语、理综,要求输出总分和理综,并以空格分隔开,代码如下

#include<cstdio>
using namespace std;
int a[10];int main()
{for(int i=1;i<=4;i++)scanf("%d",&a[i]);int sum=0;sum=a[1]+a[2]+a[3];printf("%d %d",sum+a[4],a[4]);return 0;
}

在这个代码中,我们几乎包含了数组的所有用法,大家可以仔细的品味

由一维向高维拓展

既然有一维数组,那么是否也有二维乃至更高维的数组呢?
答案是肯定的,就像同一层楼也可以容纳不同户型的原理,我们的数组也可进行拓展,代码如下

int b[10][10];       //二维数组
int c[10][10][10];  //三位数组
int d[5][5][5].....;//请充分发挥你的想象力

数组的初始化

在我们的代码中,我们时常要对一个数组赋予一定的初始值,这个过程,称为数组的初始化
实现初始化的方式多种多样
比较常用的有如下几种:
1:最简单,也是常用的方法就是将数组放在主函数外部进行定义,这时,我们的数组会被系统自动初始化为0
2:另外一种方法就是使用上一节讲到的循环,我们可以人为的写一个循环来一个一个的对数组的元素进行赋值,也就相当于对数组进行了初始化
3:此外,我们可以调用 < cstring > 中的 memset 函数,通过简单的设置参数,让系统自动完成赋值
4:数组也可以向普通变量一样,在定义阶段就给其赋予初始值,但是其与普通的单一变量赋值略有不同,样例代码如下

int a[5]={0,1,2,3,4};
int b[2][2]{{1,2},{3,4}};
int c[10]={1,2,3}
//值得注意,在我们对数组c赋值的时候,我们并没有对其全部赋值
//这时后面我们没有赋值的区域会被系统自动赋值为0

memset函数用法
结构

void * memset ( void * ptr, int value, size_t num );

可以看出,memset是一个没有返回值的函数
其内部包含有三个参数
第一个是以指针形式传入的数组
第二个是需要初始化的值
第三个是需要初始化的数组的长度
这里附上cplusplus中的样例和运行结果
样例:

/* memset example */
#include <stdio.h>
#include <string.h>int main ()
{char str[] = "almost every programmer should know memset!";memset (str,'-',6);puts (str);return 0;
}

运行结果:

------ every programmer should know memset!

字符、字符串

什么是字符,字符串

在我们的现在程序中,如果输入输出都只有单纯的数字,在我们需要读取一个英文字母时,单纯的数字显然就不能满足我们的需求
于是,这时我们就需要定义、读取、处理、输出其他不同类型的变量

于是这里先引入字符变量char

在C++中,变量的类型十分丰富
比如整数类型:short、int、long、long long
浮点类型:float、double
字符类型:char
布尔型:bool

当我们需要同时存储多个字符时,我们也可以运用定义数组的方式来存储,这时,这个数组就被我们叫做字符串,如char str[100];

字符、字符串的输入与输出

关于格式转换符

要知道,任何数据在计算机中,都是以二进制储存,非0即1,我们在输出或者输入的时候,就一定要告诉程序,我们现在要操作的这个是一个什么东西,系统才能对其进行对应的处理

所以在这里,我们对字符操作就需要用到%c或%s这个格式转换符

格式转换说明符大全
%a(%A) 浮点数、十六进制数字和p-(P-)记数法(C99)
%c 字符
%d 有符号十进制整数
%f 浮点数(包括float和doulbe)
%e(%E) 浮点数指数输出[e-(E-)记数法]
%g(%G) 浮点数不显无意义的零"0"
%i 有符号十进制整数(与%d相同)
%u 无符号十进制整数
%o 八进制整数 e.g. 0123
%x(%X) 十六进制整数<?xml:namespace prefix = st1 />() e.g. 0x1234
%p 指针
%s 字符串
%% “%”

值得注意,对于一个特定的数据类型,我们同样也可以对其进行其他的转换,以一个int或者其它类型进行输入输出
例如下面代码:

#include<cstdio>
using namespace std;int main()
{int a=65;char b='A';printf("%c %d",a,b);return 0;
}

运行结果:

A 65
--------------------------------
Process exited after 0.02979 seconds with return value 0
请按任意键继续. . .

ASCLL码

可以清楚的看到,我们以字符格式打印一个值为65的整型变量a却输出了A
我们以整数型来输出一个存了字母A的字符变量b却输出了65

那么我们可以看出来,我们的每一个符号,其实是以数字的形式被储存在变量中,于是我们有了这么一张图(也是大佬们发明的方法)

这张表被称为ASCLL表,里面对应的代码叫做ASCLL码(美国信息交换标准代码)

讲解完这么多的前导知识,我们终于要开始我们的正题,字符串输入输出了
与整型变量相似,我们的字符与字符串也可以采用相似的格式类进行输入输出操作
代码如下

char s[1000];scanf("%c",&s[1]);
printf("%c",s[1]);scanf("%s",s);
printf("%s",s);

在此可以看到,当我们使用%c对单个字符输入时,与整型一样,用到了&,也就是取地址符,但是当我们有多个字符以字符串输入时,却没有了取地址符,这时为什么呢?
回到我们对于数字储存方式的讨论,当我们在这里创建了一个s[100]的数组后,s实际就代表的时我们首位的内存地址,而[100]代表着我们以这种方式创建100个同样的内存序列,这便构成了一个数组

还是用下面这份代码来解释

#include<cstdio>
using namespace std;
int arr[10];
int main()
{for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)printf("&arr[%d] = %p\n", i, &arr[i]);return 0;
}

当我们把

&arr[i]

改为

arr+i

得到以下代码:

#include<cstdio>
using namespace std;
int arr[10];
int main()
{for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)printf("&arr[%d] = %p\n", i, arr+i);return 0;
}

同样可以得到一个类似的序列(不一定相同):

&arr[0] = 000000000040c040
&arr[1] = 000000000040c044
&arr[2] = 000000000040c048
&arr[3] = 000000000040c04c
&arr[4] = 000000000040c050
&arr[5] = 000000000040c054
&arr[6] = 000000000040c058
&arr[7] = 000000000040c05c
&arr[8] = 000000000040c060
&arr[9] = 000000000040c064

也就时是说,我们传入的是一个内存地址,让我们的输入函数从这个位置开始,我们依次写入我们的字符,直到遇到空格或回车
而在输出的时候,我们也告诉输出函数,从这个内存地址开始,依次输出里面的字符

但是,新的问题又出现了:我们的函数怎么知道在什么时候结束输出
当然是你告诉它
在我们的字符串中,如果是定义的全局变量,里面的数值会被自动初始化为0,对应 ‘\0’,在C++中,这个特殊标记起到告诉输出函数什么时候停止的作用,当我们的输出函数一个一个的像后面输出字符,知道其读取到 ‘\n’ 的时候就停止

那么,如果我们对一个字符串进行了初始化,那么它是不是在读取之后就会把当前输入的与之前初始化的都输出呢?
答案是否定的,因为在每一次输入后,我们的程序会自动在后面添加一个‘\0’来标注,以免出现上述情况

结语

数组是编程中相当基础的东西,我们不仅应当了解其使用方法,更应该去了解它背后的原理与结构,不仅数组,这个方法对于其他语法同样适用,这是我们深入了解代码的重要步骤

一位高中竞赛蒟蒻的大学C++学习日记-第三篇-数组、字符、字符串相关推荐

  1. 一个竞赛蒟蒻,开个Blog玩玩

    做为一只竞赛蒟蒻来开个Blog玩玩 大神勿喷 膜拜大佬们 附中竞赛大佬[按字典序] OrzBXD OrzCSH OrzCXY OrzHYL OrzLDY OrzLZH OrzRTL OrzSZY042 ...

  2. linux课程总结范文,大学课程学习心得体会5篇.doc

    时间: TIME \@ "yyyy'年'M'月'd'日'" 2021年4月21日 学海无涯 页码:第 PAGE 1页共 NUMPAGES 1页 大学课程学习心得体会5篇 学习作为一 ...

  3. 蒟蒻君的刷题日记Day12(线段树专题T4):P8082 [COCI2011-2012#4] KEKS 线段树版题解

    解题思路 看题解区的大佬们用的都是单调栈,本蒟蒻献上一篇线段树题解. 整个数最大,首先位数是确定的,则肯定优先考虑高位大小. 大体思路就是从前向后依次求出每一位的值(好像是废话). 对于第 iii 位 ...

  4. 蒟蒻君的数学学习之路1:斐波那契数列的n种解法

    文章目录 ⭐前言 ⭐一. 递推

  5. 蒟蒻君的刷题日记Day1:CF1A Theatre Square

    文章目录 题目大意 解题思路 代码实现 题目大意 有一个n×mn \times mn×m的矩阵,你需要用若干个a×aa \times aa×a的正方形填满ta. 正方形不能切割,可以超出这个矩阵,但不 ...

  6. 6位有符号补码阵列乘法器_C/C++学习日记:原码、反码和补码

    一.什么是原码.反码和补码 我们知道,在计算机内部存储的带符号数都是以补码形式存储,用补码形式进行运算的.什么是一个数的补码?为什么要用补码?这要从数的原码.反码开始讲.我们以整型数为例,且假定字长为 ...

  7. 大学计算机学习计划书,大学学习计划书500字

    大学学习计划书500字 (23页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.9 积分 大学学习计划书500字篇一:大学学习计划书范文三篇大学学习计 ...

  8. 大学计算机课的学后感,大学课程学习心得体会感想

    大学课程学习心得体会感想 通过每周一次的大学课程学习,我也接触到了更加丰富的英语学习资源,开阔了视野,掌握了利用个人展示这一强大的平台来锻炼我们的心得体会感想.下面是为大家收集整理的大学课程学习心得体 ...

  9. python字符串去头尾_悉尼大学某蒟蒻的Python学习笔记

    About me 本蒟蒻是悉尼大学计算机科学大一的学生,这篇博客记录了学习INFO1110这门课的一些心得,希望能对大家有帮助. To start with 因为计算机只能识别机器语言,所以我们需要编 ...

最新文章

  1. reviewboard搭建
  2. Ubuntu apt安装/卸载软件和设置软件源
  3. hdu 1042 N!(大数)
  4. SQLServer中round函数
  5. java audiorecord_Android 录音实现(AudioRecord)
  6. ef ddl生成不了脚本_如何使用Hibernate从Play生成DDL脚本! 框架项目
  7. 2017 开源软件排行_2017年开源大会精选
  8. 使用DOM4J解析XML及采用Schema校验的方法
  9. CUDA——Ubuntu系统上CUDA和cuDNN的安装教程
  10. jquery 弹出窗口_jQuery弹出窗口和工具提示窗口动画效果
  11. mysql导入sql文件,乱码,一个例子
  12. JS控制浏览器捕捉键盘
  13. AD18 制作PCB封装库时导入其3D模型+下载3D模型
  14. 计算机高效课堂建设,基于信息技术的小学音乐高效课堂的构建
  15. 六万字 HTTP 必备知识学习,程序员不懂网络怎么行,一篇HTTP入门 不收藏都可惜
  16. java itex 打印pdf_【收藏】java使用ITEXT打印PDF
  17. 升级mojave后辅助功能空白无法
  18. 逆向学习路线(推荐书籍)
  19. 模拟htonl、ntohl、htons、ntohs函数实现
  20. VSCode 代码块/全文 折叠/展开 快捷键

热门文章

  1. 微信小程序 全局数据共享 Mobx
  2. JavaScript 内存详解 分析指南
  3. CorelDRAW图片导出变色,如何解决?
  4. 变量之间的相关性研究
  5. 税后收入计算与四险一金
  6. 18位身份证号验证算法的原理以及C#实现和在管理系统的应用
  7. 安装maskrcnn-banchmark时遇到的“AT_CHECK“ is undefined错误
  8. 2020.10.22--AI--立体图形制作、矛盾空间图形设计、3D文字
  9. 代码详解设计模式--观察者模式
  10. 图像对齐讲座—旷世成都研究院 数据策略产品经理——阿里讲座