C++ Primer 读书笔记 第2章 变量和基本类型
C++ Primer 第二章 变量和基本类型
2.1 基本内置类型
C++定义了一组表示整数、浮点数、单个字符和布尔值的算术类型(arithmetic type),此外还定义了Void类型。
算术类型的存储空间大小(指用了表示该类型的二进制位数)依机器而定,C++标准规定了每个算术类型的最小存储空间。实际上,大部分编译器都使用了更大的存储空间。
表2-1 C++:算术类型 |
|||||
类型 |
含义 |
最小存储空间 |
备注 |
||
整型 |
布尔值 |
bool |
布尔型 |
-------- |
|
字符型 |
char |
字符型 |
8位 |
通常是单个机器字节(Byte) |
|
wchar_t |
宽字符型 |
16位 |
用于扩展字符集,如汉字 |
||
整数 |
short |
短整型 |
16位 |
||
int |
整形 |
16位 |
|||
long |
长整形 |
32位 |
|||
浮点型 |
float |
单精度浮点型 |
6位有效数字 |
||
Double |
双精度浮点型 |
10位有效数字 |
|||
Long double |
扩展精度浮点型 |
10位有效数字 |
基本内置类型是C++“自带”的类型,区别于标准库定义的类型。使用时不需要应用标准库就可以使用。
2.2.1 整型
表示整数、字符、布尔值的算术类型合称为整形。
1. 带符号和无符号类型
除bool类型外,其他类型可为带符号的(signed)或无符号的(unsigned),无符号的取值范围不能为负,有符号取值可以有正有负。
整型int、short、long默认为带符号型。若得无符号型必须指定类型为unsigned。
例如:unsigned long,unsigned int (可缩写为unsigned)。
2. 整型的赋值
若经一个超出其取值范围的值赋给一个指定类型的对象时,结果如何?
1) 对于unsigned类型,编译器必须调整越界值使其满足要求。
编译器将该值对unsigned类型的可能取值数码求模,然后取所得值。
2) 对于unsigned类型,负数总是超出其取值范围。
C++中,
2.1.2 浮点型
就是带小数的数,包括float , double , long double他们之间的区别是取值范围和精度,可以根据你的需要选择合适的类型。
建议:使用内置算术类型
1)char , wchar_t 两个类型虽然都是字符型但区别比较大:
在宽度上来说,一个是1byte,一个是2byte(在linux上实际是4byte)在编码上来说 wchar_t表示unicode编码方式,以上不同说明 wchar_t 可以包含更多内容比如中文,日文等等。
2)当执行整型算术运算时,很少使用short类型,因其可能会隐含赋值越界的错误。
3)char虽是整型,但通常用来存储字符而不是运算。
4)使用浮点数时,建议使用double类型,因其基本上不会有错,在float类型中隐式的精度损失是不能忽视的,而双精度计算的代价相对于单精度可以忽略。
2.2 字面值常量
即常量。只有内置类型存在字面值,无类类型的字面值,故也无任何标准库类型的字面值。
1、整形字面值规则
例:
20 //decimal 十进制
024 //octal 八进制 以零(0)开头
0x14 //hexadecimal 十六进制 以0x或0X开头
通过在数值后面加L或l指定常量为long类型。
通过在数值后面加U或u定义unsigned类型。
没有short类型的字面值常量。
2、浮点型字面值规则
默认的浮点字面值常量为double类型。在数值后面加F或f表示单精度。同时加L或l表示扩展精度。
3、布尔字面值和字符字面值
单词true和false是布尔型的字面值:如bool test = false;
可打印的字符字面值常用单引号定义:如’a’ ‘2’ ‘,’
在字符字面值前加L,得到wchar_t类型的宽字符字面值:如L’a’
4、非打印字符的转义序列
换行符 |
\n |
水平制表符 |
\t |
纵向制表符 |
\v |
退格符 |
\b |
回车符 |
\r |
进纸符 |
\f |
报警符 |
\a |
反斜符 |
\\ |
疑问号 |
\? |
单引号 |
\’ |
双引号 |
\” |
可将任何字符表示为通用转义字符:\ooo,此处的ooo表示三个八进制数字。
如 \7 响铃符 \12 换行符 \0 空字符 \062 ‘2’
也可用十六进制转义字符定义:\xddd
5、字符串字面值
用双引号括起来的零个或多个字符表示。如:“name”
宽字符串字面值,如:L”a wide string literal”
6、字符串字面值的连接
std::cout<<”a multi-line ”
“string literal”
“using concatenation”
<<std::endl;
此语句将输出:a multi-line string literal using concatenation
7、多行字面值
在一行的末尾加一反斜线符号可将此行和下一行当作同一行处理。
2.3 变量
变量提供了程序可以操作的有名字的存储区。
2.3.1 什么是变量
先了解两个表达式概念:
左值:左值可以出现在赋值语句的左面或者右面,如:变量
右值:右值只能出现在赋值语句的右面而不能出现在左面,如:常量、字面值常量
2.3.3 定义对象
1、初始化
复制初始化:用符号(=);
直接初始化:把初始化式放在括号中;(语法更灵活且效率更高)。
注意:C++中理解“初始化不是赋值”。初始化:指创建变量并给它赋初始值;赋值:擦出对象的当前值并用新值代替。
2、使用多个初始化式
对于内置类型来说,复制初始化与直接初始化几乎没有区别;
int a ; // 未初始化,栈区和堆区(函数内定义或者类里面定义)都取随机值,在全局区(全局常量,静态变量)都是全零值。
int b=1 ; // 赋值初始化
int c(1),d(b + 2) ; // 直接初始化,“()”中可为常量、变量、表达式
需要特别强调的是未初始化的内置类型虽然也会有值但是其分配规则导致其值不确定性,所以我们定义内置类型时一定要初始化值而不依赖系统的内部非配规则。
对类类型,有些初始化仅能用直接初始化完成。
内置类型不能隐身初始化,类类型一定要可以隐式初始化。
string a; // 隐式初始化,初始化成了“”
string b = "name" ;
string c(b) ;
string d(10,'a') ; // string类特有的初始化方法,等同于10个字符a组成字符串并赋值初始化给变量d
类类型的初始化其实就是构造函数:
隐式初始化实际上就调用类型的默认构造函数来初始化类型对象;
直接初始化是调用类的拷贝构造函数;
复制初始化是调用赋值操作符重载和拷贝构造函数
2.3.4 变量初始化规则
2.3.5 声明和定义
c++是一门奇怪的语言,我们先看如下代码
void main()
{
std::cout << v1 << std::endl;
}
int v1 = 1;
C++是严格的顺序编译非类对象代码的,当main函数编译时要用到的变量v1还没有执行定义,c++就会抛出异常说使用了未定义的变量v1,若把int v1;语句放到函数前面就没问题。
也可以不改变现在代码顺序而使用声明解决这个编译错误,可以这样修改代码:
void main()
{
extern int v1;
std::cout << v1 << std::endl;
}
int v1;
注意红色新增代码就是一个声明。他的意思是说:HI,系统中的某个地方定义了一个叫v1的int变量,所以你可以放心的使用。
声明是告诉编译器一些信息所以不会分配内存空间也不会产生具体的数据。
声明的对象一旦被使用就一定要在某个地方定义它,否则编译器即使暂时不抛出异常,在编译完毕后发现根本没有地方找到相关定义也一样会编译失败。
以上例子只适合变量,同一个文件中常量在使用前一定要先定义,否则即使做了申明也会出错。
声明最大的好处体现在多文件的编程中,比如说我编写了一个头文件并引入到了主文件中,头文件需要使用主文件定义的变量。由于头文件一般是先于主文件编译执行的,所以就会出现未定义的编译错误,如果在头文件中先声明一下这变量再使用就没有问题了。
除了变量C++还有常量(后面会讲到),它和变量有一些不同
2.3.6 名字的作用域
虽然C++支持面向对象,但并不是完全的面向对象,它也支持面向过程。因此有一些代码是不属于任何类的,比如说main函数就不属于任何类。
针对这种情况变量根据其位置可分为两种:全局变量、局部变量。广义上说定义在类内部(包括类所属函数内部)和函数内部的变量叫局部变量,除此之外的变量就是全局变量了。
用来区分名字的不同意义的上下文称为作用域(Scope)。作用域是程序的一段区域,一个名字可以和不同作用域中的不同实体相关联。
C++中,大多数作用域是用花括号来界定的。一般来说,名字从其声明点开始直到其声明所在的作用域结束处都是可见的。
全局作用域;局部作用域;语句作用域。
C++中作用域可嵌套。
2.4 const限定符
const限定符表示定义一个常量,常量一旦定义则不可更改。不可更改的意思是既不能对常量句柄重新赋值,也不能更改常量对象的数据成员。
因为常量定义后就不能被修改,故定义时必须初始化:
conststd::string hi = “hello!”; //正确
constint i , j=0; //错误,i未初始化 constint bufsize=512;
bufsize=5; //错误,常量初始化后其值不可以修改
常量分为两类:
(1)编译时常量:定义后直接初始化的常量;
(2)运行时常量:要初始化的值必须要通过代码运行才可以确定。
constint a(1); // 编译时常量
constint b = getval(); // 运行时常量值来自一个函数的运行结果
const myclass my(1,"tom"); // 自定义类的常量定义都是运行时常量,因为需要运行类的构造函数
常量初始化之后就不可以做任何的更改操作。
Const对象默认为文件的局部变量:此变量只存在于定义的那个文件,不能被其他文件访问。
// head.h
externint a;
// usend a
externconstint b; // 常量声明语法也可写成 const extern int b
// usend b
头文件中用到两个在其他地方定义的变量,故需要申明一下再使用。
//main.cc
#include head.h
int a(1); // 这样定义的变量可以被其他相关文件(head.h)声明并使用
// const int b(2); 对于常量这样写不行是因为这样定义的变量作用范围只在本文件中,头文件虽然做了声明但无法使用这个常量,应该用下面的语法来定义
externconstint b(2); // 这样定义的常量才可以被其他相关文件(head.h)声明并使用
int main()
{
// do...
}
主文件中定义了头文件需要的对象,和变量不同,常量若在其他地方被声明或使用一定要在定义的时候加上关键字extern,因为常量默认作用范围是定义它的那个文件,变量默认是所有相关文件。
2.5 引用
引用就是对某个对象起一个别名,故作用在引用上的所有操作事实上都作用在该引用绑定的对象上。
引用最重要的作用是函数传参。
变量引用
int val = 1;
int &refval = val; // 引用了一个变量 int &refval2; // 错误,引用必须初始化 int&refval3 =10 ; // 错误,10是个字面常量,常量必须要用常量引用
refval = 2; // 等价于 val = 2
Const引用--(常量引用) constint val = 1;
constint &ref1 = val; // 引用了一个一般常量 constint &ref2 = 9; // 引用了一个字面常量 int&ref3 = val; // 错误,常量必须要使用常量引用,ref3是个变量引用 int var = 2; constint &ref2 = var // 常量引用指向了一个变量,这时候
ref2 = 3; // 不允许通过常量引用来做任何更改操作
var = 3; // 但是可以用原始变量来更改内容
总之,常量引用可以引用常量或变量,但是无论如何都不能通过引用来更改数据内容。
变量引用只能引用变量,用引用可以更改内容效果与用原始变量更改内容是一样的。
对于引用还有一点很重要:非常量引用类型必须严格匹配,常量引用可以在内置类型之间相互引用
double a = 123.4;
int &b = a; // 错误,类型不匹配
constint &c = a; // ok
// 这个操作实际等同于
int temp = a;
constint &c = temp;
如果对非const引用b不做类型匹配限制,b实际就会引用临时变量temp,对b的修改无法反应到变量a,引用失去了其意义。const引用c没有这样的问题,因为它本身不允许修改。
2.6 typedef
用来给某个类型指定一个别名,比如
typedef int whl;
whl a(1) ; // 等同于 int a(1)
typedef 数据类型/标示符 别名
使用typedef的原因:
1) 为了隐藏特定类型的实现,强调使用类型的目的;
2) 简化复制的类型定义,使其更易理解;
3) 允许一种类型用于多个目的,同时使得每次使用该类型的目的明确。
2.7 枚举
枚举是一组可选常量值,既然是一组可选值,说明包含多个常量。
枚举定义语法:enum 枚举类型名{枚举成员1,枚举成员2,…,枚举成员n}
enum val{val1 = 2, val2 = 4, val3} // 最后一个内容没有显示给值等价于 val3 = 5
enum whl{whl1,whl2,whl3} //如果不指定值,默认第一个值从0开始,下一个依次+1递增。
枚举成员是常量:每一项都是一个唯一的const类型值,上面的定义有点类似于:
const val1 = 2; const val2 = 4; const val3 = 5;
由于是const的,所以 val2 = 1 或者 val a = 2; 都不允许。
枚举项和int类型值有对应关系,但是二者只能单向转换,枚举可以自动转成int,而int却不能转成枚举
val a = val2 ; // 枚举之间赋值初始化
int b = val2 ; // 枚举转成int并初始化
val a = 2 ; // int 不能转成枚举,无法初始化
2.8 类类型
一般来说C++吧除了内置类型之外的类型都叫类类型,我们习惯上把自定义的类class称为类类型。 类一般采用先定义类并声明类的成员函数,然后在外部定义成员函数的语法形式。
这部分内容不在这里详述会在后续章节中专门说明。
2.9 编写自己的头文件
从上面的课程我们应该大概知道什么是头文件,一般来说头文件中包含声明而不是定义,但是下面两种情况比较特殊
类定义要放在头文件里。这样如果某个文件需要这个类只需要把头文件include进来即可。
运行时常量也可以在头文件定义,表达式可以在包含文件中定义。这样就能实现在在不同的包含文件得到不同的常量值。
// head.h
int getval();
const int p = getval(); // mast1.cc
#include "head.h"
int getval()
{
return 100;
} int main()
{
cout << p << endl; // 输出100
} // mast2.cc
#include "head.h"
int getval()
{
return 200;
} int main()
{
cout << p << endl; // 输出200
}
有时候某个头文件可能会被包含多次(直接包含+间接包含)。比如文件包含了头文件A,也包含了头文件B,头文件B同时也包含了A,则文件重复包含了A。这个时候如果A中有定义语句就会产生“重复定义”的编译错误,这个时候可以用#ifndef 把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的:
#ifndef <标识>
#define <标识>
...... 头文件代码
#endif
<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h
#ifndef _STDIO_H_
#define _STDIO_H_
...... 头文件代码
#endif
该预定义标示不单能防止头文件被重复包含编译,而且还可以用在不同头文件定义同名对象时出现异常的处理上。
C++ Primer 读书笔记 第2章 变量和基本类型的更多相关文章
- 《C++ Primer》笔记 第2章 变量和基本类型
如果你的数值超过了int表示范围,选用long long 如果你需要使用一个不大的整数,那么明确指定它的类型是signed char或者unsigned char 执行浮点数运算选用double 当一 ...
- 《JavaScript高级程序设计》 - 读书笔记 - 第4章 变量、作用域和内存问题
4.1 基本类型和引用类型的值 JavaScript变量是松散类型的,它只是保存特定值的一个名字而已. ECMAScript变量包含两种数据类型的值:基本类型值和引用类型值.基本类型值指的是简单的数据 ...
- 《C++primer》v5 第2章 变量和基本类型 读书笔记 习题答案
2.1 int,long long ,short 可表示范围和占用内存空间不同.具体与计算机有关. 无符号类型只能表示0和正数,带符号类型可以表示负数,0,正数. float是单精度,一般占用4个字节 ...
- C++ Primer 读书笔记 第1章
1.1 编写简单的C++程序 每个C++程序都必须包含一个main函数,因为main函数是系统执行入口,且main函数是唯一被系统显示调用的函数. 定义函数必须指定4个元素:返回类型.函数名.形参表. ...
- C++ Primer抄书笔记(二)——变量和基本类型(下)
四.const限定符[引用/指针/顶层/常量表达式] const对象值不变,必须初始化,能完成此type的大部分operation. 一般,多文件独立变量,编译初始化仅文件内有效: 除非,(条件:初值 ...
- C++ Primer 抄书笔记(二)——变量和基本类型(上)
一.基本内置类型 base build-in type[算数类型/类型转换/字面值常量] 基本内置类型(算数类型arithmetic type(整型integral type(字符,布尔bool),浮 ...
- C++ Primer 笔记(2)第二章 变量与基本类型
第二章 变量与基本类型 1.基本内置类型包括算术类型和空类型,算术类型分为两类:整型(包括字符和布尔类型)和浮点型: 2.布尔类型(bool)的取值是真(true)或者假(false): 3.字面值常 ...
- 《Linux内核设计与实现》第五周读书笔记——第十一章
<Linux内核设计与实现>第五周读书笔记——第十一章 20135301张忻 估算学习时间:共2.5小时 读书:2.0 代码:0 作业:0 博客:0.5 实际学习时间:共3.0小时 读书: ...
- 《Linux内核设计与实现》读书笔记——第五章
<Linux内核设计与实现>读书笔记--第五章 标签(空格分隔): 20135321余佳源 第五章 系统调用 操作系统中,内核提供了用户进程与内核进行交互的一组接口.这些接口让应用程序受限 ...
随机推荐
- PTF在PET上印刷線路的注意事項
PTF: Polymer Thick Film (聚合厚模),維基的解釋 PET: Polyethylene terephthalate (聚乙烯對苯二甲酸酯),維基的解釋 就如同大家所知道的,相較於 ...
- Keil MDK中使用pc-lint的详细方法
keil MDK版本:V4.03 PC-lint版本: V8.0 关于pc-lint的强大作用,网上有很多,这里不想再复述,只说一句:能通过pc-lint检验的程序不一定没有问题,但通过了pc-li ...
- 元素“Button”不是已知元素。原因可能是网站中存在编译错误,或者缺少web.config文件
最近开发的时候ASP控件都有波浪下划线,提示不是已知元素,搞得挺郁闷的.虽然不影响变异,不过就是不爽. 折腾N久...... 解决了,把FramWork平台换成3.5,问题解决,不知道为啥,求大神指点 ...
- poj1484---判断保险丝是否烧断
题目输入要求: 2 2 10 //设备数n 接下来的操作数m 保险丝能承受最大电流c5 //电器1的电流7 //2的电流1 //反转开关12 //反转开关2 思路:设置一个flag数组,记得每次 ...
- setObject与setValue的区别
在使用NSMutableDictionary的时候经常会使用setValue forKey与setObject forKey,他们经常是可以交互使用的,代码中经常每一种的使用都有.1.先看看setVa ...
- sharepoint 2013 reporting services 远程server返回错误: (500) 内部server错误。
在sharepoint 2013部署reporting services过程中,点击管理中心,server上的服务.系统配置.提示了一个错误: 远程server返回错误: (500) 内部server ...
- Cannot access empty property
致命错误:不能够进入此空值,位于E:\sunlion\web\down\class\db_sql.php 代码 <?php Class TestClass1{ var $class2; publ ...
- Nicholas C. Zakas如何面试前端工程师
转载自:http://www.cnblogs.com/yizuierguo/archive/2010/02/04/1663767.html Original Post:Interviewing the ...
- Xcode升级7.3 自动补全不提示导入的自定义类解决方案
见图:
- Mongodb基础知识----Mongodb权威指南阅读
文档是Mongodb中数据的基本单元,类型关系型数据库中的行,每个文档都有一个键值唯一的键_id.集合可以看做拥有动态模式的表. Mongodb一个实例可以拥有多个相互独立的数据库. Mongodb区 ...