C++面试题

目录

1. 指针和引用的区别?

2. 静态变量什么时候初始化

3. mutable

4. C++模板是什么,底层怎么实现的?

5. 虚函数可以声明为inline吗?

6. 类成员初始化方式?构造函数的执行顺序 ?为什么用成员初始化列表会快一些?

7. 必须使用成员列表初始化的情况

8. 在C++中析构函数可以是纯虚的吗

9. 构造函数析构函数可以调用虚函数吗?

10. 构造函数析构函数可否抛出异常

11. 类如何实现只能静态分配和只能动态分配

12. 什么情况会自动生成默认构造函数?

13. 什么是组合?

14. 继承机制中对象之间如何转换?

15. 如何在共享内存上使用STL(Standard Template Library)标准库?

16. vector越界访问下标,map越界访问下标?vector删除元素时会不会释放空间?

17. 说说你对C和C++的看法,c和c++的区别?

18. C/C++的内存分配,详细说一下栈、堆、静态存储区?

19. 关于使用智能指针管理内存资源,RAII

20. 位运算

21. define分别与const、typedef、inline的区别

22. lambda函数

23. 模板类和模板函数的区别是什么?

24. 为什么模板类一般都是放在一个.h文件中

25. 重载运算符?

26. 重载函数匹配原则

27. C++的四种类型转换

28. 静态成员与普通成员的区别

30. 隐式转换,如何消除隐式转换?

31.虚函数的内存结构,那菱形继承的虚函数内存结构呢

32. 多继承的优缺点,作为一个开发者怎么看待多继承

33. 迭代器++it,it++哪个好,为什么

34. C++如何处理多个异常的?

35. 在成员函数中调用delete this会出现什么问题?对象还可以使用吗?

36. 智能指针的作用;

37. class、union、struct的区别

38. 动态联编与静态联编

39. 动态编译与静态编译

40. volatile关键字的作用?

41. 讲讲大端小端,如何检测

42. 空类会默认添加哪些东西?怎么写?空类的大小是多少?为什么?

43. 为什么拷贝构造函数必须传引用不能传值?

44. 静态函数能定义为虚函数吗

45. this指针调用成员变量时,堆栈会发生什么变化?

46. 类对象的大小

47. 移动构造函数

48. 何时需要合成复制构造函数

49. 何时需要成员初始化列表?过程是什么?

50. 构造函数的执行步骤

51. 哪些函数不能是虚函数

52. 将“引用”作为函数参数有哪些特点?

53. 如何禁止自动生成拷贝构造函数?

54. C++怎么实现一个函数先于或后于main函数运行

55. 虚函数与纯虚函数的区别在于

56. 为什么要用static_cast转换而不用c语言中的转换?

57. 成员函数里memset(this,0,sizeof(*this))会发生什么

58. 回调函数的作用

59. 随机数的生成


1. 指针和引用的区别?

(1) 指针是一个实体,需要分配内存空间。引用只是变量的别名,不需要分配内存空间。

(2) 指针在定义的时候不一定要初始化,并且指向的空间可变。引用在定义的时候必须进行初始化,并且不能够改变。(注:引用的值不能为nullptr)

(3) 有多级指针,但是没有多级引用,只能有一级引用。

(4) 指针和引用的自增运算结果不一样。指针是指向下一个空间,引用时引用的变量值加1

(5) sizeof 指针得到的是指针本身的大小。而sizeof 引用得到的是所指向的变量(对象)的大小

(6) 而指针访问一个变量是间接访问。引用访问一个变量是直接访问。

2. 静态变量什么时候初始化

(1) 初始化只有一次,但是可以多次赋值,在主程序之前,编译器已经为其分配好了内存。

(2) 在C中,初始化发生在代码执行之前,编译阶段分配好内存之后,就会进行初始化,所以我们看到在C语言中无法使用变量对静态局部变量进行初始化。

(3) 而在C++中,初始化时在执行相关代码时才会进行初始化。

