C++primer习题集(第四章 )

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

  值为105

  逻辑为( 5 + ( (10 * 20 ) / 2 ) )

 


 

4.2 在下述表达式的合理位置添加括号,使得添加括号后运算对象的组合顺序与添加前一致。

(a) *vec.begin() --> *(vec.begin())
(b) *vec.begin() + 1 --> ( *(vec.begin()) + 1)

  


 

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

  一方面,这样导致了二元运算符的可移植性不好(但是可以用括号弥补)

  另一方面,这样子做可以让编译器更好利用硬件资源(适配硬件),提高速度

  感觉缺陷是可以弥补的,但是好处却是不可以替代的,这样做我觉得挺好的。

 


 

4.4 在下列表达式中加上括号,说明过程以及结果。编写程序(不加括号)对你的结果进行验证。

// (((12/3)*4)+(5*15)+((24%4)/2))   预计,91
#include<iostream>
#include<string>
using namespace std;

int main()
{
    int x=12/3*4+5*15+24%4/2;
    cout<<x<<endl;
    return 0;
}

 


 

4.5 写出下列表达式的求值结果。

#include<iostream>
#include<string>
using namespace std;

int main()
{
    int x1= -30 * 3 + 21 / 5;   //-86
    int x2= -30 + 3 * 21 / 5;   //-18
    int x3= 30 / 3 * 21 % 5;    //0
    int x4= -30 / 3 * 21 % 4;   //-2
    cout<<x1<<endl;
    cout<<x2<<endl;
    cout<<x3<<endl;
    cout<<x4<<endl;
    return 0;
}

 


 

4.6 写出一条表达式用于判断一个数是奇数还是偶数。

#include<iostream>
#include<string>
using namespace std;

int main()
{
    string s;
    int x1= -30 * 3 + 21 / 5;   //-86
    s=x1%2 ? "奇数":"偶数";
    cout<<s<<endl;

    return 0;
}

 


 

4.7 溢出是什么含义?写三条导致溢出的表达式。

  溢出,包括整数溢出,浮点数溢出以及内促溢出。

    int16_t x=65535+1;  //2^16,整数溢出
    float f=3.4e-50//浮点数溢出
    int a[10];
    a[10]=1;        //内存溢出

 


 

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

  • 在逻辑&&中,顺序是从左往右,遇到第一个0说明逻辑不成立
  • 在逻辑||中,顺序是从左往右,遇到第一个1说明逻辑成立
  • 在相等运算符中,也是从左往右判断。

 


 

4.9 解释在下面的if语句中条件部分的判断过程。

    const char *cp="hello world!";
    if(cp&&*cp) //判断cp地址不为0,且字符串内容不为空

 


 

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

    int x=0;
    while(x!=42){
        cin>>x;
        cout<<x<<endl;
    }

 


 

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

#include<iostream>
#include<string>
using namespace std;

int main()
{
    int a,b,c,d;
    cout<<"请按顺序输入abcd的值:"<<endl;
    cin>>a>>b>>c>>d;
    if(a>b&&b>c&&c>d)
        cout<<"顺序一致!"<<endl;
    else
        cout<<"顺序不一致!"<<endl;

    return 0;
}

 


 

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

  根据优先级,先判断的是j<k,得到bool型的值temp,再计算i!=temp,得到bool型的结果。

    i,j,k=1,2,3     //i!=j<k  --->   1!=(2<3)   --->   false(0)
    i,j,k=2,3,4     //i!=j<k  --->   2!=(3<4)   --->   2!=True(1)   -->   True(1)

 


 

4.13 在下述语句中,当赋值完成后,i和d的值分别为多少?

#include<iostream>
#include<string>
using namespace std;

int main()
{
    int i;
    double d;
    //a
    d=i=3.5;    //i=3;d=3;
    cout<<i<<"   "<<d<<endl;
    //b
    i=d=3.5;    //i=3;d=3.5
    cout<<i<<"   "<<d<<endl;
    return 0;
}

 


 

4.14 执行下述if语句后会发生什么情况?

#include<iostream>
#include<string>
using namespace std;

int main()
{
    int i=10;
    //if(42=i)
    //    cout<<"42=i"<<endl;   //无法通过编译,不能给常量赋值
    if(i=42)              //赋值必定为1
        cout<<"i=42"<<endl;
    cout<<i<<endl;  //42
    return 0;
}

 


 

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

