C++ Primer(第五版) 第二章 基本内置类型

容易忘记的部分:

2.1:C++提供的几种字符串类型有哪些及其用途?

基本的字符类型char,一个char的类型和一个机器字节一样

其他字符类型用于拓展字符集,如wchar_t、char16_t、char32_t

wchar_t类型确保可以存放机器最大拓展字符集中的任意一个字符

char16_t和char32_t则为Unicode字符集服务

2.2:如何选择所使用的类型

当数值不为负数时,使用无符号类型(unsigned)

一般常用int和long long执行整数的运算

算术表达式中不使用char和bool,只有在特定的时候才使用特定的类型(char:存放字符,bool:存放布尔值)

使用字符时最好明确指出是signed char还是unsigned char

执行浮点数运算时选用double

2.3:字符类型转换中需要注意的问题

无符号类型:

1.当赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的取数。例如8bit的unsigned char表示[0,255]内的数,把-1赋值给它得到255

2.如果表达式里既有带符号类型又有无符号类型,那么带符号类型会自动转化为无符号类型,表达式的结果不会有负数的存在

带符号类型:

1.当赋给带符号类型一个超出表示范围的数,结果是未定义的

2.4:字面值常量相关内容

1.以0开头的代表8进制,0x/0X开头的代表16进制。整型字面值的具体类型由它的值和符号决定。

2.字符串字面值是由常量字符构成的数组

3.转移字符,具体有哪些转移字符及其表示见书P62

4.我们可以通过添加前缀或者后缀来指定字面值的类型,具体的前缀、后缀见书P63

2.5:什么是对象?

对象是指一块能存储数据某种类型的存储空间,一般把命名了的对象叫做变量,而把变量中存的数据叫做值

2.6:初始化的相关事项

1.初始化不是赋值,初始化是创建变量时赋予一个初始值,而赋值是把对象当前的值移除,用新的值来替代

2.列表初始化不能用于可能存在初始值丢失的情况(如用浮点数对整型进行列表初始化)

3.默认初始化:对于内置类型来说,当定义的变量在函数外时,默认初始化为0,若定义的变量来函数内时,变量不被初始化。对于类来说,默认值只与类的构造函数有关,与位置无关

2.7:声明和定义的区别

声明使得名字被程序知道,一个文件想用别人定义的名字必须包含对那个名字的声明

定义负责创建于名字相关的实体。除了规定变量的类型和名字,还会申请存储空间,也有可能赋予初始值

显示声明:在类型前添加关键词extern。如果存在初始化,则视为定义

如果要在多个文件中使用一个变量,变量只能被定义一次,但是可以被声明多次

2.8:标识符的命名规则

标识符(变量名/函数名.....)由字母、数字和下划线组成,其中必须以字母或者下划线开头,长度没有限制,但是对大小写敏感。通常不要使用下划线开头的标识符,因为标准库实现的名字均以下划线开头。

命名规范:

1.能体现实际含义

2.变量名一般用小写字母

3.用户自定义的类名用大写字母开头

4.如果标识符由多个单词组成,则单词间应用下划线分开

注意不要使用C++中的关键词和操作替代名(具体有哪些见书P43)

2.9:相同变量名的不同作用域覆盖问题

名字的有效区域始于名字的声明语句,以声明语句所在的作用域末端为结束

当一个变量在它所嵌套的作用域下又被定义了一次,则在新建变量的作用域下,新建的变量值会覆盖老的变量值,如果想要访问老的变量值,则需要使用作用域符::,当作用域符的左侧为空时,获得全局作用域下老的变量值。

建议:当第一次使用变量在定义它,并且局部变量最好不要和全局变量同名

2.10:生成空指针的办法

1.用字面值nullptr来初始化指针,nullptr作为一种特殊的字面值可以被转换为任意其他指针类型(推荐使用)

2.用字面值0来初始化

3.用一个名为NULL的预处理变量来给指针赋值,这个变量定义在头文件cstdlib中,值为0(避免使用)

2.11:指针值有哪些

1.指向一个对象

2.指向紧邻对象所占空间的下一个位置

3.空指针,没有指向任何对象

4.无效指针,即上述情况之外的其他值

2.12:const限定符

const只能限定对象,因此没有const引用,但是有引用const对象的引用

对象的类型决定了其上的操作。const类型的对象和非const对象类型相比的不同在于:

