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型*/
搞定~

浙公网安备 33010602011771号