笔试选择题总结5

一、 临界资源是指每次仅允许一个进程访问的资源。  临界资源是针对共享资源来说的。

属于临界资源的硬件有打印机、磁带机等,软件有消息缓冲队列、变量、数组、缓冲区等。 诸进程间应采取互斥方式,实现对这种资源的共享。

二、

网络互连设备根据不同层实现的机理不一样,又具体分为五类:
一、 网络传输介质 互联设备
二、网络 物理层 互联设备
三、 数据链路层 互联设备
四、网络层互联设备
五、 应用层 互联设备
笔试选择题总结5_第1张图片
三、 要明白这种攻击的基本原理,还是要从TCP连接建立的过程开始说起:
大家都知道,TCP与UDP不同,它是基于连接的,也就是说:为了在 服务端和客户端之间传送TCP数据,必须先建立一个 虚拟电路,也就是TCP连接,建立TCP连接的标准过程是这样的:
首先,请求端(客户端)发送一个包含SYN标志的TCP报文,SYN即同步(Synchronize),同步报文会指明客户端使用的端口以及TCP连接的初始序号;
第二步,服务器在收到客户端的SYN 报文后,将返回一个SYN+ACK的报文,表示客户端的请求被接受,同时TCP序号被加一,ACK即确认(Acknowledgment)。
第三步,客户端也返回一个确认报文ACK给服务器端,同样TCP序列号被加一,到此一个TCP连接完成。
以上的连接过程在TCP协议中被称为 三次握手(Three-way Handshake)。
问题就出在TCP连接的三次握手中,假设一个用户向服务器发送了SYN 报文后突然死机或掉线,那么服务器在发出SYN+ACK应答报文后是无法收到客户端的ACK报文的(第三次握手无法完成),这种情况下服务器端一般会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个未完成的连接,这段时间的长度我们称为SYN Timeout,一般来说这个时间是分钟的数量级(大约为30秒-2分钟);一个用户出现异常导致服务器的一个线程等待1分钟并不是什么很大的问题,但如果有一个恶意的攻击者大量模拟这种情况,服务器端将为了维护一个非常大的半连接列表而消耗非常多的资源----数以万计的半连接,即使是简单的保存并遍历也会消耗非常多的CPU时间和内存,何况还要不断对这个列表中的IP进行SYN+ACK的重试。实际上如果服务器的TCP/IP栈不够强大,最后的结果往往是堆栈溢出崩溃---即使服务器端的系统足够强大,服务器端也将忙于处理攻击者伪造的TCP连接请求而无暇理睬客户的正常请求(毕竟客户端的正常请求比率非常之小),此时从正常客户的角度看来,服务器失去响应,这种情况我们称作:服务器端受到了SYN Flood攻击(SYN 洪水攻击)。
关于synflood攻击的说法正确的是:
1.  服务端由于连接队列被占满而不能对外服务
2.  大量连接处于SYN_RECV状态
3.  使用硬件防火墙可以一定程度上抵御攻击
四、 a.   成员函数被重载的特征:

 1 )相同的范围(在同一个类中);

 2 )函数名字相同;

 3 )参数不同;

 4  virtual 关键字可有可无。

b. 覆盖是指派生类函数覆盖基类函数,特征是:

 1 )不同的范围(分别位于派生类与基类);

 2 )函数名字相同;

 3 )参数相同;

 4 )基类函数必须有 virtual 关键字。

c.“ 隐藏  是指派生类的函数屏蔽了与其同名的基类函数,规则如下:

 1 )如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载混淆)。

 2 )如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有 virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)

五、左外连接的结果集包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是连接列所匹配的行 

右外连接是左向外连接的反向连接。将返回右表的所有行。 

全外连接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。 

内连接使用比较运算符根据每个表共有的列的值匹配两个表中的行。

六、将整数数组(7-6-3-5-4-1-2)按照堆排序的方式原地进行升序排列,请问在第一轮排序结束之后,数组的顺序是_____。

每次最大堆构建完之后,都会把末尾元素与堆顶互换,这样当前最大元素就移到了当前数组的最后面,所以全部进行完之后,数组变成了升序排列。如果在每次堆顶与末尾元素互换的时候将堆顶输出,则是降序输出。可以自己模拟下过程。

步骤:原数组已经是一个大顶堆,可直接开始排序。
(大顶堆:每个节点的值都不小于自己两个左右子节的完全二叉树)
每轮输出堆顶元素后,以堆中最后一个元素代替之(由于此题要求原地排序,即不产生额外的空间,堆顶元素与最后一个元素交换)。再将新的顶点元素不断与其子节点中大于该元素的较大者交换,直到该元素大于其左右两个子节点,或成为叶子节点。此时将剩余元素调整成一个新的大顶推。
           7                        2                        6                       6
          /  \                      /  \                      /  \                     /  \
        6     3     ==>      6     3     ==>      2     3    ==>      5    3 
       /  \    /  \              /  \    /                /  \    /               /  \    /  
     5   4  1   2          5   4  1     7        5   4  1          2   4  1      7 