1.不能改变对象的内容

2.const对象必须初始化

要想在文件之间共享const变量,解决的办法是不管是声明还是定义都添加extern关键字

2.13:constexpr和常量表达式

常量表达式:值不会改变,且在编译过程就能得到计算结果的表达式。一个对象/表达式是否为常量表达式由其对象(const)和初始值(常量表达式)决定

允许将变量声明为constexpr类型以便由编译器来验证变量是否是常量表达式。要求声明constexpr的变量一定是一个常量,同时必须要用常量表达式进行初始化,以及声明要用到的类型必须是字面值类型(内置类型,不包括标准库和自己定义的类类型)

虽然指针和引用都能定义为constexpr,但是因为constexpr的初始值必须是常量,所以对于指针来说,只有当其的初始值为nullptr或者指向某个固定地址(只能是在函数外定义,不能在函数内定义。或者是:允许函数定义一类有效范围超出函数本身的变量)才可以。而对于一个constexpr指针来说,constexpr只修饰指针本身,是一个顶层const,constexpr位于声明最开始的地方

2.14:两种处理类型别名的办法

使用关键词typedef和关键词using(别名声明)

typedef double wages;

using SI=Sales_item;

2.15:auto类型说明符

auto的原理:通过初始值来推断变量的类型。因此auto定义的变量必须要有初始值

如果使用auto在一条语句声明多个变量,要确保证明语句中变量的数据类型相同

auto会忽略顶层const,保留底层const。因此如果希望推断出顶层const,必须自己明确指出

2.16:decltype类型指示符

decltype的作用是选择并返回操作数的数据类型,在这个过程中,它不计算表达式结果,只得到它的类型。

decltype会保留顶层const,此处与auto不同。

引用从来都作为其引用对象的别名出现,而只有在decltype中例外,decltype(引用),会返回一个引用类型,同时注意此处必须初始化

需要理解的部分:

2.1:内置类型的机器实现是怎么样的?

(详细解释见书P57)一个类型的对象占据一定的字节大小。对于一个地址,我们只有知道了存储在该地址的数据的类型,才能知道该内存空间的明确含义

2.2:引用

我们这里的引用指的是左值引用,而右值引用主要用于内置类

因为引用本身不是一个对象,所以不存在引用的引用。

于此同时,引用的类型要和与之绑定的对象严格匹配,不能于某个字面值绑定在一起

2.3:指针

指针本身是对象,并且指针也只能指向对象(即不存在指向引用的指针)

指针的类型要和它所指的对象严格匹配

指针的解引用操作只适用于那些确实指向了某个对象的有效指针

不能把int变量直接赋值给指针(但是可以把字面值0赋值给指针)

建议定义了对象之后再定义指向它的指针,同时建议初始化所有指针,如果不清楚指针指向哪里,就初始化为nullptr或0

想要搞清一条赋值语句改变的是指针的值还是指针所指对象的值,记住赋值改变的永远是等号左侧的对象

永远记住指针存的是地址,当拿指针参与运算时(一定要确保指针是有效的指针)。如果是条件判断,则看指针是否指向一个对象。如果是判断指针是否相等,则看指针所保存的地址是否相等即可。

2.4:指针和引用的不同

1.指针本身是对象。而引用只是其他对象的别名,和其他对象绑定在一起。

2.指针可以先后指向多个不同的对象,允许指针赋值和拷贝。而引用不能更改绑定对象。

3.指针无需在定义时赋值,其默认初始化和内置类型相同。而引用在定义时一定要确定其引用的对象,所以必须初始化。

2.5:某些符号有多重含义

像&和*,既能作为表达式里的运算符,也能作为声明语句中的一部分出现。由符号出现的位置决定了符号的意义。

当&和*紧随类型名出现时,符号是声明的一部分;而当符号出现在表达式中时,它们又转变成了运算符

2.6:void*指针

是一种特殊指针,可以存放任意对象的地址。

但因为我们不知道它所指对象的类型,所以不能通过解引用对所指对象进行操作。

但它可以作指针本身的操作:和其他指针比较、作为函数输入/输出,赋值给另一个void*指针

2.7:符合类型的声明

1.类型修饰符(*和&)只作用于单个对象。对于int *p,其基本类型是int,不是int*。*仅仅修饰了对象p,不对其他对象产生任何的作用

