C++ Primer 笔记+习题解答(二)

来源:互联网 发布:java中 是什么意思 编辑:程序博客网 时间:2024/06/01 07:40

今天是第二篇笔记了,主要记录一下比较有意思的知识点,做不到面面兼顾。

有错误 请指正 谢谢

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;  //4294967264int 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; //0cout <<"u - i = "<<u-i<< " type is "<<typeid(u-i).name()<<endl; //0system("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;//floatcout << 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

为什么写的这么零碎?因为我写的不好,因为书本才是王道。我只能写一点不常见的东西,不然无异于抄书。习题解答仅供参考,其实不用关心答案正确与否,会了就会了,不会的自己应该很清楚。

0 0