主要是由于C++引入对象后,要进行初始化必须执行相应构造函数和析构函数,在构造函数或析构函数中经常会需要进行某些程序中需要进行的特定操作,并非简单地分配内存。所以C++标准定为全局或静态对象是有首次用到时才会进行构造,并通过atexit()来管理。在程序结束,按照构造顺序反方向进行逐个析构。所以在C++中是可以使用变量对静态局部变量进行初始化的。

3. mutable

如果需要在const成员方法中修改一个成员变量的值,那么需要将这个成员变量修饰为mutable。即用mutable修饰的成员变量不受const成员方法的限制;

4. C++模板是什么,底层怎么实现的?

(1) 编译器从函数模板通过具体类型产生不同的函数;编译器会对函数模板进行两次编译:在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。

(2) 在使用函数模板的源文件中包含函数模板的头文件,如果该头文件中只有声明,没有定义,那编译器无法实例化该模板,最终导致链接错误。

5. 虚函数可以声明为inline吗?

可以,但编译器不一定会这么做

(1) 虚函数用于实现运行时的多态,或者称为晚绑定或动态绑定。而内联函数用于提高效率。内联函数的原理是,在编译期间,对调用内联函数的地方的代码替换成函数代码。内联函数对于程序中需要频繁使用和调用的小函数非常有用。

(2) 虚函数要求在运行时进行类型确定,而内敛函数要求在编译期完成相关的函数替换;

如果virtual可以在编译期决定调用什么函数,那么就可以被inline

6. 类成员初始化方式?构造函数的执行顺序 ?为什么用成员初始化列表会快一些?

(1) 赋值初始化,通过在函数体内进行赋值初始化;列表初始化,在冒号后使用初始化列表进行初始化。

(2) 一个派生类构造函数的执行顺序如下:

①基类(虚基类)按照继承的顺序执行构造函数;

②类成员对象按照初始化顺序执行构造函数;

③派生类自己的构造函数。

(3) 赋值初始化时在构造函数当中做赋值的操作,而初始化列表是做纯粹的初始化操作。C++的赋值操作是会产生临时对象的。临时对象的出现会降低程序的效率。

7. 必须使用成员列表初始化的情况

(1) 必须使用成员初始化的四种情况

①当初始化一个引用成员时;

②当初始化一个常量成员时;

③当调用一个基类的构造函数,而它拥有一组参数时;

④当调用一个成员类的构造函数,而它拥有一组参数时;

(2) 成员初始化列表做了什么

①编译器会一一操作初始化列表,以适当的顺序在构造函数之内安插初始化操作,并且在任何显示用户代码之前;

②list中的项目顺序是由类中的成员声明顺序决定的,不是由初始化列表的顺序决定的;

8. 在C++中析构函数可以是纯虚的吗

可以,但是如果类包含纯虚析构函数,则必须为纯虚析构函数提供函数体。因为派生类的析构函数里面隐含调用了基类的析构函数。如果缺少~Base()的函数体,当然会出现错误。

9. 构造函数析构函数可以调用虚函数吗?

可以

在构造函数和析构函数中最好不要调用虚函数;在执行基类构造函数的时候,派生类的成员变量完全未初始化,那么如果此时调用的是派生类的虚函数,如果里面调用了派生类的成员变量,那么就导致出现错误

10. 构造函数析构函数可否抛出异常

(1) 构造函数可以抛出异常但不建议,如果在构造时发生问题,那么就不是一个完整的对象,因此析构函数也不会被调用,只会处理异常发生前的变量。

(2) 析构函数不可以抛出异常,通常异常发生时,C++机制会调用已经构造对象的析构函数来释放资源,此时如析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。

ps: 如果控制权基于异常的因素离开析构函数,而此时正有另一个异常处于作用状态,C++会调用terminate函数让程序结束;

11. 类如何实现只能静态分配和只能动态分配

ps: 静态分配发生在程序编译和连接的时候。动态分配则发生在程序调入和执行的时候。