2.类型修饰符的个数没有限制。如:可以通过*的个数区分指针的级别,**代表指向指针的指针,要想访问到最原始的对象,需要通过两次解引用,在内存中的表示就是一个新的地址空间存了上一个指针所在的地址。

3.存在指向指针的引用。如int *p; int *&r=p;

要想理解r的含义,最简单的办法就是从右向左阅读。在C++中里变量名越近的符号对变量的影响越大。

2.8:const的引用

引用所能进行的操作,受其绑定对象的限制。当其绑定的对象为常量时,则引用不能改变其对象的值,同时要求引用本身也必须是const的

引用的类型于其引用对象的类型必须保持一致的例外情况:

在初始化 常量引用 时,可以用任意表达式作为初始值,只要该表达式的结果能转化成引用的类型即可。尤其,允许绑定非常量的对象,字面值,甚至是一般表达式。(后两种情况会创建临时地址用于转化后的值/字面值/表达式的结果)

而对于 常量引用 引用非常量对象的行为虽然不算错误,但在在C++中被归为非法

2.9:指针和const(指向的对象是const的)

和常量引用一样,指向常量的指针不能用于改变其对象的值,同时想要存放常量对象的地址,只能用常量指针。

指针的类型和其指向对象的类型必须保持一致的例外情况(和常量引用类似):

允许常量指针指向非常量的对象,该情况下不能通过指针去改变对象的值(因为指针认为自己指向了常量),但是可以通过其他途径去该改变对象的值(因为对象不是常量)

2.10:const指针(指针本身是const的)

同其他基本的const对象一样,const指针也必须初始化,一旦初始化后便不能再改变

书写格式: 【对象类型 *const 变量名】把*放到const前说明指针是一个常量,同时不变的是指针而不是指针所指的对象

指针本身是常量只是指针的值不变(存放对象的地址),但是这不意味着不能通过解引用指针去改变所指向的对象的值

2.11:顶层const

哪些对象含有顶层const或/和底层const:

对于指针来说,指针本身和指针所指的对象是不是常量是两个独立的问题,进而引出顶层const(指针本身是const)和底层const(指针所指的对象是const)这两个概念。

拓展到一般情况,对于一般的数据类型,只含有顶层const,表示自己对象本身是否为const

而底层const则与指针和引用这样的复合类型有关。当引用所指对象是const,那么该引用含有底层const,但是引用不含顶层const,因为引用本身不是对象

因此只有指针对象可能同时拥有顶层和底层const,而对于引用最多只能拥有底层const,对于一般类型最多只能拥有顶层const

有关含底层/顶层const对象的拷贝操作:

在执行对象的拷贝操作时,顶层const可以忽略。

而底层const的限制不能被忽视,拷入和拷出对象必须具有相同的底层const;或者拷出对象无底层const,但是拷入对象有底层const。对此,我们可以先去掉顶层是否有const(底层const对底层的赋值不起任何的影响),只关注底层const,问题又回到了含const的对象的赋值问题上来。

2.12:使用别名时需要注意的问题

当别名声明一个复合类型(如指针)/常量时,对于一条声明语句不能直接直接将别名替换回原来的形式。一定要明确整个声明语句其基本类型到底是什么,若别名代表一个指针,则基本类型为指针。

如:typedef char* pstring; //别名代表一个指针

const pstring cstr=0;  //const修饰这个别名(即指针),如果替换回char*就会发生错误

2.13:decltype和引用

如果decltype使用的是表达式,则其返回表达式结果对应的类型

若有int i=42,*p=&i,&r=i;   则decltype(r)得到引用类型,但decltype(r+0)得到一个int类型,而解引用操作得到引用类型(因为解引用指针可以得到指针所指的对象,而且还能给这个对象赋值,即解引用常出现在等号左侧)

同时decltype和auto另一个区别(还有一个是decltype保留顶层const)在于,decltype的结果类型与表达式形式密切相关。如果decltype使用的是一个不加括号的变量,则得到变量的类型。如果变量加上括号,就会被当作一个表达式(因为变量是一种可以作为赋值语句左值的特殊表达式),从而得到一个引用类型

原文地址:https://www.cnblogs.com/HDUjackyan/p/9811662.html

时间: 2024-11-04 06:24:47

C++ Primer(第五版) 第二章 基本内置类型的相关文章

