当前课程知识点:C/C++:从基础语法到优化策略 > Final Exam > Final exam > 2.2 Integers
返回《C/C++:从基础语法到优化策略》慕课在线视频课程列表
Introduce different kinds of integers
大家好 我们这一部分介绍一下整数
整数大家也许以为是一个很简单的知识点 大家都会用
但其实不尽然 这个没有大家想象那么简单
整数 也就是说没有小数部分的数值就是整数
那么C和C++里面它定义的整数类型有这么几种
char short int long long long
那么它们的区别是什么
它们的区别实际上是它们的宽度不一样或者说长度不一样
也就是说它们要存一个int类型的整数在内存或者磁盘上要占多少个字节
它们是不一样的
所以这个顺序基本上是一个从短到长的这么一个顺序
每一个整数它前面都可以加一个修饰符signed或者unsigned
来表示这个整数是有符号的整数还是没有符号的整数
没有符号的话就是说它是正整数 只能表示正数 不能表示负数
signed就表示它可以表示正的和负的都可以表达
默认情况下 如果一般来说你不加signed
就是你不加这个符号
就int 就默认就是signed int可以表示正也可以表示负数 short也是一样
但是有的时候不尽然 我在这给大家举一个例子 就是我遇到的错误
也就说在这里
char char的话一般来说是有符号的
你只是用char就是有符号的这样一个整数
但是有的编译器
在我写的这段代码 大家可以看 里面的数值都是有正有负
那么它应该
signed按说是不用写出来 这就是可以的 实际上在有的编译器里面
实际上在有的编译器里面
如果你不写 你写的char的话 它默认为是unsigned char
就是都是正数 所以这个bug我debug了好久才发现
啊 如果想不犯错误 不妨写上去
像这signed char就不会有问题了
所有的编译器都会把它认为是正数和负数都可以表达
这是我犯的一个错误
嗯 我们来看
每一个整数类型啊 比如short或者int或者long
它到底占几个字节或者多少位 一个字节是八位
实际上C和C++语言里面并没有规定
这个是像Java的话 它是非常明确的规定
int就是32位也就是四个字节
但是C和C++语言里面
语言没有这个规范 不同的编译器不同的平台会给出不同的答案
但现在来讲基本上来说int是32位
也就是四个字节 基本上所有的现代的系统都是这个样子的
当然 就是说特别在short或者long的时候
如果你不确定 或者你的系统要跨平台等等
最好是事先做一下计算或者做事前测试一下这个系统是多少 这样的话不容易出错
我很多年前也遇到过这样的问题 我也是写了一个程序
然后呢 结果运行总是不对
因为曾经这个程序在很多系统上都运行过 都是没问题的
但是在后来把它移植到一个很小的相机里面去 它就是不对
debug了很久好几天
最后发现是因为它里面的int是16位的导致的
之前我没想过这个问题竟然发生了 发生在我身上
所以说呢 要让你的程序写的很稳定很好
你必须考虑到不同的平台不同的这个长度的情况
你必须考虑到不同的平台不同的这个长度的情况
好 我们来看个例子
就怎么去用这个东西 就前面我们讲到
不同的整数 它的长度是不一样的
那我们怎么去判断它的长度呢
我们可以使用sizeof Operator就是操作符
可以这样来写sizeof (int)
它就会返回int是占几个字节
如果也可以这样 不加括号加个空格
我个人喜欢是上面这样 这种看上去像一个函数容易理解
下面这种的 它就是更多话的像一个operator 就是一个操作符
两种方法都是对的 我们来看
所以说我们采用这个的话 我们就可以计算出int是占几个字节
我们要申请内存如果要申请多少都可以算出来了
嗯 这个是一个很重要的这个操作 就是计算一些东西的大小
而且它也是一个key word在C语言里面 sizeof是保留字 你不可以用
那么比如说 我们怎么去测试呢
那么我们来看看这个例子 limits这个例子
好 这个
在这个例子里面 我们来看
我们使用了一些宏 来用这个宏来定义这个INT_MAX
顾名思义 它是一个int的最大值是多少
那这个宏是哪定义的呢 实际上是在这里面定义的
在这里面定义的啊
那么还有short最大值是多少 long的最大值是多少 那么long long的最大值是多少
这个这些宏就是根据你的编译器你的平台这样来决定的
每个平台不一样 你可以这样来取出它的最大值来
如果你想要知道int是占几个字节 那你可以用sizeof int
然后呢 就打印出int is多少个字节
如果是short是多少 因为刚才我们这个类型是short
那么可以这样 在这个里面我们可以看
上面这个参数是int 是个类型 下面是个变量
这两种操作都可以 变量的话你也可以这样加个括号啊
这样也是没问题的 都是对的
这也是C++语法比较灵活的地方 就是让你很多种写法都对 条条大路通罗马
long的话是下面这个一样的 long long是多少 那就可以打印出来
同样的 我们可以打印Maximum values 就是最大值
int是多少 刚才我们获取的这个int
当然我们也可以直接把这个INT_MAX这个宏
写在这个INT最大值这 这样结果是一样的
那或者说short也是可以 short是最大值 long是最大值 longlong的最大值
还有最小值 INT_MIN的最小值是多少
还有就是每个char是有多少个位 那我们可以打印出来
我们这个程序编译一下
然后看一下 g++ limits 应该进入到上一层目录里了
好 编译完之后生成a.out文件
我们运行 我们来看运行结果是这样的
它说int是四个字节 在我的这个电脑上
short是两个字节 long和long long是八个
但有的系统里面long是四个 不太确定
所以说用之前 特别是long 用之前一定要注意
那么int最大值是这么大 那基本上就是 我们说2G 两GB的这个字 那就是二
如果是无符号 那就是4字G short那就小很多
long的话最大值是到这么大
因为是它是多少 long的话是八个字节
所以说它能表达这么长的数值 这个整数
long long和long是一样的 所以说这样
最小值 int的最小值是个负值
Bits per byte是8
一个字节有八位
这样的话我们可以通过这种方式把我们这个系统里面的相关的
就是跟字节类型相关的宽度就可以获取到了
我们这个例子 sizeof的例子啊 我们再来看下一页
就是说我们前面有例子里面有一些宏 就是比如说INT_MAX
这些宏其实都是定义在一个头文件里面
定义在这个头件文climits这个头文件里面 它的定义有很多
类似这些 就我这列了一些
然后呢 每一个跟编译器相关 跟系统相关
它都会提供这么一个文件
然后呢 你就可以用它就可以知道
哎 你这个平台的编译的时候是怎么样 那么怎么用呢
那么怎么用呢 我们就是用include 前面讲的去来用它
那么我们前面讲了整数定义 然后那就初始化整数
整数的初始化怎么初始化
初始化按说是很简单的一件事 我们直接用等号给它赋个值就行了嘛对吧
这是很简单的
实际上你复杂初始化的话 我们可以直接把一个这种 一个常量把它赋值
也可以用一个宏 把一个宏赋值 也可以是变量 就把它赋上去
赋上去就说你怎么赋 那我们来看几个例子吧
这个初始化的这个例子
好
初始化里面我们来看 主要是下面这部分
嗯 前面有 前面这个只是打印啊 这一块它就是一个初始化
它定义了声明了一个变量 然后呢把这个值赋给它 也说这个变量的初始值就是INT_MAX
然后这个是打印 这个没事 那么这个里面还可以这样来初始化
hamburgers=24 也就是说你可以加个花括号 这样是可以的
花括号本来这样是最简洁 其实我个人更倾向于这样啊 这样简洁
所以说你加上花括号之后呢 这是新的标准啊 你可以这样
然后你可以打印出来
还有一种就是这个是C++11的标准 这样来初始化
这种初始化方式呢 我个人不太喜欢
因为看上去没有上面这种或者说这种来的清晰
如果你是整数 我建议你这样容易理解一些
或者这些也是可以的 这个也是跟刚才这个实际上是一样的
这种初始化呢也是可以的 那它就是默认你就是零了
它又是把它设成零 然后我们可以把它编译一下
编译之后
我们可以用两个&符号
就表示如果前面这个命令执行没有出错 那我们就会执行后面的那个命令
哦它这边说出错了 哪儿出错了呢 它说这个地方出错了
它说这里面应该放个标量 不应该是空的
不应该是空的 为什么呢 我们前面说C++11标准
我们来试试 我们用C++11标准来编译一下试试
好 怎么指定C++11标准 -std=C++11
编译通过 也就是说这个写法是C++11标准支持的
但是旧标准是不支持的 所以就会出错
当然你可以就是说 std指令就可以指定你的编译器
编译的按照哪个语言规范来编译
我们比如说按照17版本没问题 那如果是03版本
就出错了是吧 也就是说新版本规则更多
这就是C++的这个特点 新版本加了很多新的规则
所以最后我们编译器编译的时候我们要指定一个标准
这个的话 我现在用的编译器没指定 就是默认它是03标准去编译的 看来是
好 这个是初始化的部分
这是11标准里面的 那就说我们可以用一个花括号去初始化
花括号可以是留空 我们刚才例子也看到了
我们刚才例子也看到了 如果留空采用11标准就可以编 否则就不能编
还有一个就是无符号的类型
无符号的话就是说只能是零或者正的数值 不可以是负的
这样的话 有符号可以表示正和负 无符号只能表示负正的 为什么还要用无符号呢
那它的优势就在于你没有符号位 你所有的比如说八个字节 int是32位
那你32位全部用来表示数值 而没有
像如果是有符号的话 第一个是符号位
只剩下31位来表达数值 那它最大就是2的31次方了
那如果你是个有符号的 最大就是2的32次方
所以说它表达的范围就大了很多
我们这里面也来看一个例子 就说
我们用整数的时候 要特别小心 要特别小心
问题就在这个例子里面给大家看一下
如果不小心会导致什么问题
好在这个例子里面 在这个例子里面我们来看
这边sam 它是个short类型 也是16位的
最大值是2的15次方减1
那我们把这个最大值赋给它 然后呢
sue把这个值赋给它 值是一样的 但它是unsigned short
也就是说unsigned short 它的取值范围是0到2的16次方减1
也就是说它比这个short要翻倍了 所以我们把它打印出来
比如说
sam是多少 “Sam has dollars”
假如他们有钱 然后呢给每个人加一块钱
大家知道这个sam这个值已经是最大值了 你再加一块那是多少
那就饱和了就越界了 那个值就就超出了范围
那怎么办 它会怎么处理 我们来看
等一下看结果 这个加1的话那毫无疑问它在范围内应该是没问题的
这是第一个例子 第二个例子呢
是sam置零 zero
啊zero是什么 我们来看这个宏定义 zero就是零
这个地方因为是用了这个宏 你跟这个是等价的
然后cout打印"Sam has"<< sam <<"dollars and Sue has"<< sue
也是0 dollars了
那么"Take $1 from each account."
就每个人打印减1 那我们减1是多少
那么如果sam的话 它是因为有符号你减1就是负一嘛
好理解 那么0减1在这个时候会是多少
0减1是多少 那我们来看一看
嗯 我来编译一下
没错 然后运行
我们可以看 当它是最大值的时候 它是有符号的最大值是这么大
然后它是32767 然后我们加一块
32767+1就变成了负32768
这是为什么
32767有的同学也会认为加1 越界不能表达
那继续是32767呗 就不要增加了
它实际上在C++里面它不会这样 它会变成一个负的很大的数
这个呢 32767+1就32768
那我们来看如果它们都是零
如果分别减1 它是有符号的
减1之后就是负1 这个无符号的减1之后就会变成65535
为什么是这个值 我们看一下这个解释
我们这个就是要回到就是说整数的表达方式里面
整数的话 我们来看 如果你是unsigned short
那么它的零就是全是0 1就是这个1
它的最大值就是正数嘛 符号位为零然后后面填满就是32767
最小值呢
这个最大值就是那个short最大值 不是unsigned
如果是unsigned short最大值 那就是全部填成1 它没有符号位
这些是没有符号位的 第一位都不是符号位
全部填满就是65535也是2的16次方减1
这是无符号的short 有符号的short
零还是零是一样的 如果全部填1那它就是负1
如果 100000 那它就是负32768
这个地方 这个是整数的表达方式啊 那我们来看
如果一个有符号的 假如这个值是个有符号的
那我们加1之后会变成什么
其实不管有符号没符号 只要这个值加了1
那它就会变成进位往上加 进位进位往上进
也就说 在实际上加1的操作里面 它不区分符号和不符号
就直接加 最后的结果就变成10000000
它就得到这样的结果加1 加1如果是在
这个无符号的里面那没问题 你加上1之后1000000
那么就是32768 没错
那么如果前面是个1 那它就变成一个有符号的
那么就是1000000 那么如果是你有符号 那就会变成负32768
会变成负的了
同样减1也是这样的 如果是有符号的0减1就变成负1嘛
负1就是这个值 这是负1
但是呢如果它是个无符号类型
你这个值在无符号的表达里面那就是65535呀
也就是说实际上在整数运算的时候它不管你有没有符号
它就是这样去算 它就是假设没有符号
所以呢 这样在赋值的时候 这样就刚才的例子里面
就是到了那个边界的时候 要特别的小心
好 嗯
那么就是怎么来选整数的类型呢
那么那既然容易越界 我们是不是就可以说
选越大越好 范围越大 那越大越浪费内存
所以说我们要去选最合适的 最常用的实际上是int
有unsigned int 或者说如果你想保持节约内存 你可以用short
嗯 它的意思后面我们会提到 你用short只是一个short变量
它并不能节约内存 没有太大意义
当你是一个很长的数组的时候 short数组和int数组
那它就会真的节约内存
只是一个变量 一般是无所谓的
如果你的范围很小 就是0到255或者说0到127那你就用char
还有就是我们来看就这个例子 这个例子里面
不同的机器上 也就是说同样的代码在不同的机器上可能输出不一样的结果
这是我们要注意的 前面我也介绍了我过去经历过的一些bug
是由这些引起的
如果你们以后遇到莫名其妙的bug
不妨往这个方向去想一想是不是由于这个原因引起的
好
下一个就说这个Integer Literals怎么写呢
整数怎么写 怎么去表达
那不很显然吗 我们都会用整数1234我们都用了很久了
其实我们前面的例子里面都是十进制的表达
如果八进制六进制怎么用啊
十进制我们对于人来讲是非常友好的 我们容易理解
那么在过去老的Unix系统里面经常用八进制
还有十六进制也是非常的流行的 十六进制可以每一个数值就表示四个bit
那两个16进制数就是八位 它就跟计算机就是更接近 也容易去用
所以说呢如果你只是1234像我们前面写 就十进制这样写
如果你的一个数字前面加上个0 那么它就会变成八进制
如果你的一个数值前面加个0X 大写 小写都可以
那么它就是个十六进制 所以呢 写的时候千万注意整数前面不要加0
那也会就变成八进制啊 我们来看下一个例子
我们有几个例子来展示 第一个就是hexoct1这个例子
另外一个hexoct2 这两个例子我们来看它引起的问题
第一个呢 我们有三个整数变量 赋值42
这就是十进制的42 这个是十六进制的42
这个是八进制的42
然后我们把它打印出来 它们的值看是多少
嗯如果编译成功 我们就直接运行它
好 编译成功直接运行了
编译&运行一次完成它的条件 这个意思是说前面这个命令
如果没有错误 那就运行后面这个 如果有错就停下
那么我们来看42十进制的 那就打印42
因为我们的打印采用的是十进制打印
嗯这个的话 十六进制的42实际上在转成十进制就是66
八进制的42就是34
所以记得你在去写着数值的时候
不要轻易前面加个0 加0这个意思就全变了
然后你会莫名其妙为什么值被修改了
你以为它是42 实际上它是34
所以说这个是一个注意的点
另外一个例子 我们这三个值都赋给十进制的42
然后如果我们想要去打印的话 打印出来
那么如果是打印十进制 那我们就直接cout这样就可以了
如果我们要打印十六进制
那就要执行这条命令先执行 执行完之后
后面的cout输出的内容就会按十六进制去输出这个数值
如果oct的话 那你就是按照八进制去输出 我们运行这个例子
看三个42 不同的输出
42是十进制的42 那42转成十六进制就是2a
转成八进制就是52 这是它的进制的转换
那么我们后面再讲 就是char这个类型
首先呢就是char这个类型 从字面上讲就是characters是表达字符的
其实呢
我们在我们的脑子里 我们应该把char看成一个整数
它就是一个整数
它就是一个八位的整数 可以表示字符 十六位可以表示字符
三十二位也可以表示字符 它没关系
为什么呢 因为每个字符它都编了码
比如说这个
这个编码的里面1就被编成了31
那你把这个char赋成31它既表示整数31也可以表示这个字符1 这样
那么我们来看就是这个表
这个表我相信大家应该相对比较熟悉啊
不多讲 它表达了实际上从0一直到127
127以上的不同的国家有不同的定义
特别是西欧的一些国家 它只用这个字母是无法表达它的语言
它就在这里面又定义了一些他们不同的语言的一些字符
当然现在还有更多的编码方式
比如说中文的编码 又是更长
因为中文不可能用这么几十个字字就编出来了
那么我们来看一看 既然char是一个整数我们要用起来特别的小心
给两个小例子给大家展示
第一个是chartype
这个很简单啊 这个例子我都不去演示了
我们定义一个类型是char类型它就是个整数
然后我们去输入它
然后呢 它既然是char类型 其实呢这个地方内容是整数
但它输入的时候 我们来看它应该是
我输个31它是什么 它是会指的是字母1吗
不是的啊 这个还是运行一下吧
我输个3它就说就是个3 我输个31呢 它还是3
因为它是个char嘛 所以cin只转进来一个字符
第一个字符三 那就是如果我输个1的话呢
我输个1它是字符1 它真正对应的整数char ch里面的值 它是31
我们再来看更多的更详细的例子
这个morechar 这个例子 比如说M 这是个字符
它是个char类型 如果把它的值赋给int i
我们如果把这个打印出来就是ch
因为它是个char 打印的时候它就会按字符去打印 它的值就是i
如果加1然后赋给i 那就是这个ch就被加了1 M+1是多少
就是N 然后打印出来 还有就是
这个呢我们可以就这样打印 我们来看这几种 就put
put打印实际上是打印一个字符的 刚才说M和N
那么put这个N字符那它是put出N的数值
还是就N的编码数值还是N呢 我们来看
我们来看 M对应的编码值是77 N对应的是78
因为我们加了1
那么打印的时候 那么put这个函数
它的打印实际上是它的字符 字符打印出来
好 这个是char
char的话 从0到127我们先说这些
这个编码有一些是可以打印的 有一些是不可以打印的
比如说像这些换行符号 我们用这个来表示
Newline可以表示下一行
还有Tab Horizontal Tab Vertical Tab等等
还有Backspace
在这展示下Backspace Backspace就是后退
那么它对应这个编码值是8
第八个值 如果你把它打印出来 会产生什么样的效果
后退 把后退打印出来是什么效果
这个例子很有趣 你看这个就容易理解有一些命令行的程序
它的光标可以四处移动是怎么来的
这边是打印的一个字符串
然后第二行就"Enter your agent code"
就让你打印一个值 冒号 下划线 下划线 下划线
下划线之后 这里面有很多个下划线 然后后面再跟着
就前面是打印了八个下划线 后面再打印八个/b
打印八个\b就是回退 然后呢 会怎么样
然后你的输入数值把这个值输成long直接输进来
说你输入了什么 我们来看
大家来看光标在哪里 光标是在这里
我们本来应打印到后面去了 对吧
按说光标应该在最后面 在这个位置
但是呢 因为我们又后退了八次
就是/b八次 所以说呢这个被我按了方向键 它输进去了
按了八次 所以说它光标就后退八次
那我们说我输进去343
它就拿出来 因为它读的时候
第一个是一个刚才不小心按的方向键 所以说读入失败就是零
我们再来一次 343 好 它说我是刚才输进去的是343
所以也就是说这个可以控制光标的运动
也就是说这些符号实际上是可以打印的
虽然不一定是可见的字符 但是它可能对应特定的行为
More About char 就是说char的话
signed char就是负128到127
unsigned char就是0到255
这个具体怎么用 那刚才我们讲char的话表示的是字符
那么如果是中文还有一些其它的文字
因为全世界这么多文字只有英语可以是26个英文字母那样表 达
那怎么办 我们可以使用w_char这个类型
或者更明确指出来是16位的编码还是32位的编码
那么用这个来表示
它的长度就是一些中文啊 其它的文字可以
这不细讲
还一个就是整数的类型 也不能完全算整数吧 基于整数
它是波尔类型 boolean
这个类型大家注意一点点 就C和C++的区别
这个类型里面是C++的类型 C语言里面没有布尔类型的啊
然后还有就是布尔类型它表示0和1
那是不是说我只要一个位一个bit就对了就够了
是的
一个bit就可以表示0 1 就表示出true or false
0就是false true就是1
但实际上一个波尔类型的变量
它占的内存占的存储空间是一个byte 不是一个位
它就浪费了七个位只用一个
你可以这样想 我们赋值用起来是这样的
int然后赋一个值 然后false赋一个值
同时呢我们可以这样去转换
bool start等于-100那么它start会是多少呢
它是有类型强制转化 它会变成true
也就是说只要这个赋的值不是0 它都是true 都是1
要注意的是
还有一个最后的就是说所有的我们这些类型啊
我们刚才讲的整数类型 包含后面我们要讲的浮点类型
我们都可以前面加一个const的修饰符
const修饰符为什么要加它 我们可以使用宏来define
一个不变的量 一个固定值 比如说数学函数里面的π
数学变量里面的π3.1415926 那
那它可以使用这个define定义出来一个很长的整数
那么我们在C++里面更多推崇用const
const int Months=12
比如说我要表示一年有多少个月 那我用const int Months
那么一旦定义好这样写好的之后呢
Months这个变量就不可以被修改了
它的值就是固定为12不可以变啊 这样
如果你这样写const int toes 然后你想去赋值
首先你这样去赋就赋不对了
而且你这样const int toes
你这样去做呢 编译器很多时候会报错说你没有初始化它
你既然是const 那就定义的时候就把它初始化了 一步到位
大家课后可以去试一下 如果你去把这两行代码
甚至说只把第一行代码写到你的C语言的源文件里面
它会发生什么 是编译错误还是什么其它的错误
这是一个我们留的一个小作业吧
-Quiz 1
-Quiz 2
-3.3 Relational expressions (> < ==)
-3.5 Branching statements (if else)
-3.8 break and continue statements
-Quiz 3
-4.4 Structures, Unions and Enumerations
-Quiz 4
-5.3 Allocate memory: C++ style
-Quiz 5
-6.3 Recursion and pointer to functions
-Quiz 6
-Quiz 7
-8.1 C/C++ with ARM development board
-Quiz 8
-9.2 Constructors and destructors
-Quiz 9
-10.1 Operators in cv::Mat in OpenCV
-10.4 Automatic conversions and type casts for classes
-Quiz 10
-11.1 Dynamic memory and classes
-11.2 New and improved String class
-11.3 Using pointers to objects
-Quiz 11
-12.2 Static and dynamic binding
-12.3 Access control: protected
-12.4 Inheritance and dynamic memory allocation
-Quiz 12
-13.1 Constructor and assignment
-13.2 Classes with object members
-Quiz 13
-14.1 CNN for image classification
-Quiz 14
-15.3 RTTI and type cast operators
-Quiz 15
-Final exam