【自用记录】C++ Primer 第二章 变量和基本类型

目录

练习2.1:类型int、long、long long、和short的区别是什么? 无符号类型和带符号类型的区别是什么? float和double的区别是什么?

练习2.2:计算按揭贷款时,对于利率、本金和付款分别应选择何种数据类型?说明理由。

练习2.3:读程序写结果。

练习2.4:编写程序检查你的估计是否正确。

练习2.5: 指出下述字面值的数据类型并说明每一组内几种字面值的区别。

练习2.6:下面两组定义是否有区别,如果有,请叙述之。

练习2.7:下述字面值表示何种含义?它们各自的数据类型是什么?

练习2.8:请利用转义序列编写一段程序,要求先输出2M,然后转到新一行。

修改程序使其先输出2,然后输出制表符,再输出M,最后转到新一行。

练习2.9:解释下列定义的含义。对于非法的定义,请说明错在何处并将其改正。

练习2.10:下列变量的初值分别是什么?

练习2.11:指出下面的语句是声明还是定义。

练习2.12:请指出下面的名字中哪些是非法的?

练习2.13:下面的程序中j的值是多少?

练习2.14:下面的程序合法吗?如果合法,它将输出什么?

练习2.15:下面的哪个定义是不合法的?为什么?

练习2.16:下列赋值合法or不合法?

练习2.17:执行下面的代码段将输出什么结果?

练习2.18:编写代码分别更改指针的值以及指针所指对象的值。

练习2.19:说明指针和引用的主要区别。

练习2.20:请叙述下面这段代码的作用。

练习2.21:请解释下述定义。在这些定义中有非法的吗?如果有,为什么?

练习2.22:假设p是一个int型指针,请说明下列代码的含义。

练习2.23:给定指针p,你能知道它是否指向了一个合法的对象吗?如果能,叙述判断的思路;如果不能,也请说明原因。

练习2.24:在下面这段代码中为什么p合法而1p非法?

练习2.25:说明下列变量的类型和值。

练习2.26:下面哪些句子是合法的?如果有不合法的句子,请说明为什么?

练习2.27:下面的哪些初始化是合法的?请说明原因。

练习2.28:说明下面的这些定义是什么意思,挑出其中不合法的。

练习2.29:假设已有上一个练习中定义的那些变量,则下面的哪些语句是合法的?请说明原因。

练习2.30:对于下面的这些语句,请说明对象被声明成了顶层const还是底层const?

练习2.31:假设已有上一个练习中所做的那些声明,则下面的哪些语句是合法的?请说明顶层const和底层const在每个例子中有何体现。

练习2.32:下面的代码是否合法?如果非法,请设法将其修改正确。

练习2.33:利用本节定义的变量,判断下列语句的运行结果。

练习2.34:基于上一个练习中的变量和语句编写一段程序,输出赋值前后变量的内容。

练习2.35:判断下列定义推断出的类型是什么,然后编写程序进行验证。

练习2.36:关于下面的代码,请指出每一个变量的类型以及程序结束时它们各自的值。

练习2.37:如果i是int,则表达式i=x的类型是int&。赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型。根据这一特点,请指出下面的代码中每一个变量的类型和值。

练习2.38:说明由decltype指定类型和由auto指定类型有何区别。请举出一个例子,decltype指定的类型与auto指定的类型一样;再举一个例子,decltype指定的类型与auto指定的类型不一样。

练习2.39:编译下面程序。注意,如果忘记写类定义体后面的分号会发生什么情况?

练习2.40:根据自己的理解写出Sales_data类,最好与书中的例子有所区别。

练习2.41:使用你自己的Sales_data类重写之前三个的练习。眼下先把Sales_data类的定义和main函数放在同一个文件里。

练习2.42:根据你自己的理解重写一个Sales_data.h头文件,并以此基础重做练习2.41


练习2.1:类型int、long、long long、和short的区别是什么? 无符号类型和带符号类型的区别是什么? float和double的区别是什么?