前者是把new、delete运算符重载为private属性。后者是把构造、析构函数设为protected属性,再用子类来动态创建

12. 什么情况会自动生成默认构造函数?

(1) 类中有一个类成员含有默认构造函数的,编译器会为该类自动生成默认构造函数。

(2) 基类中含有默认构造函数,而派生类中没有定义默认构造函数,则编译器会为派生类提供一个上一层基类的默认构造函数。

(3) 类中含有虚函数时或基类为虚基类时,由于编译器要为该类生成虚函数表vtable,并为该类的对象生成指向该vtable的vptr,所以需要为该类合成默认构造函数

13. 什么是组合?

组合就是一个类里面的数据成员是另一个类的对象,即内嵌其他类的对象作为自己的成员;

ps: 创建组合类对象,构造函数的执行顺序:按照内嵌对象成员在组合类中的定义顺序调用内嵌对象的构造函数,与组合类构造函数的初始化列表顺序无关。然后执行组合类构造函数的函数体,析构函数调用顺序相反。

14. 继承机制中对象之间如何转换?

(1) 向上类型转换

将派生类指针或引用转换为基类的指针或引用被称为向上类型转换,向上类型转换会自动进行,而且向上类型转换是安全的。

(2) 向下类型转换

将基类指针或引用转换为派生类指针或引用被称为向下类型转换,向下类型转换不会自动进行,因为一个基类对应几个派生类,所以向下类型转换时不知道对应哪个派生类,所以在向下类型转换时必须加动态类型识别技术。如RTTI (Run-Time Type Identification) 技术,用dynamic_cast进行向下类型转换。

15. 如何在共享内存上使用STL(Standard Template Library)标准库?

(1) 考虑到要将STL容器放到共享内存中,而容器却自己在堆上分配内存。一个最笨拙的办法是在堆上构造STL容器,然后把容器复制到共享内存,并且确保所有容器的内部分配的内存指向共享内存中的相应区域,这基本是个不可能完成的任务。

(2) 一个方法就是进程A把容器放在共享内存中的确定地址上(fixed offsets),则进程B可以从该已知地址上获取容器。另外一个改进点的办法是,进程A先在共享内存某块确定地址上放置一个map容器,然后进程A再创建其他容器,然后给其取个名字和地址一并保存到这个map容器里。进程B知道如何获取该保存了地址映射的map容器,然后同样再根据名字取得其他容器的地址。

16. vector越界访问下标,map越界访问下标?vector删除元素时会不会释放空间?

(1) 通过下标访问vector中的元素时不会做边界检查,即便下标越界,程序也不会报错,而是返回这个地址中存储的值。如果想在访问vector中的元素时首先进行边界检查,可以使用vector中的at函数。通过使用at函数不但可以通过下标访问vector中的元素,而且在at函数内部会对下标进行边界检查。

(2) map的下标运算符[]的作用是:将key作为下标去执行查找,并返回相应的值;如果不存在这个key,就将一个具有该key和value的某人值插入这个map。

(3) erase()函数,只能删除内容,不能改变容量大小; clear()函数,只能清空内容,不能改变容量大小;如果要想在删除内容的同时释放内存,那么可以选择deque容器。

