C++ Primer 【第四版】第二章 变量和基本类型

来源:互联网 发布:宋仲基宋慧乔婚礼知乎 编辑:程序博客网 时间:2024/05/22 02:08
习题2.1

intlongshort 类型之间有什么差别?

【解答】

它们的最小存储空间不同,分别为16位、32 位和16 位。一般而言,short类型为半个机器字(word)长,int 类型为一个机器字长,而long类型为一个或两个机器字长(在32 位机器中,int 类型和long 类型的字长通常是相同的)。因此,它们的表示范围不同。

 

习题2.2

unsignedsigned类型有什么差别?

【解答】

前者为无符号类型,只能表示大于或等于0的数。后者为带符号类型,可以表示正数、负数和0

 

习题2.3

如果在某机器上short类型占16 位,那么可以赋给short类型的最大数是什么?unsigned short类型的最大数又是什么?

【解答】

若在某机器上short类型占16 位,那么可以赋给short类型的最大数是215-1,即32767;而unsigned short类型的最大数为216-1,即65535

 

习题2.4

当给16位的unsigned short 对象赋值100000 时,赋的值是什么?

【解答】

34464

100000超过了16位的unsigned short 类型的表示范围,编译器对其二进制表示截取低16位,相当于对65536 求余(求模,%),得34464

 

习题2.5

float类型和double类型有什么差别?

【解答】

二者的存储位数不同(一般而言,float类型为32 个二进制位,double类型为64个二进制位),因而取值范围不同,精度也不同(float类型只能保证6位有效数字,而double 类型至少能保证10 位有效数字)。

 

习题2.6

要计算抵押贷款的偿还金额,利率、本金和付款额应分别选用哪种类型?解释你选择的理由。

【解答】

利率可以选择float类型,因为利率通常为百分之几。一般只保留到小数点后两位,所以6 位有效数字就足以表示了。本金可以选择long类型,因为本金通常为整数。long 类型可表示的最大整数一般为231-1(即2147483647),应该足以表示了。付款额一般为实数,可以选择double类型,因为float 类型的6 位有效数字可能不足以表示。

 

习题2.7

解释下列字面值常量的不同之处。

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

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

(c)3.14,3.14f,3.14L

【解答】

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

'a'char型字面值,L'a'wchar_t 型字面值,"a"为字符串字面值,L"a"为宽字符串字面值。

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

10int型字面值,10u unsigned型字面值,10Llong 型字面值,10uLunsigned long型字面值,012 为八进制表示的int 型字面值,0xC为十六进制表示的int型字面值。

(c)3.14,3.14f,3.14L

3.14double型字面值,3.14f float型字面值,3.14Llong double 型字面值。

 

习题2.8

确定下列字面值常量的类型:

(a)–10 (b) -10u (c) -10. (d) -10e-2

【解答】

(a)int

(b)unsigned int

(c)double

(d)double

 

习题2.9

下列哪些(如果有)是非法的?

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

(b)3.14e1L (c) "two" L"some"

(d)1024f (e) 3.14UL

(f)"multiple line

comment"

【解答】

 (c)非法。因为字符串字面值与宽字符串字面值的连接是未定义的。

(d)非法。因为整数1024后面不能带后缀f

(e)非法。因为浮点字面值不能带后缀U

(f)非法。因为分两行书写的字符串字面值必须在第一行的末尾加上反斜线。

 

习题2.10

使用转义字符编写一段程序,输出2M,然后换行。修改程序,输出2,跟着一

个制表符,然后是M,最后是换行符。

【解答】

输出2M、然后换行的程序段:

//输出"2M"和换行字符

std::cout<< "2M" << '\n';

修改后的程序段:

//输出'2', '\t', 'M'和换行字符

std::cout<< '2' << '\t' << 'M' << '\n';

 

习题2.11

编写程序,要求用户输入两个数——底数(base)和指数(exponent),输出

底数的指数次方的结果。

【解答】

#include<iostream>

intmain()

{

//局部对象

intbase, exponent;

longresult=1;

//读入底数(base)和指数(exponent

std::cout<< "Enter base and exponent:" << std::endl;

std::cin>> base >> exponent;

if(exponent < 0) {

std::cout<< "Exponent can't be smaller than 0" << std::endl;

return-1;

}

if(exponent > 0) {

//计算底数的指数次方

for(int cnt = 1; cnt <= exponent; ++cnt)

result*= base;

}

std::cout<< base

<<" raised to the power of "

<<exponent << ": "

<<result << std::endl;

return0;

}

 

习题2.12

区分左值和右值,并举例说明。

【解答】

左值(lvalue)就是变量的地址,或者是一个代表“对象在内存中的位置”的表达式。右值(rvalue)就是变量的值,见2.3.1节。变量名出现在赋值运算符的左边,就是一个左值;而出现在赋值运算符右边的变量名或字面常量就是一个右值。

例如:

val1=val2/8

这里的val1是个左值,而val2 8 都是右值。

 

习题2.13

举出一个需要左值的例子。