C++primer(第五版)第九章 顺序容器(容器的运用及其部分习题解答,C++11特性总结,重点章节内容较多)

顺序容器:为程序员提供了控制元素存储和访问顺序的能力.(无序容器)           1.顺序容器的概述           A.顺序容器的类型           vector:可变大小数组.支持快速随机访问.在尾部之外的位置插入或删除元素可能很慢.          deque:双端队列.支持快速随机访问.在头尾位置插入/删除速度很快.           list:双向链表.只支持双向顺序访问.在list中任何位置进行插入/删除操作速度都很快.          forword_list

c++ primer 第五版第九章

9.01 对于下面的程序任务,vector, deque和list哪种容器最为合适?解释你选择的理由.如果没有哪一种容器优于其它容器,也请解释理由. 读取固定数量的单词,将它们按字典序插入到容器中.我们将在下一章看到,关联容器更适合这个问题. 读取未知数量的单词,总是将新单词插入到末尾.删除操作在头部进行. 从一个文件中读取未知数量的整数.将这些整数排序,然后打印到标准输出. 使用list,需要在中间插入,用list效率更高. 使用deque.只在头尾进行操作,deque效率更高. 使用vect

C++ Primer(第五版) 第九章:顺序容器

练习9.1:考察使用哪种顺序容器 (a)list,当需要在容器中任意位置执行插入/删除操作时,用list最好 (b)deque,当需要在头部插入/删除元素,不需要在容器中间任意位置插入/删除元素时,用deque最好 (c)vector,当不需要在头部/任意位置插入/删除元素的情况下,用vector最好 练习9.2:考察对容器可以保存的元素类型的限制 list<deque<int>>lst1; list<deque<int> >lst2;     //在编译器

C++ Primer 第五版:第1 章

*****C++ Primer 第五版第1章学习笔记***** *****实验代码在Red Hat 6.6或VS 2013中调试***** *****文章内容依据当前知识撰写,存在认识的局限性***** 1.1 编写一个简单的C++程序 函数:依据我个人理解,C/C++的函数是一个能够完成一个功能的模块. 完整函数的组成: ①返回类型:不一定有返回值,故不一定有返回类型 ②函数名:根据名字标识完成特定功能的模块,必须存在 ③形参列表:可能没有参数传入,不一定存在 ④函数体:一个完整的函数应该是有

C++ Primer 第五版:第2章

*****C++ Primer 第五版第2章学习笔记***** *****实验代码在Red Hat 6.6或VS 2013中调试***** *****文章内容依据当前知识撰写,存在认识的局限性***** 今天学习C++ Primer 的第2章,还没有看完,先写一点看书的心得和笔记. 对象类型决定对象包含的数据和能参与的运算操作,同时还决定了存储空间大小.算术表达式中不要使用char,因为不同机器实现不一样,导致结果不同.单精度计算不一定比双精度快. C++类型不匹配时,是自动进行类型的转换. C

C++Primer第五版习题解答---第一章

C++Primer第五版习题解答---第一章 ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2022/1/7 第一章:开始 练习1.3 #include<iostream> int main() { std::cout << "hello, world" << std::endl; return 0; } 练习1.4: #include<iostream> int main() { int

C++ Primer(第五版)学习笔记_5_标准模板库string(2)

C++ Primer(第五版)学习笔记_5_标准模板库string(2) 10.搜索string对象的元素或子串 采用find()方法可查找字符串中的第一个字符元素(char, 用单引号界定)或者子串(用双引号界定):如果查到,则返回下标值(从0开始计数),如果查不到,则返回一个很大的数string:npos(即:4294967295). #include <iostream> #include <stdio.h> #include <string> using nam

C++ Primer(第五版)学习笔记_6_标准模板库_set集合容器

C++ Primer(第五版)学习笔记_6_标准模板库_set集合容器 Set集合容器实现了红黑树(Red-BlackTree)的平衡二叉检索树的数据结构,在插入元素时,它会自动调整二叉树的排序,把该元素放到适当的位置. (1)确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值: (2)另外,还得确保根节点左子树的高度与右子树的高度相等.这样,二叉树的高度最小,从而检索速度最快. 平衡二叉检索树的检索使用中序遍历算法,检索效率高.默认情况下,将键值由小到大遍历. 对于s

C++ Primer 第五版学习笔记

<C++ Primer>第五版中文版学习笔记 ? C++ Primer 第五版学习笔记