doc格式,60多页吧,几百道题吧,都有答案吧,看好在下!部分:1.求下面函数的返回值(微软)int func(x) { int countx = 0; while(x) { countx ++; x = x&(x-1); } return countx; } 假定x = 9999。 答案:8思路:将x转化为2进制,看含有的1的个数。2. 什么是“引用”?申明和使用“引用”要注意哪些问题?答:引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。3. 将“引用”作为函数参数有哪些特点?(1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。4. 在什么时候需要使用“常引用”? 如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;例1int a ;const int &ra=a;ra=1; //错误a=1; //正确 例2string foo( );void bar(string & s); 那么下面的表达式将是非法的:bar(foo( ));bar("hello world"); 原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。引用型参数应该在能被定义为const的情况下,尽量定义为const 。5. 将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!注意事项:(1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。 (2)不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。(3)可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。(4)流操作符重载返回值申明为“引用”的作用:流操作符<>,这两个操作符常常希望被连续使用,例如:cout << "hello" << endl; 因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个<<操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用<<操作符。因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。 赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。例3#i nclude int &put(int n);int vals[10];int error=-1;void main(){put(0)=10; //以put(0)函数值作为左值,等价于vals[0]=10; put(9)=20; //以put(9)函数值作为左值,等价于vals[9]=20; cout<<vals[0]; cout<<vals[9];} int &put(int n){if (n>=0 && n<=9 ) return vals[n]; else { cout<<"subscript error"; return error; }} (5)在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用,Effective C++[1]的Item23详细的讨论了这个问题。主要原因是这四个操作符没有side effect,因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。6. “引用”与多态的关系?引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。例4Class A; Class B : Class A{...}; B b; A& ref = b;7. “引用”与指针的区别是什么?指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。此外,就是上面提到的对函数传ref和pointer的区别。8. 什么时候需要“引用”?流操作符<>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。以上 2-8 参考:http://blog.csdn.net/wfwd/archive/2006/05/30/763551.aspx9. 结构与联合有和区别?1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。 2. 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。10. 下面关于“联合”的题目的输出?a)#i nclude union{int i;char x[2];}a;void main(){a.x[0] = 10; a.x[1] = 1;printf("%d",a.i);}答案:266 (低位低地址,高位高地址,内存占用情况是Ox010A)………………
1.static有什么用途?(请至少说明两种) 1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。 2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。 3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用 2.引用与指针有什么区别? 1) 引用必须被初始化,指针不必。 2) 引用初始化以后不能被改变,指针可以改变所指的对象。 3) 不存在指向空值的引用,但是存在指向空值的指针。 3.描述实时系统的基本特性 在特定时间内完成特定的任务,实时性与可靠性。 4.全局变量和局部变量在内存中是否有区别?如果有,是什么区别? 全局变量储存在静态数据库,局部变量在堆栈。 5.什么是平衡二叉树? 左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1。 6.堆栈溢出一般是由什么原因导致的? 没有回收垃圾资源。 7.什么函数不能声明为虚函数? constructor函数不能声明为虚函数。 8.冒泡排序算法的时间复杂度是什么? 时间复杂度是O(n^2)。 9.写出float x 与“零值”比较的if语句。 if(x>0.000001&&x<-0.000001) 10.Internet采用哪种网络协议?该协议的主要层次结构? Tcp/Ip协议 主要层次结构为: 应用层/传输层/网络层/数据链路层/物理层。 11.Internet物理地址和IP地址转换采用什么协议? ARP (Address Resolution Protocol)(地址解析協議) 12.IP地址的编码分为哪俩部分? IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。 13.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。 循环链表,用取余操作做 14.不能做switch()的参数类型是: switch的参数不能为实型。 1.写出判断ABCD四个表达式的是否正确, 若正确, 写出经过表达式中 a的值(3分) int a = 4; (A)a += (a++); (B) a += (++a) ;(C) (a++) += a;(D) (++a) += (a++); a = ? 答:C错误,左侧不是一个有效变量,不能赋值,可改为(++a) += a; 改后答案依次为9,10,10,11 2.某32位系统下, C++程序,请计算sizeof 的值(5分). char str[] = “http://www.ibegroup.com/” char *p = str ; int n = 10; 请计算 sizeof (str ) = ?(1) sizeof ( p ) = ?(2) sizeof ( n ) = ?(3) void Foo ( char str[100]){ 请计算 sizeof( str ) = ?(4) } void *p = malloc( 100 ); 请计算 sizeof ( p ) = ?(5) 答:(1)17 (2)4 (3) 4 (4)4 (5)4 3. 回答下面的问题. (4分) (1).头文件中的 ifndef/define/endif 干什么用?预处理 答:防止头文件被重复引用 (2). #i nclude 和 #i nclude “filename.h” 有什么区别? 答:前者用来包含开发环境提供的库头文件,后者用来包含自己编写的头文件。 (3).在C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”声明? 答:函数和变量被C++编译后在符号库中的名字与C语言的不同,被extern "C"修饰的变 量和函数是按照C语言方式编译和连接的。由于编译后的名字不同,C++程序不能直接调 用C 函数。C++提供了一个C 连接交换指定符号extern“C”来解决这个问题。 (4). switch()中不允许的数据类型是? 答:实型 4. 回答下面的问题(6分) (1).Void GetMemory(char **p, int num){ *p = (char *)malloc(num); } void Test(void){ char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); } 请问运行Test 函数会有什么样的结果? 答:输出“hello” (2). void Test(void){ char *str = (char *) malloc(100); strcpy(str, “hello”); free(str); if(str != NULL){ strcpy(str, “world”); printf(str); } } 请问运行Test 函数会有什么样的结果? 答:输出“world” (3). char *GetMemory(void){ char p[] = "hello world"; return p; } void Test(void){ char *str = NULL; str = GetMemory(); printf(str); } 请问运行Test 函数会有什么样的结果? 答:无效的指针,输出不确定 5. 编写strcat函数(6分) 已知strcat函数的原型是char *strcat (char *strDest, const char *strSrc); 其中strDest 是目的字符串,strSrc 是源字符串。 (1)不调用C++/C 的字符串库函数,请编写函数 strcat 答: VC源码: char * __cdecl strcat (char * dst, const char * src) { char * cp = dst; while( *cp ) cp++; /* find end of dst */ while( *cp++ = *src++ ) ; /* Copy src to end of dst */ return( dst ); /* return dst */ } (2)strcat能把strSrc 的内容连接到strDest,为什么还要char * 类型的返回值? 答:方便赋值给其他变量 6.MFC中CString是类型安全类么? 答:不是,其它数据类型转换到CString可以使用CString的成员函数Format来转换 7.C++中为什么用模板类。 答:(1)可用来创建动态增长和减小的数据结构 (2)它是类型无关的,因此具有很高的可复用性。 (3)它在编译时而不是运行时检查数据类型,保证了类型安全 (4)它是平台无关的,可移植性 (5)可用于基本数据类型 8.CSingleLock是干什么的。 答:同步多个线程对一个数据类的同时访问 9.NEWTEXTMETRIC 是什么。 答:物理字体结构,用来设置字体的高宽大小 10.程序什么时候应该使用线程,什么时候单线程效率高。 答:1.耗时的操作使用线程,提高应用程序响应 2.并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求。 3.多CPU系统中,使用线程提高CPU利用率 4.改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独 立的运行部分,这样的程序会利于理解和修改。 其他情况都使用单线程。 11.Windows是内核级线程么。 答:见下一题 12.Linux有内核级线程么。 答:线程通常被定义为一个进程中代码的不同执行路线。从实现方式上划分,线程有两 种类型:“用户级线程”和“内核级线程”。 用户线程指不需要内核支持而在用户程序 中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度 和管理线程的函数来控制用户线程。这种线程甚至在象 DOS 这样的操作系统中也可实现 ,但线程的调度需要用户程序完成,这有些类似 Windows 3.x 的协作式多任务。另外一 种则需要内核的参与,由内核完成线程的调度。其依赖于操作系统核心,由内核的内部 需求进行创建和撤销,这两种模型各有其好处和缺点。用户线程不需要额外的内核开支 ,并且用户态线程的实现方式可以被定制或修改以适应特殊应用的要求,但是当一个线 程因 I/O 而处于等待状态时,整个进程就会被调度程序切换为等待状态,其他线程得不 到运行的机会;而内核线程则没有各个限制,有利于发挥多处理器的并发优势,但却占 用了更多的系统开支。 Windows NT和OS/2支持内核线程。Linux 支持内核级的多线程 13.C++中什么数据分配在栈或堆中,New分配数据是在近堆还是远堆中? 答:栈: 存放局部变量,函数调用参数,函数返回值,函数返回地址。由系统管理 堆: 程序运行时动态申请,new 和 malloc申请的内存就在堆上 14.使用线程是如何防止出现大的波峰。 答:意思是如何防止同时产生大量的线程,方法是使用线程池,线程池具有可以同时提 高调度效率和限制资源使用的好处,线程池中的线程达到最大数时,其他线程就会排队 等候。 15函数模板与类模板有什么区别? 答:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化 必须由程序员在程序中显式地指定。 16一般数据库若出现日志满了,会出现什么情况,是否还能使用? 答:只能执行查询等读操作,不能执行更改,备份等写操作,原因是任何写操作都要记 录日志。也就是说基本上处于不能使用的状态。 17 SQL Server是否支持行级锁,有什么好处? 答:支持,设立封锁机制主要是为了对并发操作进行控制,对干扰进行封锁,保证数据 的一致性和准确性,行级封锁确保在用户取得被更新的行到该行进行更新这段时间内不 被其它用户所修改。因而行级锁即可保证数据的一致性又能提高数据操作的迸发性。 18如果数据库满了会出现什么情况,是否还能使用? 答:见16 19 关于内存对齐的问题以及sizof()的输出 答:编译器自动对齐的原因:为了提高程序的性能,数据结构(尤其是栈)应该尽可能 地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问 ;然而,对齐的内存访问仅需要一次访问。 20 int i=10, j=10, k=3; k*=i+j; k最后的值是? 答:60,此题考察优先级,实际写成: k*=(i+j);,赋值运算符优先级最低 21.对数据库的一张表进行操作,同时要对另一张表进行操作,如何实现? 答:将操作多个表的操作放入到事务中进行处理 22.TCP/IP 建立连接的过程?(3-way shake) 答:在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。   第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状 态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个 SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;   第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1) ,此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。 23.ICMP是什么协议,处于哪一层? 答:Internet控制报文协议,处于网络层(IP层) 24.触发器怎么工作的? 答:触发器主要是通过事件进行触发而被执行的,当对某一表进行诸如UPDATE、 INSERT 、 DELETE 这些操作时,数据库就会自动执行触发器所定义的SQL 语句,从而确保对数 据的处理必须符合由这些SQL 语句所定义的规则。 25.winsock建立连接的主要实现步骤? 答:服务器端:socker()建立套接字,绑定(bind)并监听(listen),用accept() 等待客户端连接。 客户端:socker()建立套接字,连接(connect)服务器,连接上后使用send()和recv( ),在套接字上写读数据,直至数据交换完毕,closesocket()关闭套接字。 服务器端:accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连 接。该新产生的套接字使用send()和recv()写读数据,直至数据交换完毕,closesock et()关闭套接字。 26.动态连接库的两种方式? 答:调用一个DLL中的函数有两种方法: 1.载入时动态链接(load-time dynamic linking),模块非常明确调用某个导出函数 ,使得他们就像本地函数一样。这需要链接时链接那些函数所在DLL的导入库,导入库向 系统提供了载入DLL时所需的信息及DLL函数定位。 2.运行时动态链接(run-time dynamic linking),运行时可以通过LoadLibrary或Loa dLibraryEx函数载入DLL。DLL载入后,模块可以通过调用GetProcAddress获取DLL函数的 出口地址,然后就可以通过返回的函数指针调用DLL函数了。如此即可避免导入库文件了 。 27.IP组播有那些好处? 答:Internet上产生的许多新的应用,特别是高带宽的多媒体应用,带来了带宽的急剧 消耗和网络拥挤问题。组播是一种允许一个或多个发送者(组播源)发送单一的数据包 到多个接收者(一次的,同时的)的网络技术。组播可以大大的节省网络带宽,因为无 论有多少个目标地址,在整个网络的任何一条链路上只传送单一的数据包。所以说组播 技术的核心就是针对如何节约网络资源的前提下保证服务质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值