今天是第二篇笔记了,主要记录一下比较有意思的知识点,做不到面面兼顾。
有错误 请指正 谢谢
C++对象类型决定了其能进行的操作。一个表达式是否合合法取决于参与其中的数据类型。如C++之类的静态类型语言会在编译器进行类型检测,诸如python之类的语言是在运行期进行检查。关于编译和运行时期的概念按照其字面意思进行理解,大致是正确的。
i=i+j;//这个语句的具体含义取决于i和j的数据类型。i可能是一个类的对象
//也可能只是常见的内置数据类型。
分为两类,1是算术类型(arithmetic type),2是空类型(void type)
算术类型:字符类型,布尔型,整形,浮点型。
void 类型:不对应具体的值。常见的就是函数的返回值。
拓展字符类型,基本字符类型。
计算机寻址的最小内存快。通常是8位一个字节。位:bit; 字节:byte。
字(word)一般由4个或者8个字节组成。有点类似吞吐量的意思。内存中每个自己与一个地址关联起来。可以通过地址访问相应的自己。为了赋予地址明确的含义,必须知道存储的内容的数据类型。数据类型决定了数据所占用的字节数,以及如何解释这些自己的内容。在深度探索C++对象模型也提到类似的问题。
无符号和带符号类型.
除去布尔型和拓展字符型,其他整形可以划分为有符号型和无符号型。
有符号可以表示0,正数,负数。无符号就只能表示正数,0.
分为三种:char ,signed char, unsigned char ,但是对外表现只 有两种有符号型和无符号型。也就是说char 和 signed char 是不一样的,具体的行为是由编译器决定的。
如:unsigned char 类型的表示范围:理论上为了对称范围是-127到127.实际现代计算机通常是-128到127.
从一种类型转换为另一相关类型。主要是相关。
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.//转不了了。
不要混用带符号和不带符号的类型。整形的字面值一般是最小容纳类型(不包含short)也就是说int能容纳下的数字,那么编译器就会默认你是int了。若int放不下,会自动上调到合适的类型。
字符串字面值实际上是由字符字面值构成的数据。编译器会在最后一位加一个空字符('\0') 标识结束。
所以字符串的实际长度比内容多1.
字符串字面值的书写格式:特殊的一种,当两个相邻字符串之只有空格,缩进,换行符构成,那么可以分开书写。
如cout<<"This is a sample"
<<" oh ! ";
两类不可以直接使用的字符:1是不可打印字符,如退格,换行等。2是特殊含义的字符,比如反斜线,问号等。
那么要使用此类字符要加上反斜线。比如常见的‘\n’表示换行。
上面这些可以称为转义序列。
比如你可以这样打印字母A: \x41;不建议使用。其次就是x表示16进制。
如:double db1=2L;
还有许多前缀和后缀,不一一介绍。
int i; //定义。
extern int i ;//声明。
extren int i=0;//定义。
任何存在初始化行为的声明也是定义。
基于其他类型定义出来的类型。比如引用和指针。
不会改变值,在编译期就可以计算出结果。
声明定义常量,并且只能用常量初始化。
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是指针常量。
第二个是指向常量的指针。
对于复杂声明,建议从右向左读。首先找变量名。区分变量名和标识符的关系。标识符包含变量名。
auto 可以用表达式的类型去初始化一个auto 类型。
如 int v1=2;
int v2=3;
auto x=v1+v2; //编译器可以推断出x的类型。这个地方有了初始化操作,不想初始化可以使用decltype.
decltypde(v1) x; //x的类型是int .这个地方并不需要吃初始化操作。
ifndef xxx
#define xxx
#include
class a{};
#ennif
防止多次包含。
2.1
区别:
1.int long ,long long ,short 的区别。
最主要的区别就是所占的字节数是不同,也等价于容纳数的范围不同。long long 最大。
2.无符号类型和有符号类型的区别:
无符合的只能表示正数,有符号的可以表示全部。
3.float 和double 的区别:
精度不同,推荐使用double。
2.2
利率选用 unsigned double ;本金选用 unsigned double; 付款也应该选用 unsigned double.
2.3
#include
using namespace std;
int main(){
unsigned u = 10, u2 = 42;
cout << "u2 - u = "<
2.4
请看2.3
2.5
//(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
using namespace std;
int main(){
cout << typeid(10e-2).name() << endl;//验证方法typeid().name() 函数。
system("pause");
return 0;
}
2.6有区别:
第一组: int month=9,day=7; 9和7 都是10进制整数。
第二组: int month=09,day=07; 09是什么鬼.不是八进制也不算十进制 07 是8进制整数。
2.7
#include
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<
2.8
#include
using namespace std;
int main(){
cout << "\062\x4D\012";
cout << "\062\x9\x4D\012";
system("pause");
return 0;
}
//全部用ASCII码表示的。
2.9
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; 会有截断。
2.10global_str empty string;
global_int 0;
local_str 未初始化
local_int 未初始化
2.11
extern int ix=1024 /definition
int iy //definition
extern int iz //declaration
2.12
(a),(c),(d)
2.13
j=100
2.14
不合法。i只存活于循环体内。循环体外无法打印i.
2.15
b,d 不合法。
2.16不考虑截断问题,全部可以通过编译。vs2013+win 7
2.17
output: 10 10 ,两个10之间有一个空格
2.18
#include
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;
}
2.19
区别:1.无空引用,声明即绑定,但可以有空指针。
2.指针是对象,占据内存的行为,引用是变量的别名。
2.20
通过指针间接修改i的值,i的值为以前值的平方积。
2.21
有。类型不一致。
2.22
1.p指针不为空,则执行if里面的语句。
2.*P的值不等于0,就执行if里面的语句。
2.23
根据上下文观察吧。或者输出*p,看看是不是垃圾值。
2.24
因为 p是 void* 型的。可以存储任何变量的地址。
而lp 的类型是long int ,同i 的类型不一致。
理论上是可以接受的,但是实际情况定义为错误比较好。
2.25
a)ip 是指针。i 是int ,r是i的引用
b)i 是int,ip是空指针
c)ip 是指针,ip2是int 。
2.26
a,d不合法。const 量必须初始化并且不能改变值。
2.27
b,d,e,g
2.28
不合法的:a,b,d,e.不合法原因因为常量只能初始化,不能赋值。
2.29
合法:a,b,c
2.30
顶层const: v2, 靠右的是顶层const.
底层const: p2, 靠左的是底层const.
2.31
全部合法。赋值操作时,可以忽略const.但是涉及到const作为左值时,也就是值将被修改,那么要关注const.
2.32
不合法:修改方案:int null=0,*p=&null;
2.33
42, 42 ,42 ,报错,报错,42.
2.34
略
2.35
j : int; k:int;p:int const *; j2: int ; k2: int .
#include
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
2.36
a:int ; b: int ; c: int ; d: int ;
结果:a=4,b=4,c=4,d=4;
#include
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;
}
2.37
#include
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& ,不用奇怪。
2.38
区别:auto 类型推断时肯定要初始化;而decltype 不需要,除非必要。
关于int& 和 int ,我的编译器不区分,所以不做测试。
2.39
#include
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”
2.40
#include
using namespace std;
#include
struct Foo{
string bookNo;
unsigned int units_sold; //可能一开始写的时候注意不到无符号数的使用。
double revenue;
};
int main(){
system("pause");
return 0;
}
2.41
略
2.42
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include
#include
struct Sales_data{
std::string bookNo;
unsigned int units_sold;
double revenue;
};
#endif // !SALES_DATA_H
重点是学会使用header gurd !!!最好都要加上。不建议包含命名空间,详情见下一节。
为什么写的这么零碎?因为我写的不好,因为书本才是王道。我只能写一点不常见的东西,不然无异于抄书。习题解答仅供参考,其实不用关心答案正确与否,会了就会了,不会的自己应该很清楚。