练习2.2:计算按揭贷款时,对于利率、本金和付款分别应选择何种数据类型?说明理由。

利率double、本金unsigned long long、付款unsigned     ??

练习2.3:读程序写结果。

#include 
int main()
{
	unsigned u = 10, u2 = 42;
	std::cout << u2 - u << std::endl;
	std::cout << u - u2 << std::endl;
	return 0; 
}

32

取模后的值

#include 
int main()
{
	int i = 10, i2 = 42;
	unsigned u = 10;
	std::cout << i2 - i << std::endl;
	std::cout << i - i2 << std::endl;
	std::cout << i - u << std::endl;
	std::cout << u - i << std::endl;
	return 0; 
}

32

-32

0

带符号类型取值为负时会出现异常结果

练习2.4:编写程序检查你的估计是否正确。

【自用记录】C++ Primer 第二章 变量和基本类型_第1张图片

【自用记录】C++ Primer 第二章 变量和基本类型_第2张图片

练习2.5: 指出下述字面值的数据类型并说明每一组内几种字面值的区别。

(a)'a', L'a', "a", L"a"

'a' : char型字面值 字符

L'a' : 宽字符 字符,类型是wchar_t

"a" : 字符串型字面值

L"a" : 宽字符 字符串

(b)10, 10u,10L,10uL,012,0xC

10:整型字面值

10u : 整型字面值 后缀u或U 最小匹配类型:unsigned

10L:整型字面值 后缀l或L 最小匹配类型:long

10uL:整型字面值   后缀中有U,该字面值属于无符号类型;后缀中有L,该字面值的类型至少是long——>unsigned long或unsigned long long

012:以0开头的整数代表八进制数

0xC:以0x或0X开头的代表十六进制数

(c)3.14,3.14f,3.14L

3.14:浮点型字面值 默认为double

3.14f:浮点型字面值 后缀f或F,类型为float

3.14L:浮点型字面值 后缀l或L,类型为long double

(d)10,10u,10.,10e-2 

10:整型字面值

10u:整型字面值 后缀u或U 最小匹配类型:unsigned

10.:有小数点 浮点型字面值 默认为double

10e-2:以科学计数法表示的指数,其中指数部分用E或e标识  浮点型字面值 默认为double

练习2.6:下面两组定义是否有区别,如果有,请叙述之。

int month = 9, day = 7;

int month = 09, day = 07;

有区别 第一行为十进制数,第二行为八进制数

编译程序时会显示 :  八进制常量中的数字“9”、数字“7”无效

练习2.7:下述字面值表示何种含义?它们各自的数据类型是什么?

(a)"Who goes with F\145rgus?\012"

有反斜线\,字符串字面值:输出Who goes with Fergus?换行

\145 : e , \012:换行符

【自用记录】C++ Primer 第二章 变量和基本类型_第3张图片

(b)3.14e1L

浮点型字面值,后缀L:类型long double      e1:乘 10的1次方

#include 
int main()
{
	long double a = 3.14e1L;
	std::cout << a << std::endl;
	return 0; 
}
#include 
int main()
{
	std::cout << 3.14e1L << std::endl;
	return 0; 
}

 【自用记录】C++ Primer 第二章 变量和基本类型_第4张图片

(c)1024f

后缀f:单精度浮点型字面值,类型为float

#include 
int main()
{
	std::cout << 1024f << std::endl;
	return 0; 
}

 [Error]整数常量上的后缀“f”无效

编译报错

网上查询后,正确形式应为1024.f,需要一个小数点标志它为浮点型字面值,否则系统认为1024是整型,与后缀的f不搭。

