C++ Primer 笔记+习题解答(二)
2015-01-20 16:50
405 查看
今天是第二篇笔记了,主要记录一下比较有意思的知识点,做不到面面兼顾。
有错误 请指正 谢谢
算术类型:字符类型,布尔型,整形,浮点型。
void 类型:不对应具体的值。常见的就是函数的返回值。
除去布尔型和拓展字符型,其他整形可以划分为有符号型和无符号型。
有符号可以表示0,正数,负数。无符号就只能表示正数,0.
unsigned char c = -1; 因为-1字面值默认是int 的,所以会进行转换。这个地方涉及到二进制补码的知识,也就是计算机如何存储负数的。
最后输出c的值是255。关于255是如何得来的,是-1转换后的值除以表示的最大范围所得到的余数。
举个例子:
以0开头的数字是八进制,0x开头表示16进制。
所以字符串的实际长度比内容多1.
字符串字面值的书写格式:特殊的一种,当两个相邻字符串之只有空格,缩进,换行符构成,那么可以分开书写。
那么要使用此类字符要加上反斜线。比如常见的‘\n’表示换行。
上面这些可以称为转义序列。
24.constexpr:
声明定义常量,并且只能用常量初始化。
请看2.3
2.5
2.28
略
2.35
略
2.42
有错误 请指正 谢谢
1.引言:
任何计算机语言都有一组公共的语法特征,不通语言的主要区别在于语法特征的实现细节。
2.基本特征:
一般泛指内置数据类型。大多数C++语言通过两种方式扩充语言:1是自定义数据类型2是把常用的封装成库提供给使用者。
3.一句老话:
C++对象类型决定了其能进行的操作。一个表达式是否合合法取决于参与其中的数据类型。如C++之类的静态类型语言会在编译器进行类型检测,诸如python之类的语言是在运行期进行检查。关于编译和运行时期的概念按照其字面意思进行理解,大致是正确的。4.一个例子:
i=i+j;//这个语句的具体含义取决于i和j的数据类型。i可能是一个类的对象 //也可能只是常见的内置数据类型。
5. 基本内置类型:
分为两类,1是算术类型(arithmetic type),2是空类型(void type)算术类型:字符类型,布尔型,整形,浮点型。
void 类型:不对应具体的值。常见的就是函数的返回值。
6.C++几种字符类型:
拓展字符类型,基本字符类型。7.字节:
计算机寻址的最小内存快。通常是8位一个字节。位:bit; 字节:byte。8.存储的基本单位:
字(word)一般由4个或者8个字节组成。有点类似吞吐量的意思。内存中每个自己与一个地址关联起来。可以通过地址访问相应的自己。为了赋予地址明确的含义,必须知道存储的内容的数据类型。数据类型决定了数据所占用的字节数,以及如何解释这些自己的内容。在深度探索C++对象模型也提到类似的问题。9.重点关注C++类型的概念。
10.符号:
无符号和带符号类型.除去布尔型和拓展字符型,其他整形可以划分为有符号型和无符号型。
有符号可以表示0,正数,负数。无符号就只能表示正数,0.
11.在相应的类型前加上unsigned 或者signed 可以得到对应的符号类型。
12.其中字符型比较特殊:
分为三种:char ,signed char, unsigned char ,但是对外表现只 有两种有符号型和无符号型。也就是说char 和 signed char 是不一样的,具体的行为是由编译器决定的。13.无符号类型的所有比特位都用来存储数值。有符号类型最高位是表示正负。
如:unsigned char 类型的表示范围:理论上为了对称范围是-127到127.实际现代计算机通常是-128到127.14.类型转换:
从一种类型转换为另一相关类型。主要是相关。unsigned char c = -1; 因为-1字面值默认是int 的,所以会进行转换。这个地方涉及到二进制补码的知识,也就是计算机如何存储负数的。
最后输出c的值是255。关于255是如何得来的,是-1转换后的值除以表示的最大范围所得到的余数。
举个例子:
上面提到:-1的默认类型是int型的。那么-1在计算机中如何存储呢?是这样搞的。 首先:最高位是1表示负数。那么-1表示成:1000 0001 ;然而工作并没结束。 除去最高位之外,其余进行求反,得到反码。即:1111 1110 ;得到反码。 最后一步:求补码。对反码+1;即可以得到: 1111 1111 ; 补码对应的10进制数字是:255 .那么255%256=255,故上面的c值是255.如果转换不了,或者超出范围就会成为未定义行为或者截断成为异常值。
unsigned char c=256.//转不了了。不要混用带符号和不带符号的类型。
以0开头的数字是八进制,0x开头表示16进制。
15.浮点型的默认字面值是double。
整形的字面值一般是最小容纳类型(不包含short)也就是说int能容纳下的数字,那么编译器就会默认你是int了。若int放不下,会自动上调到合适的类型。16.字符和字符串字面值:
字符串字面值实际上是由字符字面值构成的数据。编译器会在最后一位加一个空字符('\0') 标识结束。所以字符串的实际长度比内容多1.
字符串字面值的书写格式:特殊的一种,当两个相邻字符串之只有空格,缩进,换行符构成,那么可以分开书写。
<span style="font-size:18px;">如cout<<"This is a sample"</span> <<" oh ! ";两类不可以直接使用的字符:1是不可打印字符,如退格,换行等。2是特殊含义的字符,比如反斜线,问号等。
那么要使用此类字符要加上反斜线。比如常见的‘\n’表示换行。
上面这些可以称为转义序列。
17.泛化转义序列:
比如你可以这样打印字母A: \x41;不建议使用。其次就是x表示16进制。18.通过添加前缀后缀可以指定字面值类型。
如:double db1=2L;还有许多前缀和后缀,不一一介绍。
19.内置类型采用列表初始化的时候,不能存在截断的风险,否则会报错。
20.声明和定义的区别:
int i; //定义。 extern int i ;//声明。 extren int i=0;//定义。任何存在初始化行为的声明也是定义。
21.为什么支持分离式编译,所以要严格区分定义和声明,多次声明没问题,但只能一次定义。
22.复合类型的理解:
基于其他类型定义出来的类型。比如引用和指针。23.常量表达式:
不会改变值,在编译期就可以计算出结果。24.constexpr:
声明定义常量,并且只能用常量初始化。constexpr int i=10;一个陷进:
const int *p=nullptr; constexpr int *p=nullptr; 这两个一样嘛?不同。第一个是指向常量的指针,第二个是指针常量。类型别名:typedef 和 using 声明别名。
如: using money=double ; typedef double money; 两者表达的意思一样。一个陷进:
typedef char *pstring; const pstring p; const char* p; 两个等价嘛?不等价。所以不要简单替换理解。第一个const修饰的是char*整体。也就是说p是指针常量。 第二个是指向常量的指针。对于复杂声明,建议从右向左读。首先找变量名。区分变量名和标识符的关系。标识符包含变量名。
26.auto 和 decltype 类型说明符。
auto 可以用表达式的类型去初始化一个auto 类型。如 int v1=2; int v2=3; auto x=v1+v2; //编译器可以推断出x的类型。这个地方有了初始化操作,不想初始化可以使用decltype. decltypde(v1) x; //x的类型是int .这个地方并不需要吃初始化操作。
27.头文件卫士:
ifndef xxx #define xxx #include<string> class a{}; #ennif防止多次包含。
28.习题解答:
2.1<span style="font-size:24px;">区别: 1.int long ,long long ,short 的区别。 最主要的区别就是所占的字节数是不同,也等价于容纳数的范围不同。long long 最大。 2.无符号类型和有符号类型的区别: 无符合的只能表示正数,有符号的可以表示全部。 3.float 和double 的区别: 精度不同,推荐使用double。 </span>2.2
<span style="font-size:24px;">利率选用 unsigned double ;本金选用 unsigned double; 付款也应该选用 unsigned double.</span>2.3
<span style="font-size:24px;">#include <iostream> using namespace std; int main(){ unsigned u = 10, u2 = 42; cout << "u2 - u = "<<u2-u <<" type is "<<typeid(u2-u).name()<< endl; //32; cout <<"u - u2 = "<<u-u2<<" type is " <<typeid(u-u2).name()<< endl; //4294967264 int i = 10, i2 = 42; cout << "i2 - i = "<<i2-i<<" type is "<<typeid(i2-i).name() <<endl; //32; cout <<"i - i2 = "<<i-i2<<" type is "<<typeid(i-i2).name()<< endl; //-32; cout << "i - u = " << i - u <<" type is "<< typeid(i - u).name() <<endl; //0 cout <<"u - i = "<<u-i<< " type is "<<typeid(u-i).name()<<endl; //0 system("pause"); return 0; }</span>2.4
请看2.3
2.5
<span style="font-size:24px;">//(a) 'a ; L'a' ; "a" ;L"a" 从左到右类型依次是:char ,wchar_t ,常量字符串,宽字符常量字符串。 //(b) 10 ;10u ;10L ;10uL ;012; 0xC; 依次是 int,unsigned int ,long int ,unsigned long int ,8进制 int,16进制 int。 //(c) 3.14 ;3.14f ;3.14L 依次是 double ,float, double //(d) 10 ;10u ;10. ;10e-2; int ,unsigned int ,double ,double , #include <iostream> using namespace std; int main(){ cout << typeid(10e-2).name() << endl;//验证方法typeid().name() 函数。 system("pause"); return 0; }</span>2.6
<span style="font-size:24px;">有区别: 第一组: int month=9,day=7; 9和7 都是10进制整数。 第二组: int month=09,day=07; 09是什么鬼.不是八进制也不算十进制 07 是8进制整数。 </span>2.7
<span style="font-size:24px;">#include <iostream> using namespace std; int main(){ cout << "Who goes with F\145rgus?\012"; //145是三个八进制数字。\12换行、 cout << typeid("Who goes with F\145rgus?\012").name() << endl; cout << 3.14e1L<<endl; // long double cout << typeid(3.14e1L).name() << endl; cout << 3.14f << endl;//float cout << typeid(3.14f).name() << endl; cout << 3.14L << endl; cout << typeid(3.14L).name() << endl; system("pause"); return 0; }</span>2.8
<span style="font-size:24px;">#include <iostream> using namespace std; int main(){ cout << "\062\x4D\012"; cout << "\062\x9\x4D\012"; system("pause"); return 0; } //全部用ASCII码表示的。 </span>2.9
<span style="font-size:24px;">a. 错误:int input_value; cin>>input_value; b. 错误:int i={3.13} 存在信息丢失风险。C++Primer 定义为错误,vs2013可以通过 c. 错误:double salary=wage=99.99; wage 未定义。 d. 正确:int i=3.13; 会有截断。 </span>2.10
<span style="font-size:24px;">global_str empty string; global_int 0; local_str 未初始化 local_int 未初始化</span>2.11
<span style="font-size:24px;">extern int ix=1024 /definition int iy //definition extern int iz //declaration</span>2.12
<span style="font-size:24px;">(a),(c),(d) </span>2.13
<span style="font-size:24px;">j=100</span>2.14
<span style="font-size:24px;">不合法。i只存活于循环体内。循环体外无法打印i.</span>2.15
<span style="font-size:24px;">b,d 不合法。</span>2.16
<span style="font-size:24px;">不考虑截断问题,全部可以通过编译。vs2013+win 7 </span>2.17
<span style="font-size:24px;">output: 10 10 ,两个10之间有一个空格</span>2.18
<span style="font-size:24px;">#include <iostream> using namespace std; int main(){ int v1=3,v2=4; const int *p = &v1; //指向常量的指针 //*p = 3; 不合法 p = nullptr; //合法 int * const ptr = &v2;//常量指针 //ptr = nullptr; 不合法 *ptr = v1; //合法 system("pause"); return 0; }</span>2.19
<span style="font-size:24px;">区别:1.无空引用,声明即绑定,但可以有空指针。 2.指针是对象,占据内存的行为,引用是变量的别名。 </span>2.20
<span style="font-size:24px;">通过指针间接修改i的值,i的值为以前值的平方积。</span>2.21
<span style="font-size:24px;">有。类型不一致。</span>2.22
<span style="font-size:24px;">1.p指针不为空,则执行if里面的语句。 2.*P的值不等于0,就执行if里面的语句。</span>2.23
<span style="font-size:24px;">根据上下文观察吧。或者输出*p,看看是不是垃圾值。</span>2.24
<span style="font-size:24px;">因为 p是 void* 型的。可以存储任何变量的地址。 而lp 的类型是long int ,同i 的类型不一致。 理论上是可以接受的,但是实际情况定义为错误比较好。</span>2.25
<span style="font-size:24px;">a)ip 是指针。i 是int ,r是i的引用 b)i 是int,ip是空指针 c)ip 是指针,ip2是int 。</span>2.26
<span style="font-size:24px;">a,d不合法。const 量必须初始化并且不能改变值。</span>2.27
<span style="font-size:24px;">b,d,e,g</span>
2.28
<span style="font-size:24px;">不合法的:a,b,d,e.不合法原因因为常量只能初始化,不能赋值。</span>2.29
<span style="font-size:24px;">合法:a,b,c</span>2.30
<span style="font-size:24px;">顶层const: v2, 靠右的是顶层const. 底层const: p2, 靠左的是底层const. </span>2.31
<span style="font-size:24px;">全部合法。赋值操作时,可以忽略const.但是涉及到const作为左值时,也就是值将被修改,那么要关注const. </span>2.32
<span style="font-size:24px;">不合法:修改方案:int null=0,*p=&null;</span>2.33
<span style="font-size:24px;">42, 42 ,42 ,报错,报错,42.</span>2.34
略
2.35
<span style="font-size:24px;">j : int; k:int;p:int const *; j2: int ; k2: int . #include <iostream> using namespace std; int main(){ const int i = 42; const auto j = i; const auto &k = i; auto *p = &i; const auto j2 = i, &k2 = i; cout << typeid(k2).name(); //用typdeid函数进行验证。 system("pause"); return 0; } 平台不同,可能有差异。测试平台:vs2013+win 7 </span>2.36
<span style="font-size:24px;">a:int ; b: int ; c: int ; d: int ; 结果:a=4,b=4,c=4,d=4; #include <iostream> using namespace std; int main(){ int a = 3, b = 4; decltype(a) c = a; decltype((b)) d = a; ++c; ++d; cout << "a= " << a << endl; cout << "b= " << b << endl; cout << "c= " << c << endl; cout << "d= " << d << endl; cout << "d's type is :" << typeid(d).name(); system("pause"); return 0; } </span>2.37
<span style="font-size:24px;">#include <iostream> using namespace std; int main(){ int a = 3, b = 4; decltype(a) c = a; decltype(a=b) d = a; cout << "d's type is :" << typeid(d).name(); system("pause"); return 0; } //由于int& 类型属于符合类型,而且类似int, 所以编译器可能会d 划为 int 型。如果你的结果是int& ,不用奇怪。 </span>2.38
<span style="font-size:24px;">区别:auto 类型推断时肯定要初始化;而decltype 不需要,除非必要。 关于int& 和 int ,我的编译器不区分,所以不做测试。</span>2.39
<span style="font-size:24px;">#include <iostream> using namespace std; struct Foo{ } int main(){ system("pause"); return 0; } // error C2628: “Foo”后面接“int”是非法的(是否忘记了“;”?) //error C3874 : “main”的返回类型应为“int”而非“Foo” //error C2440 : “return” : 无法从“int”转换为“Foo”</span>2.40
<span style="font-size:24px;">#include <iostream> using namespace std; #include <string> struct Foo{ string bookNo; unsigned int units_sold; //可能一开始写的时候注意不到无符号数的使用。 double revenue; }; int main(){ system("pause"); return 0; }</span>2.41
略
2.42
<span style="font-size:24px;">#ifndef SALES_DATA_H #define SALES_DATA_H #include <iostream> #include <string> struct Sales_data{ std::string bookNo; unsigned int units_sold; double revenue; }; #endif // !SALES_DATA_H 重点是学会使用header gurd !!!最好都要加上。不建议包含命名空间,详情见下一节。 </span>
End
为什么写的这么零碎?因为我写的不好,因为书本才是王道。我只能写一点不常见的东西,不然无异于抄书。习题解答仅供参考,其实不用关心答案正确与否,会了就会了,不会的自己应该很清楚。相关文章推荐
- C++ Primer 笔记+习题解答(十一)
- C++ Primer 笔记+习题解答(十)
- C++ Primer 笔记+习题解答(八)
- C++ Primer 笔记+习题解答(三)
- C++ Primer 笔记+习题解答(九)
- C++ Primer 笔记+习题解答(五)
- C++ Primer 笔记+习题解答(一)
- C++ Primer 笔记+习题解答(六)
- C++ Primer 笔记+习题解答(四)
- C++ Primer 笔记+习题解答(七)
- Introduction to Algorithms 算法导论 第1章 基础知识 学习笔记及习题解答
- C++ primer习题笔记第4章
- C++ Primer(第五版)读书笔记 & 习题解答 --- Chapter 2
- C++ primer习题笔记第7~9章
- C++ primer 习题笔记第5~6章
- 《算法导论》习题解答搬运&&学习笔记 索引目录
- Introduction to Algorithms 算法导论 第3章 函数的增长 学习笔记及习题解答
- C++ Primer(第五版)读书笔记 & 习题解答 --- Chapter 1
- DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)
- C++ primer 习题笔记第13~15章