由此得出,第一轮结束后的顺序是:6,5,3,2,4,1,7。

七、全局对象的构造函数在main函数之前调用,析构函数在main函数之后调用。

局部栈对象在定义的时候调用构造函数,出了可见范围的时候调用析构函数。
堆对象在new的时候调用构造函数,delete的时候调用析构。
全局静态对象和全局对象一样。
局部静态对象在定义的时候调用构造,main函数之后调用析构
八、广义表的元素可以为空
九 、基类成员在派生类的访问属性取决于继承方式以及这些成员本来在基类中的访问属性
(1)基类的私有成员无论什么继承方式,在派生类中均不可以直接访问
(2)在公有继承下,基类的保护成员和公有成员均保持原访问属性
(3)在保护继承方式下,基类的保护和公有成员在派生类的访问属性均为保护属性
(4)在私有继承下,基类的保护和公有成员在派生类中的访问属性均为私有属性
          所以对于此题:
1.公有继承的私有成员不被继承,所以不能访问
2.私有继承的公有成员可以被类的方法访问,不能被对象访问,属于私有属性
3.公有继承的保护成员具有保护属性,只能被类的方法访问,不能被对象访问
十、 使用 char* p = new char[100]申请一段内存,然后使用delete p释放,有什么问题?B
 
     
  • 会有内存泄露
  • 不会有内存泄露,但不建议用
  • 编译就会报错,必须使用delete []p;
  • 编译没问题,运行会直接崩溃
C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]。 
关于 new[] 和 delete[],其中又分为两种情况:(1) 为基本数据类型分配和回收空间;(2) 为自定义类型分配和回收空间。
基本类型的对象没有析构函数,所以回收基本类型组成的数组空间用 delete 和 delete[] 都是应该可以的;但是对于类对象数组,只能用 delete[]。
   所以一个简单的使用原则就是:new 和 delete、new[] 和 delete[] 对应使用。

十一、假定指针变量p定义为“int *p=new int(100);”,要释放p所指向的动态内存,应使用语句( )A

  • delete p;
  • delete *p;
  • delete &p;
  • delete []p;

int* p = new int (100) 是创建一个int型的内存,并赋值为100; 

int *p = new int[100] 是创建100个int型的内存;
一般用法是new一个数组的话一般是delete [] 其他的直接delete即可。
但是其实对于内置数据类型,其实是delete[] 和delete都可以的。
十二、下面程序的输出结果是 D
1
2
3
char *p1= “123”, *p2 = “ABC”, str[50]=  "xyz" ;
strcpy (str+2, strcat (p1,p2));
cout << str;
  • xyz123ABC
  • z123ABC
  • xy123ABC
  • 出错
char* strcat(char *,const char*)//第一个参数所指向的内容必须可以修改,可以赋值为在栈上分配的数组
strcat(p1,p2)试图修改p1的内容,p1指向文字常量区,其指向的内容无法修改
十三、 有以下程序(strcpy 为字符串复制函数,strcat为字符串连接函数)
1
2
3
4
5
6
7
8
#include 
#include 
main( )
     char  a[ 10 ] =  "abc"  ,b[ 10 ] =  "012" ,c[ 10 ] =  "xyz" ;
     strcpy( a+ 1 ,b+ 2 );
     puts( strcat( a,c+ 1 ));
}

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

  • al2xyz
  • bc2yz
  • a2yz
  • 12yz
本题考查字符串处理函数strcpy和strcat,执行完strcpy(a+1,b+2);后,a变为a2,执行完strcat( a,c+1 )后,a变为a2yz,所以答案为C选项。
十四、 下列程序的打印结果是? D
1
2
3
char p1[15]=  "abcd" ,*p2=  "ABCD" , str[50]=  "xyz"
strcpy (str+2, strcat (p1+2,p2+1)); 
printf ( "%s" ,str);

  • xyabcAB
  • abcABz
  • ABabcz
  • xycdBCD
  • 运行出错
strcat(p1+2,p2+1); //返回以p1+2为首的字符串,即"cdBCD"
strcpy(str+2,strcat(p1+2,p2+1)); //将"cdBCD"copy到str+2位置上,并覆盖后面的内容,此时str为"xycdBCD"
十五、找程序的错和不足:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int test( char *value, int value_len, int flag)
{
     char temp_buf[BUF_SIZE];
     sprintf(temp_buf,value);
     char temp_new_buf= new char [value_len];
     if (flag)
     {
         strcat(temp_buf, "flag is true" );
         printf(temp_buf);
         return 1 ;
     }
     delete[] temp_new_buf;
     return 0 ;
}
1 在3行前加assert(value!=NULL);也可以if(value ==NULL) 设置个全局变量判断程序出错
2 temp_buf没有初始化
3 sprintf()函数,个人觉得这里没什么用 直接改成strcpy 并且对于返回值没有做判断
4 5行 temp_new_buf  new错了
5 strcat的返回值做判断
6 flag!=0的时候 不能delete 

你可能感兴趣的:(笔试选择题)