【解答】

赋值运算符的左边(被赋值的对象)需要左值,见习题2.12

 

习题2.14

下面哪些(如果有)名字是非法的?更正每个非法的标识符名字。

(a)int double = 3.14159; (b) char _;

(c)bool catch-22; (d) char 1_or_2 ='1';

(e)float Float = 3.14f;

【解答】

(a)doubleC++语言中的关键字,不能用作用户标识符,所以非法。此语句可改为:double dval= 3.14159;

(c)名字catch-22中包含在字母、数字和下划线之外的字符“-”,所以非法。可将其改为:catch_22;

(d)名字1_or_2非法,因为标识符必须以字母或下划线开头,不能以数字开头。可将其改为:one_or_two;

 

习题2.15

下面两个定义是否不同?有何不同?

intmonth = 9, day = 7;

intmonth =09, day = 07;

如果上述定义有错的话,那么应该怎样改正呢?

【解答】

这两个定义不同。前者定义了两个int型变量,初值分别为9 7;后者也定义了两个int型变量,其中day 被初始化为八进制值7;而month的初始化有错:试图将month初始化为八进制值09,但八进制数字范围为0~7,所以出错。可将第二个定义改为:int month =011, day = 07;

 

习题2.16

假设calc是一个返回double 对象的函数。下面哪些是非法定义?改正所有的非法定义。

(a)int car = 1024, auto = 2048;

(b)int ival = ival;

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

(d)double salary = wage = 9999.99;

(e)double calc = calc();

【解答】

(a)非法:auto是关键字,不能用作变量名。使用另一变量名,如aut 即可更正。

(c)非法:>>运算符后面不能进行变量定义。改为:intinput_value;std::cin >> input_value;

(d)非法:同一定义语句中不同变量的初始化应分别进行。改为:double salary = 9999.99, wage = 9999.99;

注意,(b)虽然语法上没有错误,但这个初始化没有实际意义,ival仍是未初始化的。

 

习题2.17

下列变量的初始值(如果有)是什么?

std::stringglobal_str;

intglobal_int;

intmain()

{

intlocal_int;

std::stringlocal_str;

//...

return0;

}

【解答】

global_strlocal_str的初始值均为空字符串,global_int 的初始值为0local_int没有初始值。

 

习题2.18

解释下列例子中name的意义:

externstd::string name;

std::stringname("exercise 3.5a");

externstd::string name("exercise 3.5a");

【解答】

第一条语句是一个声明,说明std::string变量name 在程序的其他地方定义。

第二条语句是一个定义,定义了std::string变量name,并将name 初始化为"exercise 3.5a"

第三条语句也是一个定义,定义了std::string变量name,并将name 初始化为"exercise 3.5a",但这个语句只能出现在函数外部(即,name是一个全局变量)。

 

习题2.19

下列程序中j的值是多少?

inti = 42;

intmain()

{

inti = 100;

intj = i;

//...

}

【解答】

j的值是100j的赋值所使用到的i 应该是main 函数中定义的局部变量i,因为局部变量的定义会屏蔽全局变量的定义。

 

习题2.20

下列程序段将会输出什么?

inti = 100, sum = 0;

for(int i = 0; i != 10; ++i)

sum+= i;

std::cout<< i << " " << sum << std::endl;

【解答】

输出为:

10045

for语句中定义的变量i,其作用域仅限于for语句内部。输出的i 值是for 语句之前所定义的变量i的值。

 

习题2.21

下列程序合法吗?

intsum = 0;

for(int i = 0; i != 10; ++i)

sum+= i;

std::cout<< "Sum from 0 to " << i

<<" is " << sum << std::endl;

【解答】

不合法。因为变量i具有语句作用域,只能在for 语句中使用,输出语句中使用i属非法。

 

习题2.22

下列程序段虽然合法,但是风格很糟糕。有什么问题呢?怎样改善?

for(int i = 0; i < 100; ++i)

//process i

【解答】

问题主要在于使用了具体值100作为循环上界:100 的意义在上下文中没有体现出来,导致程序的可读性差;若100这个值在程序中出现多次,则当程序的需求发生变化(如将100 改变为200)时,对程序代码的修改复杂且易出错,导致程序的可维护性差。改善方法:设置一个const变量(常量)取代100作为循环上界使用,并为该变量选择有意义的名字。

 

习题2.23

下列哪些语句合法?对于那些不合法的使用,解释原因。

(a)const int buf;

(b)int cnt = 0;

constint sz = cnt;

(c)cnt++; sz++;

【解答】

(a)不合法。因为定义const变量(常量)时必须进行初始化,而buf 没有初始化。

(b)合法。

(c)不合法。因为修改了const变量sz 的值。

 

习题2.24

下列哪些定义是非法的?为什么?如何改正?

(a)int ival = 1.01; (b) int &rval1 = 1.01;

(c)int &rval2 = ival; (d) const int &rval3 = 1;

【解答】

