您的位置:首页 > 编程语言 > C语言/C++

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

2015-01-20 16:50 405 查看
今天是第二篇笔记了,主要记录一下比较有意思的知识点,做不到面面兼顾。
有错误 请指正 谢谢

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

为什么写的这么零碎?因为我写的不好,因为书本才是王道。我只能写一点不常见的东西,不然无异于抄书。习题解答仅供参考,其实不用关心答案正确与否,会了就会了,不会的自己应该很清楚。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: