【C++Primer练习】第4章 表达式

练习4.1

表达式5+10*20/2的求值结果是多少?

105

练习4.2

在下列表达式合理位置添加括号,使得添加括号后的运算对象组合顺序与添加前一致
(a)*vec.begin() (b)*vec.begin()+1

成员选择运算符.优先级>解引用运算符*>加法运算符+,所以:
(a):表示先获得指向vec[0]的指针,再解引用获得值vec[0]。添加括号:*(vec.begin())
(b):表示先获得指向vec[0]的指针,再解引用获得值vec[0],最后加1。添加括号:*(vec.begin())+1
验证代码

#include 
#include 
using std::cout;
using std::endl;
using std::vector;

int main()
{
    vector<int> vec(5, 0);
    cout << *vec.begin() << endl;
    cout << *(vec.begin()) << endl;
    cout << *vec.begin() + 1 << endl;
    cout << *(vec.begin()) + 1 << endl;
    system("pause");
    return 0;
}

练习4.3

C++语言没有明确规定大多数二元运算符的求值顺序,给编译器优化留下了余地。这种策略实际上是在代码生成效率和程序潜在缺陷之间进行了权衡,你认为这可以接受吗?请说出你的理由

可以接受。程序潜在缺陷是可以在编程时调整以避免的,而代码效率相较之下更为重要。

练习4.4

在下面表达式中添加括号,说明其求值过程及最终结果。编写程序验证结果。
12/3*4+5*15+24%4/2

((12/3)*4)+(5*15)+((24%4)/2)

#include 
using std::cout;
using std::endl;

int main()
{
    cout << 12 / 3 * 4 + 5 * 15 + 24 % 4 / 2 << endl;			//91
    cout << ((12 / 3) * 4) + (5 * 15) + ((24 % 4) / 2) << endl;	//91
    system("pause");
    return 0;
}

练习4.5

写出下列表达式的求值结果:
(a)-30*3+21/5 (b)-30+3*21/5
(a)30/3*21%5 (b)-30/3*21%4

(a)-86 (b)-18
(a)0 (b)-2
验证代码

#include 
using std::cout;
using std::endl;

int main()
{
    cout << -30 * 3 + 21 / 5 << endl;   //-86
    cout << -30 + 3 * 21 / 5 << endl;   //-18
    cout << 30 / 3 * 21 % 5 << endl;    //0
    cout << -30 / 3 * 21 % 4 << endl;   //-2
    system("pause");
    return 0;
}

练习4.6

写出一条表达式用于确定一个整数是奇数还是偶数。

i % 2 ! = 0 ? “odd” : “even”

练习4.7

溢出是何含义?写出三条将导致溢出的表达式。

计算机计算结果超出该类型所能表示的范围。

#include 
using std::cout;
using std::endl;

int main()
{
    int a = 2147483647;
    cout << ++a << endl;            //-2147483648

    unsigned int b = 4294967295;
    cout << -b << endl;             //1

    short c = 32767;
    cout << ++c << endl;            //-32768

    system("pause");
    return 0;
}

练习4.8

说明在逻辑与、逻辑或及相等性运算符中运算对象的求值顺序。

  • 逻辑与:当且仅当左侧表达式为真时才运算右侧对象
  • 逻辑或:当且仅当左侧表达式为假时才运算右侧对象
  • 相等性:?

练习4.9

解释下面的if语句中条件部分判断过程
const char*cp=“Hello World”;
if(cp && *cp);

首先判断cp是否为空字符串,如果不为空字符串,解引用cp,判断cp[0]是否为真。

练习4.10

为while 循环写一个条件,使其从标准输入中读取整数,遇到 42 时停止。

#include 
using std::cin;
using std::cout;
using std::endl;

int main()
{
    int i = 0;
    while (cin >> i && i != 42)
    {
        cout << i << endl;//输入:45 88 21 42;输出:45 88 21
    }

    system("pause");
    return 0;
}

练习4.11

书写一条表达式用于测试4个值a、b、c、d的关系,确保a大于b、b大于c、c大于d。

a>b && b>c && c>d

练习4.12

假设i、j 和k 是三个整数,说明表达式 i != j < k 的含义。

首先,不相等运算符优先级低于小于运算符,所以先判断j,若为真则返回bool值1,否则返回bool值0,接着判断i是否不等于返回的bool值。

