2.1.1 算数类型
类型 int、long、long long 和 short 的区别是什么?无符号类型和带符号类型的区别是什么?float 和 double的区别是什么?
C++ 规定 short 和 int 至少16位,long 至少32位,long long 至少64位,C++语言规定,i一个int至少和short一样大,一个long至少和一个int一样大,一个long long至少和一个long一样大),。 带符号类型能够表示正数、负数和 0 ,而无符号类型只能够表示 0 和正整数。
用法:
一般使用 int 做整数运算,short 因为太小在实际中用的少,long 通常和 int 有着相同的大小。如果数据非常大,可以使用 long long 。
如果你确认数据是非负的,那么就使用 unsigned 无符号类型。
执行浮点运算时用 double ,因为 float 通常精度不够而且双精度浮点数和单精度浮点数的计算代价相差无几。
2.1.2 类型准换
读写程序结果
unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl;
> 这里是引用
std::cout << u - u2 << std::endl;
int i = 10, i2 = 42;
std::cout << i2 - i << std::endl;
std::cout << i - i2 << std::endl;
std::cout << i - u << std::endl;
std::cout << u - i << std::endl;
32
4294967264
32
-32
0
0
2.1.3 字面值常量
指出下述字面值的数据类型并说明每一组内几种字面值的区别:
(a) ‘a’, L’a’, “a”, L"a"
(b) 10, 10u, 10L, 10uL, 012, 0xC
© 3.14, 3.14f, 3.14L
(d) 10, 10u, 10., 10e-2
(a): 字符字面值,宽字符字面值,字符串字面值,宽字符串字面值。
(b): 十进制整型,十进制无符号整型,十进制长整型,十进制无符号长整型,八进制整型,十六进制整型。
( c): double, float, long double
(d): 十进制整型,十进制无符号整型,double, double
下面两组定义是否有区别,如果有,请叙述之:
int month = 9, day = 7;
int month = 09, day = 07;
第一行定义的是十进制整型。 第二行定义的是八进制整型,但是 month 变量无效,因为八进制没有 9 。
下述字面值表示何种含义?它们各自的数据类型是什么?
(a) “Who goes with F\145rgus?\012”
(b) 3.14e1L
© 1024f
(d) 3.14L
(a): Who goes with Fergus?(换行),string 类型
(b): long double
©: 无效,因为后缀 f 只能用于浮点字面量,而 1024 是整型。
(d): long double
2.2.1 变量定义
解释下列定义的含义,对于非法的定义,请说明错在何处并将其改正。
(a) std::cin >> int input_value;
(b) int i = { 3.14 };
© double salary = wage = 9999.99;
(d) int i = 3.14;
(a): 应该先定义再使用。
int input_value = 0;
std::cin >> input_value;
(b): 用列表初始化内置类型的变量时,如果存在丢失信息的风险,则编译器将报错。
double i = { 3.14 };
©: 在这里 wage 是未定义的,应该在此之前将其定义。
double wage;
double salary = wage = 9999.99;
(d): 不报错,但是小数部分会被截断。
下列变量的初值分别是什么?
std::string global_str;
int global_int;
int main()
{
int local_int;
std::string local_str;
}
这里是引用
global_int 是全局变量,所以初值为 0 。 local_int 是局部变量并且没有初始化,它的初值是未定义的。 global_str 和 local_str 是 string 类的对象,该对象定义了默认的初始化方式,即初始化为空字符串。
2.2.2 变量声明和定义的关系
指出下面的语句是声明还是定义:
(a) extern int ix = 1024;
(b) int iy;
© extern int iz;
(a): 定义
(b): 定义
©: 声明
2.2.3 标识符
请指出下面的名字中哪些是非法的?
(a) int double = 3.14;
(b) int _;
(c ) int catch-22;
(d) int 1_or_2 = 1;
(e) double Double = 3.14;
(a), ©, (d) 非法。
2.3.1 引用
下面的哪个定义是不合法的?为什么?
(a) int ival = 1.01;
(b) int &rval1 = 1.01;
(c ) int &rval2 = ival;
(d) int &rval3;
(b) 和 (d) 不合法,(b) 引用必须绑定在对象上,(d) 引用必须初始化。
考察下面的所有赋值然后回答:哪些赋值是不合法的?为什么?哪些赋值是合法的?它们执行了哪些操作?
int i = 0, &r1 = i; double d = 0, &r2 = d;
(a) r2 = 3.14159;
(b) r2 = r1;
© i = r2;
(d) r1 = d;
(a): 合法。给 d 赋值为 3.14159。
(b): 合法。会执行自动转换(int->double)。
©: 合法。会发生小数截取。
(d): 合法。会发生小数截取。
执行下面的代码段将输出什么结果?
int i, &ri = i;
i = 5; ri = 10;
std::cout << i << " " << ri << std::endl;
10, 10
2.3.2 指针
说明指针和引用的主要区别
1.引用是另一个对象的别名,而指针本身就是一个对象。
2.引用必须初始化,并且一旦定义了引用就无法再绑定到其他对象。而指针无须在定义时赋初值,也可以重新赋值让其指向其他对象。
请叙述下面这段代码的作用。
int i = 42;
int *p1 = &i;
*p1 = *p1 * *p1;
让指针 pi 指向 i,然后将 i 的值重新赋值为 42 * 42 (1764)。
请解释下述定义。在这些定义中有非法的吗?如果有,为什么?
int i = 0;
(a) double* dp = &i;
(b) int *ip = i;
© int *p = &i;
(a): 非法。不能将一个指向 double
的指针指向 int
。
(b): 非法。不能将 int
变量赋给指针。
(c ): 合法。
假设 p 是一个 int 型指针,请说明下述代码的含义。
if (p ) // …
if (*p) // …
if § // … 判断 p 是不是一个空指针, if (*p) // … 判断 p 所指向的对象的值是不是为 0
给定指针 p,你能知道它是否指向了一个合法的对象吗?如果能,叙述判断的思路;如果不能,也请说明原因。
不能,因为首先要确定这个指针是不是合法的,才能判断它所指向的对象是不是合法的。
在下面这段代码中为什么 p 合法而 lp 非法?
int i = 42;
void *p = &i;
long *lp = &i;
void * 是从 C语言那里继承过来的,可以指向任何类型的对象。而其他指针类型必须要与所指对象严格匹配。
2.3.3 理解复合类型的声明
说明下列变量的类型和值。
(a) int* ip, i, &r = i;
(b) int i, ip = 0;
© int ip, ip2;
(a): ip 是一个指向 int 的指针, i 是一个 int, r 是 i 的引用。
(b): i 是 int , ip 是一个空指针。
©: ip 是一个指向 int 的指针, ip2 是一个 int。
2.4 const限定符
下面哪些语句是合法的?如果不合法,请说明为什么?
const int buf; // 不合法, const 对象必须初始化
int cnt = 0; // 合法
const int sz = cnt; // 合法
++cnt; ++sz; // 不合法, const 对象不能被改变
2.4.1 const的引用
下面的哪些初始化是合法的?请说明原因。
int i = -1, &r = 0; // 不合法, r 必须引用一个对象
int *const p2 = &i2; // 合法
const int i = -1, &r = 0; // 合法
const int *const p3 = &i2; // 合法
const int *p1 = &i2; // 合法
const int &const r2; // 不合法, r2 是引用,引用没有顶层 const
const int i2 = i, &r = i; // 合法
说明下面的这些定义是什么意思,挑出其中不合法的。
int i, *const cp; // 不合法, const 指针必须初始化
int *p1, *const p2; // 不合法, const 指针必须初始化
const int ic, &r = ic; // 不合法, const int 必须初始化
const int *const p3; // 不合法, const 指针必须初始化
const int *p; // 合法. 一个指针,指向 const int
假设已有上一个练习中定义的那些变量,则下面的哪些语句是合法的?请说明原因。
i = ic; // 合法, 常量赋值给普通变量
p1 = p3; // 不合法, p3 是const指针不能赋值给普通指针
p1 = // 不合法, 普通指针不能指向常量
p3 = // 合法, p3 是常量指针且指向常量
p2 = p1; // 合法, 可以将普通指针赋值给常量指针
ic = *p3; // 合法, 对 p3 取值后是一个 int 然后赋值给 ic
2.4.3 顶层const
对于下面的这些语句,请说明对象被声明成了顶层const还是底层const?
const int v2 = 0; int v1 = v2;
int *p1 = &v1, &r1 = v1;
const int *p2 = &v2, *const p3 = &i, &r2 = v2;
v2 是顶层const,p2 是底层const,p3 既是顶层const又是底层const,r2 是底层const。
假设已有上一个练习中所做的那些声明,则下面的哪些语句是合法的?请说明顶层const和底层const在每个例子中有何体现。
r1 = v2; // 合法, 顶层const在拷贝时不受影响
p1 = p2; // 不合法, p2 是底层const,如果要拷贝必须要求 p1 也是底层const
p2 = p1; // 合法, int* 可以转换成const int*
p1 = p3; // 不合法, p3 是一个底层const,p1 不是
p2 = p3; // 合法, p2 和 p3 都是底层const,拷贝时忽略掉顶层const
2.4.4 constexpr和常量表达式
下面的代码是否合法?如果非法,请设法将其修改正确。
int null = 0, *p = null;
非法.
把int变量直接赋给指针是错误的操作,即使int变量的值恰好等于0也不行.
int null = 0, *p = 0;
2.5.2 类型别名
利用本节定义的变量,判断下列语句的运行结果。
a=42; // a 是 int
b=42; // b 是一个 int,(ci的顶层const在拷贝时被忽略掉了)
c=42; // c 也是一个int
d=42; // d 是一个 int *,所以语句非法
e=42; // e 是一个 const int *, 所以语句非法
g=42; // g 是一个 const int 的引用,引用都是底层const,所以不能被赋值
判断下列定义推断出的类型是什么,然后编写程序进行验证。
const int i = 42;
auto j = i; const auto &k = i; auto *p = &i;
const auto j2 = i, &k2 = i;
j 是 int,k 是 const int的引用,p 是const int *,j2 是const int,k2 是 const int 的引用。
2.5.3 decltype类型指示符
关于下面的代码,请指出每一个变量的类型以及程序结束时它们各自的值。
int a = 3, b = 4;
decltype(a) c = a;
decltype((b)) d = a;
++c;
++d;
c 是 int 类型,值为 4。d 是 int & 类型,绑定到 a,a 的值为 4 。
赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型。也就是说,如果 i 是 int,则表达式 i=x 的类型是 int&。根据这一特点,请指出下面的代码中每一个变量的类型和值。
int a = 3, b = 4;
decltype(a) c = a;
decltype(a = b) d = a;
c 是 int 类型,值为 3。d 是 int& 类型,绑定到 a。
说明由decltype 指定类型和由auto指定类型有何区别。请举一个例子,decltype指定的类型与auto指定的类型一样;再举一个例子,decltype指定的类型与auto指定的类型不一样。
decltype 处理顶层const和引用的方式与 auto不同,decltype会将顶层const和引用保留起来。
int i = 0, &r = i;
//相同
auto a = i;
decltype(i) b = i;
//不同 d 是一个 int&
auto c = r;
decltype® d = r;