#include 
int main()
{
	float a = 1024.f;
	std::cout << a << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第5张图片

(d)3.14L

浮点型字面值,后缀L:类型为long double

#include 
int main()
{
	long double a = 3.14L;
	std::cout << a << std::endl;
	return 0; 
}
#include 
int main()
{
	std::cout << 3.14L << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第6张图片

练习2.8:请利用转义序列编写一段程序,要求先输出2M,然后转到新一行。

修改程序使其先输出2,然后输出制表符,再输出M,最后转到新一行。

#include 
int main()
{
	std::cout << "2\115\12" << std::endl;
	return 0; 
}

 【自用记录】C++ Primer 第二章 变量和基本类型_第7张图片

#include 
int main()
{
	std::cout << "2\tM\n" << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第8张图片

练习2.9:解释下列定义的含义。对于非法的定义,请说明错在何处并将其改正。

(a)std::cin >> int input_value;

编译报错    [Error]在“int”之前应为主表达式

#include 
int main()
{
	std::cin >> int input_value;
	std::cout << input_value << std::endl;
	return 0; 
}

#include 
int main()
{
	int input_value = 0;
	std::cin >> input_value;
	std::cout << input_value << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第9张图片

(b)int i = { 3.14 };

使用了列表初始化:用花括号来初始化变量。

使用浮点型的值初始化int变量时可能丢失数据。这里是仅保留小数点前的值。

#include 
int main()
{
	int i = { 3.14 };
	std::cout << i << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第10张图片

(c)double salary = wage = 9999.99;

编译错误。  [Error]未在此范围内声明“wage”

若按此顺序来,应为wage先被定义并赋值,随后被用于初始化salary

因为wage没有先被定义,所以报错。

#include 
int main()
{
	double  wage = 9999.99, salary = wage;
	std::cout << salary << std::endl;
	std::cout << wage << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第11张图片

(d)int i = 3.14;

把一个浮点数赋给整数类型时,进行了近似处理。结果值仅保留浮点数中小数点之前的部分。

#include 
int main()
{
	int i = 3.14;
	std::cout << i << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第12张图片

练习2.10:下列变量的初值分别是什么?

string类规定如果没有指定初值则生成一个空串。

定义时没有指定初值,定义于任何函数体之外的变量被初始化为0:

std::string global_str;      global_str被初始化为0。  ??

int global_int;       global_int被初始化为0。

定义在函数体内部的内置类型变量,定义时没有指定初值:

int main()

    int local_int;       local_int 被默认初始化的int对象,这里被默认初始化为0
    std::string local_str;       local_str非显式地初始化为一个空串。
    return 0; 
}

定义于函数体内的内置类型的对象如果没有初始化,则其值未定义。

类的对象如果没有显式地初始化,则其值由类确定。

#include 
std::string global_str;
int global_int;
int main()
{
	int local_int;
	std::string local_str;
	std::cout << global_str << std::endl;
	std::cout << global_int << std::endl;
	std::cout << local_int << std::endl;
	std::cout << local_str << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第13张图片

练习2.11:指出下面的语句是声明还是定义。

(a)extern int ix = 1024;     定义

extern语句如果包含初始值就不再是声明,而变成定义了。

(b)int iy;     声明并定义iy。

(c)extern int iz;

仅声明iz。

练习2.12:请指出下面的名字中哪些是非法的?

(a)int double = 3.14; 非法。

(b)int _;  若定义在函数体外,则非法。

(c)int catch-22; 非法。   仅字母、数字、下划线组成

(d)int 1_or_2 = 1;  非法。  必须以字母或下划线开头

(e)double Double = 3.14;  因标识符对大小写字母敏感,所以合法。

练习2.13:下面的程序中j的值是多少?

j = 100;

#include 
int i = 42; 
int main()
{
	int i = 100;
	int j = i;
	std::cout << j << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第14张图片

练习2.14:下面的程序合法吗?如果合法,它将输出什么?

合法。输出:100 45

因为第二次定义的i定义于for语句内,覆盖了main块的变量i。在for语句之内可以访问初始值为0的i,根据程序来看最后为10,但是在main函数的其他部分就不能访问它了。所以最后要输出的i的值为定义于main函数所限定的作用域之内,出了main函数所在的块就无法访问了。

中间有“” 输出中间的字符串,此程序中的字符串是一个空格。

#include 
int main()
{
	int i = 100, sum = 0;
	for(int i = 0; i != 10; ++i)
	    sum += i;
	std::cout << i << " " << sum << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第15张图片

练习2.15:下面的哪个定义是不合法的?为什么?

(a)int ival = 1.01;

合法。声明并定义且初始化ival。

(b)int &rval1 = 1.01;

不合法。引用类型的初始值必须是一个对象。

(c)int &rval2 = ival;

合法。rval2是一个引用,与ival绑定在一起。

(d)int &rval3;

不合法。引用必须被初始化。

练习2.16:下列赋值合法or不合法?

int i = 0, &r1 = i;    double d = 0, &r2 = d;

(a)r2 = 3.14159;

合法。把3.14159赋给 r2 指向的对象,此处即是赋给了 d 。d = 3.14159。

#include 
int main()
{
	int i = 0, &r1 = i;
	double d = 0, &r2 = d;
	r2 = 3.14159;
	std::cout << d << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第16张图片

 (b)r2 = r1;

合法。   (引用的类型都要和与之绑定的对象严格匹配。)

把 r1 指向的对象即 i 的值赋给 r2 指向的对象,此处即是赋给了 d 。又因为i为int,d为double。d = 0。

#include 
int main()
{
	int i = 0, &r1 = i;
	double d = 0, &r2 = d;
	r2 = r1;
	std::cout << d << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第17张图片

 (c)i = r2;

合法。

把 r2 指向的对象 即 d 的值赋给 i 。i = 0。

#include 
int main()
{
	int i = 0, &r1 = i;
	double d = 0, &r2 = d;
	i = r2;
	std::cout << i << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第18张图片

 (d)r1 = d;

合法。

把 d 的值赋给 r1 指向的对象 即 i 。i = 0。

#include 
int main()
{
	int i = 0, &r1 = i;
	double d = 0, &r2 = d;
	r1 = d;
	std::cout << i << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第19张图片

练习2.17:执行下面的代码段将输出什么结果?

10 10

#include 
int main()
{
	int i, &ri = i;
	i = 5; ri = 10;
	std::cout << i << " " << ri << std::endl;
	return 0; 
}

 【自用记录】C++ Primer 第二章 变量和基本类型_第20张图片

练习2.18:编写代码分别更改指针的值以及指针所指对象的值。

#include 
int main()
{
	int a = 12, b = 2;
	int *p = &a;
	p = &b;
	std::cout << *p << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第21张图片

#include 
int main()
{
	int a = 12, b = 2;
	int *p = &a;
	*p = 8;
	std::cout << a << std::endl;
	return 0; 
}

 【自用记录】C++ Primer 第二章 变量和基本类型_第22张图片

练习2.19:说明指针和引用的主要区别。

引用本身并非一个对象。一旦定义了引用,就无法令其再绑定到另外的对象,之后每次使用这次引用都是访问它最初绑定的那个对象。

指针和它存放的地址之间就没有这种限制了。

练习2.20:请叙述下面这段代码的作用。

int i = 42;  声明并定义且初始化i的值为42.

int *p1 = &i;  p1存放变量i的地址,或者说,p1是指向变量i的指针。

*p1 = *p1 * *p1;  由解引用符*得到指针p1所指的对象,即可经由p1为变量 i 赋值。i 此时的值为42*42=1764. 

#include 
int main()
{
	int i = 42;
	int *p1 = &i;
	*p1 = *p1 * *p1;
	std::cout << i << " " << p1 << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第23张图片

练习2.21:请解释下述定义。在这些定义中有非法的吗?如果有,为什么?

int i = 0;

(a)double* dp = &i;

dp存放变量 i 的地址,或者说,dp是指向变量 i 的指针。

非法。把int型对象的地址赋给double型指针。指针的类型与它所指向对象的类型 两者必须匹配。

[Error]无法在初始化中将“int*”转换为“double*”

(b)int *ip = i;

非法。指针的值即是对象的地址,指针存放某个对象的地址,无法直接存对象。

[Error]从“int”到“int*”的转换无效

(c)int *p = &i;

合法。两者类型匹配。

练习2.22:假设p是一个int型指针,请说明下列代码的含义。

if ( p )  // 指针p的值(即某个对象的地址)是0的话,条件取false,任何非0指针对应的条件值都是true

if ( *p )  // *p为指针p所指对象的取值

练习2.23:给定指针p,你能知道它是否指向了一个合法的对象吗?如果能,叙述判断的思路;如果不能,也请说明原因。

指针的值(即地址)应属下列4种状态之一:

1.指向一个对象;

2.指向紧邻对象所占空间的下一个位置;

3.空指针,意味着指针没有指向任何对象;

4.无效指针,也就是上述情况之外的其他值。

练习2.24:在下面这段代码中为什么p合法而1p非法?

int i = 42;

void *p = &i;

long *1p = &i;

void *是一种特殊的指针类型,p可以存放任意类型的指针,可用于存放任意对象的地址。

而1p指针类型与所指的对象类型不匹配。

练习2.25:说明下列变量的类型和值。

(a)int* ip, i, &r = i;

ip是指向int型对象的指针;i为int型对象;r为一个引用与i绑定。

(b)int i, *ip = 0;

i为int型对象;ip是指向int型对象的指针,是空指针。

(c)int* ip, ip2;

ip是指向int型对象的指针;ip2是int型对象。

练习2.26:下面哪些句子是合法的?如果有不合法的句子,请说明为什么?

(a)const int buf;

不合法。buf是一个未经初始化的常量

(b)int cnt = 0;

合法。

(c)const int sz = cnt;

合法。cnt的值被拷贝给了sz。

(d)++cnt;++sz;

前部分合法。后部分不合法。const对象一旦创建后其值就不能再改变。

练习2.27:下面的哪些初始化是合法的?请说明原因。

(a)int i = -1, &r = 0;

非法。

前半部分合法,后半部分非法:引用类型的初始值必须是一个对象。

(b)int *const p2 = &i2;

合法。

从右向左读。p2本身是一个常量对象,接着是一个常量指针,最后常量指针指向的是一个int对象。

等号右侧有&符号。

即p2将一直指向i2.

(c)const int i = -1, &r = 0;

非法。

i本身是一个int对象,接着是一个常量对象。

引用类型的初始值必须是一个对象。

(d)const int *const p3 = &i2;

合法。

p3本身是一个常量对象,接着是一个常量指针,然后此常量指针指向的是一个int对象,最后这个int对象也是一个常量对象。   即p3是一个指向常量对象的常量指针。

等号右侧有&符号。即p3将一直指向i2.

因为p3是一个指向常量对象的常量指针,所以p3所指的对象值且p3自己存储的那个地址都不能改变。

(e)const int *p1 = &i2;

合法。

p1本身是一个指针对象,接着此指针指向的是一个int对象,最后这个int对象是一个常量对象。

p1指向i2.  p1是一个指向常量的指针。

因为p1指向的是一个常量整数,所以不可以通过p1去修改i2的值。

指向常量的指针仅仅要求不能通过该指针改变对象的值,而没有规定那个对象 即i2 的值不能通过其他途径改变。

(f)const int &const r2;

非法。

r2本身是一个常量,接着是一个引用。

[Error]“const”限定符不能应用于“const int&”

[Error]'r2'声明为引用但未初始化

(g)const int i2 = i, &r = i;

合法。

i2是一个常量整数,r是一个引用,都需要初始化,都进行了初始化。

练习2.28:说明下面的这些定义是什么意思,挑出其中不合法的。

(a)int i, *const cp;

不合法。

i是一个int型对象;cp本身是一个常量对象,接着是一个常量指针,最后此常量指针指向的是一个int对象 即此指针将一直指向这个int对象。但因为const对象一旦创建后其值就不能再改变,所以const对象必须初始化。 这里未初始化。

(b)int *p1, *const p2;

不合法。

p1本身是一个指针,接着它指向的是一个int对象。

p2本身是一个常量,接着是一个常量指针,最后它指向的是一个int对象。

但const对象没有初始化。

(c)const int ic, &r = ic;

不合法。

ic本身是一个int对象,接着是一个常量整数。

r本身是一个引用,接着是一个与int类型绑定的引用,最后是一个常量整数引用。

允许一个常量引用绑定非常量的对象、字面值,甚至是一个表达式。但不允许非常量引用绑定常量。

此题为常量绑定常量。

但const对象未初始化。

(d)const int *const p3;

不合法。

p3本身是一个常量,接着是一个常量指针,然后它指向的是一个int对象,最后此int对象是一个常量对象。即p3是一个指向常量的常量指针。

但const对象未初始化。

(e)const int *p;

合法。

p本身是一个指针,接着它指向的是一个int对象,最后这个int对象是一个常量。

即p是一个指向常量的指针。

练习2.29:假设已有上一个练习中定义的那些变量,则下面的哪些语句是合法的?请说明原因。

(a)i = ic;

合法。

ic本身是一个int对象,接着是一个常量整数。

i是一个int型对象。

可以将一个常量整数赋值给一个int型对象。

(b)p1 = p3;

不合法。

p1本身是一个指针,接着它指向的是一个int对象。指向的是一个普通的非常量整数

p3本身是一个常量,接着是一个常量指针,然后它指向的是一个int对象,最后此int对象是一个常量对象。即p3是一个指向常量的常量指针。

非常量可以转换为常量,反之则不行。

(c)p1 = ⁣

合法。

p1本身是一个指针,接着它指向的是一个int对象。

ic本身是一个int对象,接着是一个常量整数。

p1是一个一般的指针,p1此时是指向ic的指针。

(d)p3 = ⁣

不合法。

p3本身是一个常量,接着是一个常量指针,然后它指向的是一个int对象,最后此int对象是一个常量对象。即p3是一个指向常量的常量指针。

ic本身是一个int对象,接着是一个常量整数。

p3是一个指向常量的常量指针,指向的对象是固定的,将一直指向,不可随便改变。

(e)p2 = p1;

不合法。

p2本身是一个常量,接着是一个常量指针,最后它指向的是一个int对象。

p1本身是一个指针,接着它指向的是一个int对象。

p2指向的对象是固定的,将一直指向,不可随便拷贝。

(f)ic = *p3;

不合法。

ic本身是一个int对象,接着是一个常量整数。

p3本身是一个常量,接着是一个常量指针,然后它指向的是一个int对象,最后此int对象是一个常量对象。即p3是一个指向常量的常量指针。

ic是常量整数,不可随便拷贝。

练习2.30:对于下面的这些语句,请说明对象被声明成了顶层const还是底层const?

(a)const int v2 = 0;

v2是一个常量整数,永远值为0,v2为顶层const。

(b)int v1 = v2;

将v2的值赋给了v1,v1是一个普通的int型变量,可以任意改变值。  

(c)int *p1 = &v1, &r1 = v1;

p1是一个指向int型对象的指针,p1是指向v1的指针;r1是一个int型的引用,与v1捆绑。

(d)const int *p2 = &v2, *const p3 = &i, &r2 = v2;

p2是一个指向常量的指针,允许改变p2的值,这是一个底层const,p2是指向v2的指针;

p3是一个指向常量的常量指针,这是一个顶层const,p3是指向i的指针;p3既是顶层const,也是底层const。

r2是一个常量整数的引用,用于声明引用的const都是底层const,它与v2捆绑。

练习2.31:假设已有上一个练习中所做的那些声明,则下面的哪些语句是合法的?请说明顶层const和底层const在每个例子中有何体现。

(a)r1 = v2;

合法。

r1是一个int型的引用,与v1捆绑。v1是一个普通的int型变量,可以任意改变值。  

v2是一个常量整数,永远值为0,v2为顶层const。

非常量可以转换为常量,反之则不可以。

(b)p1 = p2;

合法。

p1是一个指向int型对象的指针,p1是指向v1的指针;

p2是一个指向常量的指针,允许改变p2的值,这是一个底层const,p2是指向v2的指针;

非常量可以转换为常量,反之则不可以。

(c)p2 = p1;

不合法。

p2是一个指向常量的指针,允许改变p2的值,这是一个底层const,p2是指向v2的指针;

p1是一个指向int型对象的指针,p1是指向v1的指针;

非常量可以转换为常量,反之则不可以。

(d)p1 = p3;

合法。

p1是一个指向int型对象的指针,p1是指向v1的指针;

p3是一个指向常量的常量指针,这是一个顶层const,p3是指向i的指针;p3既是顶层const,也是底层const。

非常量可以转换为常量,反之则不可以。

(e)p2 = p3;

合法。

p2是一个指向常量的指针,允许改变p2的值,这是一个底层const,p2是指向v2的指针;

p3是一个指向常量的常量指针,这是一个顶层const,p3是指向i的指针;p3既是顶层const,也是底层const。

因为这两个指针都是底层const,尽管p3同时也是一个常量指针(顶层const),仅就这次赋值而言不会有什么影响。

练习2.32:下面的代码是否合法?如果非法,请设法将其修改正确。

int null = 0, *p = null;

非法。

[Error]从“int”到“int*”的转换无效

改正:int null = 0, *p = &null;

练习2.33:利用本节定义的变量,判断下列语句的运行结果。

int i = 0, &r = i;    i是一个整数变量,其值为0;r是一个整数引用,与i捆绑,是i的别名。

auto a = r;    a是一个整数,值为0(i是一个整数)

const int ci = i, &cr = ci;     ci是一个常量整数,它的值永远是0;cr是一个常量整数的引用,与ci捆绑,是ci的别名。

auto一般会忽略掉顶层const,同时底层const会保留下来。

auto b = ci;    b是一个整数,值为0,顶层const被忽略。

auto c = cr;    c是一个整数,值为0,ci是一个常量整数,顶层const被忽略。

auto d = &i;    d是一个指向i的指针,i是一个整数变量,即d是一个指向整型变量的指针。

auto e = &ci;  e是一个指向ci的指针,ci是一个常量整数,即e是一个指向常量的指针,此为底层const,保留。(对常量对象取地址是一种底层const)

设置一个类型为auto的引用时,初始值中的顶层常量属性仍然保留。

auto &g = ci;  g是一个引用,与ci绑定,值为0,ci是一个常量整数,g是ci的别名,g是一个整型常量的引用。

(a)a = 42;

a是一个整数。a的值变为42.

(b)b = 42;

b是一个整数。b的值变为42.

(c)c = 42;

c是一个整数。c的值变为42.

(d)d = 42;

d是一个指向整型变量的指针。普通指针被直接赋值一个字面值,应该编译出错?

[Error]从“int”到“int*”的转换无效

(e)e = 42;

e是一个指向常量的指针。指向的对象可以随意更改,但对象本身是一个常量,此指针被直接赋值一个字面值,应该编译出错?

[Error]从“int”到“const int*”的转换无效

(f)g = 42;

g是一个整型常量的引用。g是ci的别名,不改变。直接编译出错。

[Error]分配只读引用'g'

练习2.34:基于上一个练习中的变量和语句编写一段程序,输出赋值前后变量的内容。

#include 
int main()
{
	int i = 0, &r = i;
	auto a = r;
	const int ci = i, &cr = ci;
	auto b = ci;
	auto c = cr;
	auto d = &i;
	auto e = &ci;
	auto &g = ci;
	std::cout << a << std::endl;
	std::cout << b << std::endl;
	std::cout << c << std::endl;
	std::cout << d << std::endl;
	std::cout << e << std::endl;
	std::cout << g << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第24张图片

#include 
int main()
{
	int i = 0, &r = i;
	auto a = r;
	const int ci = i, &cr = ci;
	auto b = ci;
	auto c = cr;
	auto d = &i;
	auto e = &ci;
	auto &g = ci;
	a = 42;
	b = 42;
	c = 42;
	std::cout << a << std::endl;
	std::cout << b << std::endl;
	std::cout << c << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第25张图片

 两指针一引用 直接编译出错:

普通指针被直接赋值一个字面值  [Error]从“int”到“int*”的转换无效

指向常量的指针被直接赋值一个字面值  [Error]从“int”到“const int*”的转换无效

g是一个整型常量的引用  [Error]分配只读引用'g'

练习2.35:判断下列定义推断出的类型是什么,然后编写程序进行验证。

(a)const int i = 42;

i是一个整型常量,值永远为42.

(b)auto j = i;

j是一个整数,因为i是一个整数,且auto将顶层const被忽略。j的值为42,但是可以改变。

(c)const auto &k = i;

auto前加const:i的类型是int,k是const int的引用。k与i捆绑,k是i的别名。k的值为42,不可改变。

(d)auto *p = &i;

p是一个指向i的指针,i是一个整型常量,对常量对象取地址是一种底层const。即p是一个指向常量的指针。

(e)const auto j2 = i, &k2 = i;

auto前加const:i的类型是int型,j2是const int整型常量,不可改变;k2是一个const int的引用,与i捆绑,不可改变。

#include 
int main()
{
	const int i = 42;
	auto j = i;
	const auto &k = i;
	auto *p = &i;
	const auto j2 = i, &k2 = i;
	j = 20;
	const int n = 30;
	p = &n;
	std::cout << j << " " << *p << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第26张图片

练习2.36:关于下面的代码,请指出每一个变量的类型以及程序结束时它们各自的值。

int a = 3, b = 4;

decltype (a) c = a;

decltype ((b)) d = a;

++c;

++d;

a和b都是一个int型对象;decltype(变量) c是一个int型对象,它的值为3;decltype双层括号变量的结果是引用,d是一个int型对象的引用,与a捆绑,是a的别名,其值为3;

程序结束时a的值为4,b的值为4,c的值为4,d的值为4.

#include 
int main()
{
	int a = 3, b = 4;
    decltype (a) c = a;
    decltype ((b)) d = a;
    ++c;
	++d;
	std::cout << a << std::endl;
	std::cout << b << std::endl;
	std::cout << c << std::endl;
	std::cout << d << std::endl;
	return 0; 
}

【自用记录】C++ Primer 第二章 变量和基本类型_第27张图片

练习2.37:如果i是int,则表达式i=x的类型是int&。赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型。根据这一特点,请指出下面的代码中每一个变量的类型和值。

int a = 3, b = 4;

decltype (a) c = a;

decltype (a = b) d = a;

a和b都是一个int型变量,值分别为3和4;c也是一个int型变量,其值为3;d是一个int型的引用,与a捆绑,是a的别名,其值为3.

练习2.38:说明由decltype指定类型和由auto指定类型有何区别。请举出一个例子,decltype指定的类型与auto指定的类型一样;再举一个例子,decltype指定的类型与auto指定的类型不一样。

练习2.39:编译下面程序。注意,如果忘记写类定义体后面的分号会发生什么情况?

#include 
struct Foo { /* 此处为空 */  }
int main()
{
	return 0; 
}

[Error]应为“;”在结构定义之后

练习2.40:根据自己的理解写出Sales_data类,最好与书中的例子有所区别。

练习2.41:使用你自己的Sales_data类重写之前三个的练习。眼下先把Sales_data类的定义和main函数放在同一个文件里。

练习2.42:根据你自己的理解重写一个Sales_data.h头文件,并以此基础重做练习2.41

你可能感兴趣的:(C++,Primer书后习题,c++)