练习4.13

在下述语句中,当赋值完成后i和d的值分别为多少?
int i; double d;
(a) d=i=3.5; (b) i=d=3.5;

(a)i=3,d=3
(b)i=3,d=3.5
验证代码

#include 
using std::cout;
using std::endl;

int main()
{
    int i;
    double d;
    d = i = 3.5;
    cout << i << " " << d << endl;  //3 3
    i = d = 3.5;
    cout << i << " " << d << endl;  //3 3.5

    system("pause");
    return 0;
}

练习4.14

执行下述if语句后将发生什么情况?
if(42=i)//…
if(i=42)//…

第一句将报错,42不可修改,不能作为左值;
第二句赋值等价于:i=42;if(i)//…即if将永远判断为真(除非修改i的值为0)。

练习4.15

下面的赋值是非法的,为什么?如何修改?

double dval; int ival; int *pi;
dval=ival=pi=0;

pi是指向int类型的指针,无法实现int到int*类型的转换。
可以修改为:dval=ival=*pi=0;即将pi指向的int类型赋值为0.

练习4.16

尽管下面的语句合法,但他们实际执行的行为可能和预期不一样,为什么?如何修改?

(a) if(p=getPtr()!=0)\\...
(b) if(i=1024)\\...

(a)由于赋值运算符优先级小于不等运算符,所以实际上先判断的是getPtr()!=0,赋值给p的是返回得到的bool值,可修改为:if((p=getPtr())!=0)
(b)实际上执行过程是将1024赋值给i,然后判断if(i),当i不为0时将永远判断为真,可修改为:if(i==1024)

练习4.17

说明前置运算符和后置运算符的区别。

前置运算符先将对象加一然后返回;后置运算符是先返回初始对象副本,然后将对象加一。

#include 
using std::cout;
using std::endl;

int main()
{
    int a = 0, b = 0;
    cout << ++a << endl;    //1
    cout << b++ << endl;    //0

    system("pause");
    return 0;
}

练习 4.18

如果132页那个输出vector对象元素的while循环使用前置递增运算符,将得到什么结果?

整体解引用的地址将后移一个单位,原本解引用范围为0->(size-1),现在为1->size

练习4.19

假设 ptr 的类型是指向 int 的指针、vec 的类型是vector、ival 的类型是int,说明下面的表达式是何含义?如果有表达式不正确,为什么?应该如何修改?

(a) ptr!=0 && *ptr++				
(b) ival++ && ival
(c) vec[ival++]<=vec[ival]

(a)若ptr不为空指针,判断ptr当前指向值是否不为零,且ptr向后移动一个单位;
(b)先判断ival的值是否不为零,ival+1,然后判断ival加一后的值是否不为零;
(c)实际上是比较vec[ival]小于等于vec[ival+1]是否为真。

练习4.20

假设 iter 的类型是 vector::iterator, 说明下面的表达式是否合法。如果合法,表达式的含义是什么?如果不合法,错在何处?

(a) *iter++;				(b) (\*iter)++;				
(c) *iter.empty();			(d) iter->empty();		
(e) ++*iter;				(f) iter++->empty();

(a)合法,先将iter后移一个单位,返回iter初始值并对初始值解引用;
(b)不合法,iter解引用后为string类型,不能使用递增运算符;
(c)不合法,成员选择运算符优先级高于解引用,而iter没有empty成员函数;
(d)合法,等同于(*iter).empty()
(e)不合法,string不能使用递增运算符;
(f)合法,先调用(*iter).empty(),再将iter后移一个单位。

练习4.21

编写一段程序,使用条件运算符从vector中找出那些元素的值是奇数,然后将这些奇数值翻倍.

#include 
#include 
using std::cout;
using std::endl;
using std::vector;

int main()
{
    vector<int> v(10);
    int count = 1;
    for (auto &i : v)
    {
        i = (count % 2) ? 2 * count : count;
        count += 1;
        cout << i << " ";//2 2 6 4 10 6 14 8 18 10 
    }
    system("pause");
    return 0;
}

练习4.22

本节的示例程序将成绩划分为high pass、pass 和 fial 三种,扩展该程序使其进一步将 60 分到 75 分之间的成绩设定为 low pass。要求程序包含两个版本:一个版本只使用条件运算符;另一个版本使用1个或多个if语句。哪个版本的程序更容易理解呢?为什么?

if版本逻辑结构清晰,更容易理解。

#include 
using std::cout;
using std::endl;

void test01(int grade)
{
    cout << ((grade > 90) ? "high pass" : (grade > 75) ? "pass"
                                      : (grade < 60)   ? "fail"
                                                       : "low pass")
         << endl;
}

void test02(int grade)
{
    if (grade > 90)
        cout << "high pass" << endl;
    else
    {
        if (grade > 75)
            cout << "pass" << endl;
        else
        {
            if (grade < 60)
                cout << "fail" << endl;
            else
                cout << "low pass" << endl;
        }
    }
}

int main()
{
    int grade1 = 93;
    int grade2 = 80;
    int grade3 = 66;
    int grade4 = 58;

    test01(grade1);//high pass
    test02(grade1);//high pass
    cout << '\n';

    test01(grade2);//pass
    test02(grade2);//pass
    cout << '\n';

    test01(grade3);//low pass
    test02(grade3);//low pass
    cout << '\n';

    test01(grade4);//fail
    test02(grade4);//fail
    cout << '\n';
    system("pause");
    return 0;
}

练习4.23

因为运算符优先级问题,下面这条表达式无法通过编译。根据4.12节的表指出问题在哪里,如何修改?
string s=“word”;
string p1=s+s[s.size()-1]==‘s’?“”:“s”;

加法运算符的优先级高于条件运算符,所以本语句首先执行s+s[s.size()-1]
可修改为:string p1=s+(s[s.size()-1]=='s'?"":"s");

练习4.24

本节的示例程序将成绩划分为 high pass、pass、和fail三种,它的依据是条件运算符满足右结合律。假如条件运算符满足的是左结合律,求值的过程将是怎样的?

