练习(二)

1.下面程序段的输出结果是

1
2
3
char *p1 = ” 123 ”, *p2 = ”ABC”, str[ 50 ] = “xyz”;
strcpy(str +  2 , strcat(p1, p2));
printr(“%s\n”, str)

xyz123ABC
z123ABC
xy123ABC
出错

2、有以下程序

1
2
3
4
5
6
#include <stdio.h>
main(){
     int  i= 0 ;
    i=~i;
    printf( "%d\n" ,i);

程序运行后的输出结果是?

8
0
1
-1
3.下列程序的运行结果是3,5,请为横线处选择合适的程序()
 
p++ ->n
(++p) ->n
(a+1) ->n
(p+1) ->n

4、以下叙述中正确的是()
语句int a[8] = {0}; 是合法的
语句 int a[] = {0};是不合法的,遗漏了数组的大小
语句 char a[2] = {"A", "B"}; 是合法的,定义了一个包含两个字符的数组
语句 char a[3]; a = "AB"; 是合法的,因为数组有三个字符空间的容量,可以保存两个字符
5、下列描述中,( )是错误的。
内联函数的主要解决程序的运行效率问题。
内联函数的定义或声明必须出现在内联函数第一次补调用之前。
内联函数中可以包括各种语句
对内联不可以进行异常接口声明
6、以下叙述中正确的是()
'\0'表示字符0
"a"表示一个字符常量
表达式:'a' &gt; 'b'的结果是"假"
'\"'是非法的

7、 下面有关final, finally, finalize的区别描述错误的是?
如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承
如果一个方法被声明为final,可以被覆盖
finally在异常处理时提供 finally 块来执行任何清除操作。
Java使用 finalize() 方法在垃圾收集器象从内存中清除出去之前做必要的清理工作

8、 如下代码的输出结果是()

 

1
11
-1
30

9、 当很频繁地对序列中部进行插入和删除操作时,应该选择使用的容器是()
vector
list
deque
stack
10、
int func(unsigned int i) {
unsigned int temp = i;
 temp = (temp & 0x55555555) + ((temp & 0xaaaaaaaa) >> 1);
 temp = (temp & 0x33333333) + ((temp & 0xcccccccc) >> 2);
 temp = (temp & 0x0f0f0f0f) + ((temp & 0xf0f0f0f0) >> 4);
 temp = (temp & 0x00ff00ff) + ((temp & 0xff00ff00) >> 8);
 temp = (temp & 0x0000ffff) + ((temp & 0xffff0000) >> 16); 
 return temp;
 }
请问 func(0x11530828)的返回值是:  1


11、写出程序的运行结果



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<iostream>
using namespace std;
 
class Base
{
     int x;
public :
     Base( int b): x(b) {}
     virtual void display()
     {
         cout << x;
     };
};
class Derived:  public Base
{
     int y;
public :
     Derived( int d): Base(d), y(d) {}  void display()
     {
         cout << y;
     }
};
 
int main()
{
     Base b(1);
     Derived d(2);
     Base *p = & d;
     b.display();
     d.display();
     p->display();
     return 0;
 
}
121
222
122
运行出错

12、“引用”与多态的关系?
两者没有关系
引用可以作为产生多态效果的手段
一个基类的引用不可以指向它的派生类实例
以上都不正确


13、若char是一字节,int是4字节,指针类型是4字节,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
class CTest
{
     public :
         CTest():m_chData(‘\0’),m_nData(0)
         {
         }
         virtual void mem_fun(){}
     private :
         char m_chData;
         int m_nData;
         static char s_chData;
};
char CTest::s_chData=’\0’;
问:
(1)若按4字节对齐sizeof(CTest)的值是多少?
(2)若按1字节对齐sizeof(CTest)的值是多少?
请选择正确的答案。
16 4
16 10
12 9
10 10

14、用C++语法来看,下列的哪个赋值语句是正确的?

char a=12
int a=12.0
int a=12.0f
int a=(int)12.0


15、 以下哪些做法是不正确或者应该极力避免的:【多选】( )
构造函数声明为虚函数
派生关系中的基类析构函数声明为虚函数
构造函数中调用虚函数
析构函数中调用虚函数

16、 下列关于运算符重载的叙述中,正确的是(        )
通过运算符重载,可以定义新的运算符
有的运算符只能作为成员函数重载
若重载运算符+,则相应的运算符函数名是+
重载二元运算符时,必须声明两个形参
17、下面是折半查找的实现,data是按升序排列的数据,x是查找下标,y是查找的上标,
v是查找的数值,返回v在data的索引,若没找到返回-1。代码不正确是____。
1
2
3
4
5
6
7
8
9
10
public int bsearch ( int [] data,  int x,  int y,  int v) {
     int m;
     while (x<y){  //1
         m = x + (y-x)/2;  //2
         if (data[m] == v)  return m;  //3
         else if (data[m] > v) y = m;  //4
         else x = m;  //5
     }
     return -1;  //6
}

18、对象引用作函数参数比用对象指针更方便些。
19、下面程序执行结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using namespace std;
class A{
     public:
         virtual void f() { cout <<  "A::f() " ; }
         void f() const { cout <<  "A::f() const " ; }
};
class B : public A {
     public:
         void f() { cout <<  "B::f() " ; }
         void f() const { cout <<  "B::f() const " ; }
};
void g(const A* a) {
     a->f();
}
int main(int argc, char *argv[]) {
     A* p =  new B();
     p->f();
     g(p);
     delete (p);
     return 0;
}
B::f() B::f() const
B::f() A::f() const
A::f() B::f() const
A::f() A::f() const

20、如果downcast是安全的(也就是,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果downcast不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。这个是指C++里的()

dynamic_cast
reinterpret_cast
static_cast
const_cast

解析:
1、 原代码有错:p1和p2都指向常量字符串,在常量区,所以不能对其进行操作;改为数组即可,但是用字符串初始化数组时要记得将数组长度加1,因为字符串默认的末尾有一个‘\0’;第二点要注意的是,strcat函数的p1要有足够的空间来容纳p1和p2连接后的串长。

修改为以下代码将可以:
char p1[7] = "123";
char p2[] = "ABC";
char str[50] = "xyz";
strcpy(str + 2, strcat(p1, p2));
printf("%s\n", str);
结果:
2、0 = 00000000000000000000000000000000 
取反11111111111111111111111111111111就是-1在计算机的存储形式
计算机内, 负数已反码形式存储, 符号位不变, 源码求反加1, 就是反码
11111111111111111111111111111111 就是 
10000000000000000000000000000001 求反 11111111111111111111111111111110 
加1 就是 11111111111111111111111111111111
3、-> 运算符优先级要比++ 运算符要高。
4、【解析】B选项中,如给全部元素赋值,则在数组说明中, 可以不给出数组元素的个数;C选项中,char a[2] = {"A", "B"};不合法,应为char a[2] = {'A', 'B'};;D选项中,用字符串方式赋值比用字符逐个赋值要多占1个字节,在该选项中应为3个字节。因此A选项正确。
5、
在内联函数中不允许使用循环语句(for,while)和switch结果,带有异常接口声明的函数也不能声明为内联函数。另外,递归函数(自己调用自己的函数)是不能被用来做内联函数的。内联函数只适合于只有1~5行的小函数。

6、

 A 选项中, '\0' 表示结束; B 选项中,字符常量是用单引号括起来的一个字符; D 选项中, '\"' 是双引号符。因此 C 选项正确。

7、

final

修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。

finally

异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。一般异常处理块需要。

方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。 

Java中所有类都从Object类中继承finalize()方法。

当垃圾回收器(garbage colector)决定回收某对象时,就会运行该对象的finalize()方法。

8、

 
 
该函数的作用是将两个数相加
num1^num2为两个数相加不带进位的结果
(num1&num2)<<1为两个数相加的进位值
递归调用将进位值加到相加结果上,不断递归知道进位为0为止,结果为num1与num2相加的值
9、

C++ STL 的实现:

1.vector  底层数据结构为数组 ,支持快速随机访问

2.list    底层数据结构为双向链表,支持快速增删

3.deque   底层数据结构为一个中央控制器和多个缓冲区,详细见STL源码剖析P146,支持首尾(中间不能)快速增删,也支持随机访问

4.stack   底层一般用23实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时

5.queue   底层一般用23实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时

6.45是适配器,而不叫容器,因为是对容器的再封装

7.priority_queue 的底层数据结构一般为vector为底层容器,堆heap为处理规则来管理底层容器实现

8.set       底层数据结构为红黑树,有序,不重复

9.multiset  底层数据结构为红黑树,有序,可重复 

10.map      底层数据结构为红黑树,有序,不重复

11.multimap 底层数据结构为红黑树,有序,可重复

12.hash_set 底层数据结构为hash表,无序,不重复

13.hash_multiset 底层数据结构为hash表,无序,可重复 

14.hash_map      底层数据结构为hash表,无序,不重复

15.hash_multimap 底层数据结构为hash表,无序,可重复 

vector表示一段连续的内存区域,随机访问效率很高,因为每次访问离起始处的位移都是固定的,但是在随意位置插入删除元素效率很低,因为它需要将后面的元素复制一遍。 list表示非连续的内存区域,并通过一对指向首尾元素的指针双向链接起来,从而允许向前和向后两个方向进行遍历。在list的任意位置插入和删除元素的效率都很高:指针必须被重新赋值,但不需要用拷贝元素来实现移动。他对随机访问支持不好,需要遍历中间的元素。每个元素有两个指针的额外空间开销。 deque(双端队列,发音为'deck')也表示一段连续的内存区域,但是他支持高效的在其首部插入和删除元素。 选择顺序容器类型的一些准则: 如果我们需要随机访问一个容器,则vector要比List好得多。 如果我们一直要存储元素的个数,则vector又是一个比list好的选择。 如果我们需要的不只是在容器两端插入和删除元素,则list显然比vector好。 除非我们需要在容其首部插入和删除元素,否则vector要比deque好。


10、

平行法计算二进制中1的个数,二进制中利用相邻位相加,直到最后剩下一个数,求出1的个数。
举例:
求255(1111 1111)二进制中1的个数。
1 1 1 1   1 1 1 1
  2    2     2    2
     4           4
            8
将255的8个位置进行编号,1号位置到8号位置,首先对12、34、56、78进行相加,得到2、2、2、2,分别存放于12、34、56、78位置,再将12、34、56、78看成一个整体,将12和34、56和78相加,得到4、4存放于1234、5678位置,最后再将1234和5678相加,得到8。算法也是利用了二分的思想,给定一个二进制数,将均分成两部分,分别求左边和右边的1的个数,然后相加,最后得到结果。

11、 如果调用的函数是实函数,则看指针的定义;如果调用的函数是虚函数,则看指针的指向(赋值)

12、引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。 
【例】: 
class A; 
class B:public A{……}; 
B b; 
A &Ref = b; // 用派生类对象初始化基类对象的引用 

Ref 只能用来访问派生类对象中从基类继承下来的成员,是基类引用指向派生类。如果A类中定义有虚函数,并且在B类中重写了这个虚函数,就可以通过Ref产生多态效果。
13、
若按4字节对齐sizeof(CTest)的值是12; 
若按1字节对齐sizeof(CTest)的值是9 
解释:

在类中,如果什么都没有,则类占用1个字节,一旦类中有其他的占用空间成员,则这1个字节就不在计算之内,如一个类只有一个int则占用4字节而不是5字节。

如果只有成员函数,则还是只占用1个字节,因为类函数不占用空间

虚函数因为存在一个虚函数表,需要4个字节,数据成员对象如果为指针则为4字节,注意有字节对齐,如果为13字节,则进位到16字节空间。

sizeof的本质是得到某个类型的大小,确切的来说就是当创建这个类型的一个对象(或变量)的时候,需要为它分配的空间的大小。而类也可以理解为类似于int、float这样的一种类型,当类中出现static成员变量的时候,static成员变量是存储在静态区当中的,它是一个共享的量,因此,在为这个类创建一个实例对象的时候,是无需再为static成员变量分配空间的,所以,这个类的实例对象所需要分配的空间是要排除static成员变量的,于是,当sizeof计算类的大小的时候会忽略static成员变量的大小
14、
从C/C++的角度去分析此题,A、B、C、D四项在编译的过程中:A项在赋值为0-127时无警告,但B/C/D均有损失精度的警告,编译还是能通过的。B、C、D项的区别是:B 项的默认为double型转向int型,C项因等号后“12.0f”的  ‘f’使其转换为folate型,D项直接通过在等号的右边加“(int)”强制类型转换,与B项相同的是:是从默认的double型转换为int型。A项会对应的ASCII字符,但在大于127时会发生常量截断会有警告。所以综上,此题A、B、C、D是都正确的
15、

A:构造函数不能声明为虚函数的原因是: 1 构造一个对象的时候,必须知道对象的实际类型,而虚函数行为是在运行期间确定实际类型的。而在构造一个对象时,由于对象还未构造成功。编译器无法知道对象 的实际类型,是该类本身,还是该类的一个派生类,或是更深层次的派生类。无法确定。。。

2 虚函数的执行依赖于虚函数表。而虚函数表在构造函数中进行初始化工作,即初始化vptr,让他指向正确的虚函数表。而在构造对象期间,虚函数表还没有被初 始化,将无法进行。
16、
  • 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。
  • 以下一些双目运算符不能重载为类的友元函数:=、()、[]、->。
  • 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。 C++提供4个类型转换函数:reinterpret_cast(在编译期间实现转换)、const_cast(在编译期间实现转换)、stactic_cast(在编译期间实现转换)、dynamic_cast(在运行期间实现转换,并可以返回转换成功与否的标志)。
  • 若一个运算符的操作需要修改对象的状态,选择重载为成员函数较好。
  • 若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数。
  • 当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部 类型的对象,该运算符函数必须作为一个友元函数来实现。
  • 当需要重载运算符具有可交换性时,选择重载为友元函数。

17、

  • 上下标没有写清楚,题目所指的应该是[x,y),这样5应该是m-1
    而在下标为[x,y]的情况下,1,4,5都是有问题的。。。。正确版本应该是这样吧
    while(x<=y) {
            m = x + (y-x)/2; //2
            if(data[m] == v) return m; //3
            else if(data[m] > v) y = m-1; //4
            else x = m+1; //5
        }
    补充:这里下标是个坑,记住上限有没有包含就可以对付1,4,5处的问题(熟记理解两个版本的代码区别),然后是2,写成x+(y-x)/2是防止xy都很大的情况下x+y越界。这样的话应对二分查找应该够了

18、在实际中,使用对象引用作函数参数要比使用对象指针函数更加普遍,这是因为使用对象引用作函数参数具有用对象指针函数参数的优点,而用对象引用作函数参数更加简单,更直接。

19、由于f()在基类中声明为虚的,则p->f()根据对象类型(B)调用B::f(),此时编译器对虚方法使用动态联编,输出B::f()。

由于f() const在基类中未声明为虚的,故p->f() const 根据指针类型(A)调用A::f() const,此时编译器对非虚方法使用静态联编,输出A::f() const。
20、
dynamic_cast将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理, 即会作一定的判断。 对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针; 对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。 
reinterpret_cast这个转换是最“不安全”的,两个没有任何关系的类指针之间转换都可以用这个转换实现。
static_cast静态转换是最接近于C风格转换,很多时候都需要程序员自身去判断转换是否安全。
const_cast这个转换好理解,可以将常量转成非常量。








  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HySmiley

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值