(b)非法。因为rval1是一个非const引用,非const 引用不能绑定到右值,而1.01 是一个右值。可改正为:int &rval1 = ival;(假设ival是一个已定义的int 变量)。

 

习题2.25

在习题2.24给出的定义下,下列哪些赋值是非法的?如果赋值合法,解释赋值的作用。

(a)rval2 = 3.14159; (b) rval2 = rval3;

(c)ival = rval3; (d) rval3 = ival;

【解答】

(d)非法。因为rval3是一个const引用,不能进行赋值。合法赋值的作用:

(a)将一个double型字面值赋给int型变量ival,发生隐式类型转换,ival 得到的值为3

(b)int1 赋给变量ival

(c)int1 赋给变量ival

 

习题2.26

(a)中的定义和(b)中的赋值存在哪些不同?哪些是非法的?

(a)int ival = 0; (b) ival = ri;

constint &ri = 0; ri = ival;

【解答】

intival = 0;定义ivalint 变量,并将其初始化为0

constint &ri = 0;定义riconst 引用,并将其绑定到右值0

ival= ri;0值赋给ival

ri= ival;试图对ri赋值,这是非法的,因为ri const引用,不能赋值。

 

习题2.27

下列代码输出什么?

inti, &ri = i;

i= 5; ri =10;

std::cout<< i << " " << ri << std::endl;

【解答】

输出:

1010

rii的引用,对ri 进行赋值,实际上相当于对i 进行赋值,所以输出i ri 的值均为10

 

习题2.28

编译以下程序,确定你的编译器是否会警告遗漏了类定义后面的分号。

classFoo {

//empty

}// Note: no semicolon

intmain()

{

return0;

}

如果编译器的诊断结果难以理解,记住这些信息以备后用。

【解答】

在笔者所用的编译器中编译上述程序,编译器会给出如下错误信息:

errorC2628: 'Foo' followed by 'int' is illegal (did you forget a ';'?)(第4行)

warningC4326: return type of 'main' should be 'int or void' instead of'Foo'(第5行)

errorC2440: 'return' : cannot convert from 'int' to 'Foo'(第6行)

也就是说,该编译器会对遗漏了类定义后面的分号给出提示。

 

习题2.29

区分类中的public部分和private 部分。

【解答】

类中public部分定义的成员在程序的任何部分都可以访问。通常在public 部分放置操作,以便程序中的其他部分可以执行这些操作。类中private部分定义的成员只能被作为类的组成部分的代码(以及该类的友元)访问。通常在private部分放置数据,以对对象的内部数据进行隐藏。

 

习题2.30

定义表示下列类型的类的数据成员:

(a)电话号码 (b)地址

(c)员工或公司 (d)梦芭莎优惠券网里面的文章

【解答】

(a)电话号码

classTel_number {

public:

//...对象上的操作

private:

std::stringcountry_number;

std::stringcity_number;

std::stringphone_number;

};

(b)地址

classAddress {

public:

//...对象上的操作

private:

std::stringcountry;

std::stringcity;

std::stringstreet;

std::stringnumber;

};

(c)员工或公司

classEmployee {

public:

//...对象上的操作

private:

std::stringID;

std::stringname;

charsex;

Addressaddr;

Tel_numbertel;

};

classCompany {

public:

//...对象上的操作

private:

std::stringname;

Addressaddr;

Tel_numbertel;

};

(d)某大学的学生

classStudent {

public:

//...对象上的操作

private:

std::stringID;

std::stringname;

charsex;

std::stringdept; //所在系

std::stringmajor;

Addresshome_addr;

Tel_numbertel;

};

注意,在不同的具体应用中,类的设计会有所不同,这里给出的只是一般性的简单例子。

 

习题2.31

判别下列语句哪些是声明,哪些是定义,请解释原因。

(a)extern int ix = 1024 ;

(b)int iy ;

(c)extern int iz ;

(d)extern const int &ri ;

【解答】

(a)是定义,因为extern声明进行了初始化。

(b)是定义,变量定义的常规形式。

(c)是声明,extern声明的常规形式。

(d)是声明,声明了一个const引用。

 

习题2.32

下列声明和定义哪些应该放在头文件中?哪些应该放在源文件中?请解释原因。

(a)int var ;

(b)const double pi = 3.1416;

(c)extern int total = 255 ;

(d)const double sq2 = squt (2.0) ;

【解答】

(a)(c)(d)应放在源文件中,因为(a)(c)是变量定义,定义通常应放在源文件中。(d)中的const变量sq2 不是用常量表达式初始化的,所以也应该放在源文件中。

(b)中的const变量pi是用常量表达式初始化的,应该放在头文件中。参见2.9.1节。

 

习题2.33

确定你的编译器提供了哪些提高警告级别的选项。使用这些选项重新编译以前选择的程序,查看是否会报告新的问题。

【解答】

在笔者所用的编译器(Microsoft Visual C++ .NET 2003)中,在Project菜单中选择Properties 菜单项,在ConfigurationPropertiesC/C++GeneralWarningLevel中可以选择警告级别。

0 0
原创粉丝点击