#include<iostream>
#include<string>
using namespace std;

int main()
{
    double dval;
    int ival;
    int *pi;
    
    //dval=ival=pi=0;  错在不能将指针类型pi赋给int类型的ival,这两个类型无法进行类型转换
    dval=ival=*pi=0;
    return 0;
}

 


 

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

    //a
    if(p=GetPtr()!=0)   //!=的优先级会高于=,所以先判断!=,得到的bool值赋给p,改法:加括号//b
    if(i=1024)      //将1024赋给i,作为赋值语句,成功必然返回1,改法:改成==

 


 

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

  •  前置(++i):在变量被使用之前,先将变量的值增加1。然后,表达式会使用增加后的值。
  •  后置(i++):在变量被使用之后,将变量的值增加1。然后,表达式会使用增加前的值。

 


 

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

#include<iostream>
#include<string>
#include<vector>
#include<string.h>
using namespace std;

int main()
{
    vector<int> v={1,2,3,4,5,6,7,8,9,10};
    auto pbeg=v.begin();
    while(pbeg!=v.end() && *pbeg >0)
        cout<<*++pbeg<<endl;

    return 0;
}

/*
范围为v[1]-v[10],最后一个值溢出了
2
3
4
5
6
7
8
9
10
1127348208
*/

 


 

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

    //a
    ptr != 0 && *ptr++; //判断指针指向的地址不为0且指针指的对象不为0;指针移到下一个int
    //b
    ival++ && ival;     //ival不为0,且ival+1不为0
    //c
    vac[ival++]<=vec[ival]; //vec[ival]<vec[ival+1]

 


 

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

    //a
    *iter++;    //合法,先对iter+1,然后对原来的iter的副本对解引用
    //b
    (*iter)++;  //不合法,string类型不能++
    //c
    *iter.empty();  //不合法,不能判断指针是否为空,应该是(*iter)++
    //d
    iter->empty();  //合法,判断string是否为空
    //e
    ++*iter;        //不合法,不能对*iter(也就是string)执行++操作
    //f
    iter++->empty();    //合法,先得到iter+1,然后对iter的副本指向的字符串进行判空
    return 0;

 


 

4.21 编写一段程序,使用条件运算符从vector<int>中找到哪些元素的值是奇数,然后把他们翻倍。

#include<iostream>
#include<string>
#include<vector>
#include<string.h>
using namespace std;

int main()
{
    vector<int> v={1,2,3,4,5,6,7,8,9,10};
    for(auto &it:v)
        it=(it%2==1 ? it*2 : it);
    for(auto it:v)
        cout<<it<<endl;
    return 0;
}

 


 

4.22 本节的示例程序将成绩划分为high、pass、fail三种,扩展使得进一步将60-75定义为low,要求两个版本,一个只用条件运算符;一个使用多个if。

#include<iostream>
#include<string>
#include<vector>
#include<string.h>
using namespace std;

int main()
{
    int grade=77;
    string eva;
    //first
    eva=grade>100 ? "ERROR" :
        grade>90 ? "high pass" :
        grade>75 ? "pass" :
        grade>60 ? "low pass" :
            "fail";
    cout<<eva<<endl;
    //second
    if(grade>100)
        eva="ERROR";
    else if(grade>90)
        eva="high pass";
    else if(grade>75)
        eva="pass";
    else if(grade>60)
        eva="low pass";
    else
        eva="fail";
    cout<<eva<<endl;
    return 0;
}

 


 

4.23 因为运算符的优先级问题,下面表达式无法编译通过。指出他的问题,应该如何修改?

    string s="word";
    string p1=s+s[s.size()-1]=='s'?"":"s";

  优先级从高到低:+,==,?:,=

  所以第一步是s+s[s.size()-1],得到新的字符串;

  第二步新的字符串与字符's'比较(此处字符串与字符比较是错误的)

  第三步······依次进行

 


 

4.24 本节的示例程序将成绩划分为high、pass、fail三种,依据是运算满足右结合律。加入条件运算满足的是左结合律,求值过程又是如何?

如果是左结合律,那么顺序如下:
finalgrade = ( (grade>90)?"high pass":grade<60) ) ? "fail" : "pass";
显然,这样子会因为第一个条件运算符的分支(grade<60)不是string类型

 


 

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

#include<iostream>
#include<string>
#include<vector>
#include<string.h>
#include<bitset>
using namespace std;