没懂(

练习4.26

如果一台机器上int占32位、char占8位,用的是Latin-1字符集,其中字符’q’的二进制形式是01110001,那么表达式~‘q’<<6的值是什么?

首先提升为int类型:

00000000 00000000 00000000 01110001

然后取反:

11111111 11111111 11111111 10001110

最后向左移动6位:

 11111111 11111111 11100011 10000000

练习4.26

在本节关于测验成绩的例子中,如果使用unsigned int作为quiz1的类型会发生什么情况?

unsigned int类型只能占用16位,无法完成统计30个学生成绩的任务,会导致数据丢失。

练习4.27

下列表达式的结果是什么?

usigned long ull=3,ul2=7;
(a) ul1 & ul2;
(b) ul1 | ul2;
(c) ul1 && ul2;
(d) ul1 || ul2;

(a)表示对ul1和ul2进行按位与操作:

(前24位均为0)00000011
&
(前24位均为0)00000111

所得结果为:

(前24位均为0)00000011

(b)表示对ul1和ul2进行按位或操作:

(前24位均为0)00000011
|
(前24位均为0)00000111

所得结果为:

(前24位均为0)00000111

(c)表示对ul1和ul2进行逻辑与操作,由于都不为零,所以结果为1.
(d)表示对ul1和ul2进行逻辑或操作,由于不都为零,所以结果为1.

练习4.28

编写一段程序,输出每一种内置类型所占空间大小

#include 
using std::cout;
using std::endl;
int main()
{
    cout << sizeof(bool) << endl;       //1
    cout << sizeof(char) << endl;       //1
    cout << sizeof(short) << endl;      //2
    cout << sizeof(int) << endl;        //4
    cout << sizeof(long) << endl;       //4
    cout << sizeof(long long) << endl;  //8
    system("pause");
    return 0;
}

练习4.29

推断下面代码输出结果并说明理由。实际运行这段程序,结果和你想象的一样吗?如果不一样,为什么?

int x[10];int *p=x;
cout<<sizeof(x)/sizeof(*x)<<endl;
cout<<sizeof(p)/sizeof(*p)<<endl;

sizeof(x)/sizeof(*x)得到的结果是数组的大小,即10;
sizeof§/sizeof(*p)=指针p的大小/指针p指向空间的大小,4/4=1;

练习4.30

根据p142页的表,在下述表达式的适当位置添加括号,使得加上括号之后的表达式含义和原来相同。

(a) sizeof x + y		(b) sizeof p->mem[i]
(c) sizeof a < b		(d) sizeof f()

(a)sizeof优先级高于加法运算符,所以先执行sizeof。添加括号:sizeof(x)+y;
(b)sizeof优先级低于成员选择运算符。添加括号:sizeof(p->mem[i]);
(c)sizeof优先级高于关系运算符。添加括号:sizeof(a) (d)sizeof优先级低于函数调用运算符。添加括号:sizeof( f() ).

练习4.31

本节程序使用了前置版本的递增运算符和递减运算符,解释为什么要用前置版本而不用后置版本。要想使用后置版本的递减递增运算符需要做哪些改动?使用后置版本重写本节程序。

for循环中执行的语句顺序为:

  1. 初始化:vector::size_type ix=0;
  2. 判断:ix != ivec.size()
  3. 语句:ivec[ix]=cnt
  4. 递增递减:++ix, --cnt
  5. 判断:ix != ivec.size()
  6. 语句:ivec[ix]=cnt
  7. 递增递减:++ix, --cnt
  8. (5-7重复)
    如果我们使用后置版本,即第4步修改为:ix++, cnt–。那么就会执行递增递减后返回ix、cnt初始值的副本。虽然得到的结果是一样的,但是多了一个存储返回初始值副本的步骤,有些浪费.
#include 
#include 
using std::cout;
using std::endl;
using std::vector;
int main()
{
    vector<int> ivec(10);
    vector<int>::size_type cnt = ivec.size();
    for (vector<int>::size_type ix = 0; ix < ivec.size(); ix++, cnt--)
    {
        cout << "ivec[" << ix << "]: " << cnt << endl;
        ivec[ix] = cnt;
    }
    system("pause");
    return 0;
}

输出:

ivec[0]: 10
ivec[1]: 9
ivec[2]: 8
ivec[3]: 7
ivec[4]: 6
ivec[5]: 5
ivec[6]: 4
ivec[7]: 3
ivec[8]: 2
ivec[9]: 1

练习 4.32

解释下面这个循环的含义。

constexpr int size=5;
int ia[size]={1,2,3,4,5};
for(int *ptr=ia,ix=0;ix!=size && ptr!=ia+size;++ix,++ptr)
{/*...*/}

遍历数组ia

练习4.33

根据p147页的表说明下面这条表达式的含义

someValue ? ++x, ++y : --x, --y

首先逗号运算符优先级最低,接着是三目运算符。从右向左看,表达式可以分割为:( someValue ? ++x, ++y : --x), --y;
也就是说如果someValue为真,则执行语句:++x,++y,–y
如果someValue为假,则执行语句:–x,–y。

练习4.34

根据本节给出的变量定义,说明在下面的表达式中将发生什么样的类型转换:

(a) if(fval)	(b) dval=fval+ival;		(c)dval+ival*cval

(a)float转bool
(b)先执行加法运算符,即int转float,加法得到float类型赋值时转为double
(c)先执行乘法,char转int,乘法得到的int类型在执行加法时转为double

练习4.35

假设有如下定义:
char cval; int ival; unsigned int ui;
float fval; double dval;
请回答在面的表达式中发生了隐式类型转换吗?如果有,指出来

(a) cval='a'+3		(b) fval=ui-ival*1.0
(c) dval=ui*fval	(d) cval=ival+fval+dval

(a)字符’a’先转化为int类型执行加法,得到int类型在赋值过程中转化为char
(b)先执行乘法,ival提升为double以后执行乘法,ui也提升为double然后执行减法,赋值过程中转为float
(c)unsigned int类型转float执行乘法,赋值时转为double
(d)int转float执行加法,再转double执行加法,赋值时转char

练习4.36

假设i是int类型,d是double类型,书写表达式i *= d使其执行整数类型的乘法而非浮点数的乘法。

i*=static_cast(int)d

练习4.37

用命名的强制转化类型改写下列旧式的转化语句。

int i;double d;const string *ps;char *pc;void *pv;
(a) pv=(void *)ps;	(b) i=int(*pc);
(c) pv=&d;			(d) pc=(char*)pv;

(a)pv=const_castps;
(b)i=static_cast(*pc);
(c)pv=static_cast(&d);
(d)pc=reinterpret_cast(pv);

练习4.38

说明下面这条表达式的含义。
double slope=static_cast(j/i);

将j/i的结果强制转换为double类型然后赋值给slope。

你可能感兴趣的:(C/C++,c++,算法,开发语言)