int main()
{
    bitset<8> q=01110001;
    cout<<(~q<<6);
    return 0;
}

/*
10000000
如果设定为二进制数,首先对它取反,然后左移六位
*/
int main()
{
    char q='q';
    cout<<(~q<<6);
    return 0;
}

/*
-7296
如果是char型,那么会自动转换为int类型,先对他取反,然后左移六位,结果是-7296
*/

 


 

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

  在某些系统上,int是16位的,可能会导致不够用,因此还是long比较适合。

 


 

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

#include<iostream>
using namespace std;

int main()
{
    unsigned long ul1=3,ul2=7;
    //a
    cout<<(ul1&ul2)<<endl;
    //b
    cout<<(ul1|ul2)<<endl;
    //c
    cout<<(ul1&&ul2)<<endl;
    //d
    cout<<(ul1||ul2)<<endl;
    return 0;
}

/*
3   按位与
7   按位或
1  A&&B均不为0
1  A||B至少一个不为0

*/

 


 

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

int main()
{
    cout << sizeof (int) << endl;               // 4
    cout << sizeof (char) << endl;             // 1
    cout << sizeof (short) << endl;            // 2
    cout << sizeof (long) << endl;             // 8
    cout << sizeof (float) << endl;             // 4
    cout << sizeof (double) << endl;            // 8
    cout << sizeof (long double) << endl;       // 16
    cout << sizeof (long long) << endl;         // 8
    return 0;
}

 


 

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

#include<iostream>
using namespace std;

int main()
{
    int x[10];
    int *p=x;
    cout<<sizeof(x)/sizeof(*x)<<endl;   //10,sizeof(x)=4*10,sizeof(*x)=4
    cout<<sizeof(p)/sizeof(*p)<<endl;   //1, sizeof(p)=4,这是指针大小,sizeof(*p)=4,这是int大小
    return 0;
}

 


 

4.30 根据4.12节里面的表(147面)。在下述表达式的适当位置加上括号,使得表达式前后含义一致。

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

 


 

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

vecot<int>::size_type ix=0;
for(vector<int>::size_type ix=0;ix!=ivec.size();ix++,cnt--)
    ivec[ix]=cnt
/*
使用前置运算符可以避免多余的工作。
后置运算符是需要拷贝一个当前副本,然后才+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数组,ix是下标方法,ptr是指针方法
*/

 


 

4.33  根据4.12节中的表(147页)说明下面表达式的含义。

someValue ? ++x,++y:--x,--y;
/*
逗号优先级最低,但是?:为三目运算符
若someValue不为0,则对x和y执行自增操作;为0则x执行自减操作。--y为单独的语句
可以理解为(someValue ? (++x,++y):--x),--y
*/

 


 

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

    //a     float->bool
    if (fval)
    //b     int->float,float->double
    dval=fval+ival;
    //c     char->int,int->double
    dval+ival*cval

 


 

4.35 假设有如下定义,则下面表达式中是否发生了隐式转化?如果有,请指出来。

    char cval;
    int ival;
    unsigned int ui;
    float fval;
    double dval;
    
    //a     'a'->int,int->char
    cval='a'+3;
    //b     ival->double,ui->double,double->float
    fval=ui-ival*1.0
    //c     ui->float,float->double
    dval=ui*fval;
    //d     ival->float,float->double,double->char
    cval=ival+fval+dval;  

 


 

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

#include<iostream>
using namespace std;

int main()
{
    int i=10;
    double d=5.3;
    i*=static_cast<int>(d);

    cout<<i;

    return 0;
}

 


 

4.37 用命名的前置类型转换改写下列旧式的转换语句。

    int i;
    double d;
    const string *ps;
    char *pc;
    void *pv;
    
    //a     pv=(void *)ps;
    pv=const_cast<string*>(ps);
    //b     i=int(*pc);
    i=static_cast(int)(*pc);
    //c     pv=&d;
    pv=static_cast(void*)(d);
    //d     pc=(char*)pv
    pc=reinterpret_cast(char*)(pv);

 


 

4.38 说明下面这条表达式的含义。

    double slope=static_cast<doouble>(j/i);
    
    /*将j/i的值,做强制类型转换,改为double型*/

 

 



 搞定~

 

posted @ 2023-08-09 14:54  para_dise  阅读(33)  评论(0)    收藏  举报