C++面试题、c++面试题

C++面试题、c++面试题

ID:83011160

大小:74.04 KB

页数:89页

时间:2023-09-19

上传者:无敌小子
C++面试题、c++面试题_第1页
C++面试题、c++面试题_第2页
C++面试题、c++面试题_第3页
C++面试题、c++面试题_第4页
C++面试题、c++面试题_第5页
C++面试题、c++面试题_第6页
C++面试题、c++面试题_第7页
C++面试题、c++面试题_第8页
C++面试题、c++面试题_第9页
C++面试题、c++面试题_第10页
资源描述:

《C++面试题、c++面试题》由会员上传分享,免费在线阅读,更多相关内容在行业资料-天天文库

1.介绍一下STL.详细说明STL如何实现vector。STL(标准模版库,StandardTemplateLibrary)它由容器算法迭代器组成。STL有以下的一些优点:可以方便容易地实现搜索数据或对数据排序等一系列的算法;调试程序时更加安全和方便;即使是人们用STL在UNIX平台下写的代码你也可以很容易地理解(因为STL是跨平台的)。vector实质上就是ー个动态数组,会根据数据的增加,动态的增加数组空间。2.如果用VC开发程序,常见这么几个错误,C200l,c2005,c2011,这些错误的原因是什么。在学习VC++的过程中,遇到的LNK2001错误的错误消息主要为;unresolvedexternalsymbol"symbol”(不确定的外部"符号")。如果连接程序不能在所有的库和目标文件内找到所引用的函数、变量或标签,将产生此错误消息。一般来说,发生错误的原因有两个;ー是所引用的函数、变量不存在、拼写不正确或者使用错误;其次可能使用了不同版本的连接库。编程中经常能遇到LNK2005错误——重复定义错误,其实LNK2005错误并不是ー个很难解决的错误.3.继承和委派有什么分别,在决定使用继承或者委派的时候需要考虑什么。在OOD,OOP中,组合优于继承.

1当然多态的基础是继承,没有继承多态无从谈起。当对象的类型不影响类中函数的行为时,就要使用模板来生成这样ー组类。当对象的类型影响类中函数的行为时,就要使用继承来得到这样ー组类.1.指针和引用有什么分别;如果传引用比传指针安全,为什么?如果我使用常量指针难道不行吗?(1)引用在创建的同时必须初始化,即引用到ー个有效的对象:而指针在定义的时候不必初始化,可以在定义后面的任何地方重新赋值.(2)不存在NULL引用,引用必须与合法的存储单元关联;而指针则可以是NULL.(3)引用一旦被初始化为指向ー个对象,它就不能被改变为另ー个对象的引用;而指针在任何时候都可以改变为指向另ー个对象.给引用赋值并不是改变它和原始对象的绑定关系.(4)引用的创建和销毁并不会调用类的拷贝构造函数(5)语言层面,引用的用法和对象一样:在二进制层面,引用一般都是通过指针来实现的,只不过编译器帮我们完成了转换.不存在空引用,并且引用一旦被初始化为指向ー个对象,它就不能被改变为另ー个对象的引用,显得很安全。const指针仍然存在空指针,并且有可能产生野指针.总的来说:引用既具有指针的效率,又具有变量使用的方便性和直观性.2.参数传递有几种方式:实现多态参数传递采用什么方式,如果没有使用某种方式原因是什么:传值,传指针或者引用

21.结合一个项目说明你怎样应用设计模式的理念。设计模式更多考虑是扩展和重用,而这两方面很多情况下,往往会被忽略。不过,我不建议滥用设计模式,以为它有可能使得简单问题复杂化.2.介绍一下你对设计模式的理解。(这个过程中有很多很细节的问题随机问的)设计模式概念是由建筑设计师ChristopherAlexander提出:"每ー个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心.这样,你就能一次又一次地使用该方案而不必做重复劳动.”上述定义是对设计模式的广义定义.将其应用到面向对象软件的领域内,就形成了对设计模式的狭义定义.可以简单的认为:设计模式就是解决某个特定的面向对象软件问题的特定方法,并且已经上升到理论程度。框架与设计模式的区别:1,设计模式和框架针对的问题域不同.设计模式针对面向对象的问题域;框架针对特定业务的问题域2I设计模式比框架更为抽象.设计模式在碰到具体问题后,才能产生代码;框架已经可以用代码表示3I设计模式是比框架更小的体系结构元素.框架中可以包括多个设计模式设计模式就像武术中基本的招式.将这些招式合理地纵组合起来,就形成套路(框架),框架是一种半成品.3.C++和C定义结构的分别是什么。Clanguage的结构仅仅是数据的结合Cplusplus的struct和class其实具备几乎ー样的功能,只是默认的访问属性不一样而已。

31.构造函数可否是虚汗数,为什么?析构函数呢,可否是纯虚的呢?构造函数不能为虚函数,要构造ー个对象,必须清楚地知道要构造什么,否则无法构造ー个対象。析构函数可以为纯虚函数。2.拷贝构造函数相关问题,深拷贝,浅拷贝,临时对象等。深拷贝意味着拷贝了资源和指针,而浅拷贝只是拷贝了指针,没有拷贝资源这样使得两个指针指向同一份资源,造成对同一份析构两次,程序崩溃。临时对象的开销比局部对象小些。3.结合1个你认为比较能体现OOP思想的项目,用UML来描述。(最好这个项目继承,多态,虚函数都有体现)这个问题大概会占面试时间的一半,并且会问很多问题,ー不小心可能会被问住)4.基类的有1个虚函数,子类还需要申明为virtual吗?为什么。不申明没有关系的。不过,我总是喜炊显式申明,使得代码更加清晰。5.C也可以通过精心封装某些函数功能实现重用,那C++的类有什么优点吗,难道仅仅是为实现重用。并不仅仅是这样的。OOD,OOP从根本上改变了程序设计模式和设计思想,具备亜大和深远的意义。

4类的三大最基本的特征:封装,继承,多态.1.C++特点是什么,如何实现多态?画出基类和子类在内存中的相互关系。多态的基础是继承,需要虚函数的支持,简单的多态是很简单的。子类继承父类大部分的资源,不能继承的有构造函数,析构函数,拷贝构造函数,〇perator=函数,友元函数等等2.为什么要引入抽象基类和纯虚函数?主要目的是为了实现ー种接口的效果。3.介绍一下模板和容器。如何实现?(也许会让你当场举例实现)模板可以说比较古老了,但是当前的泛型编程实质上就是模板编程。它体现了一•种通用和泛化的思想。STL有7种主要容器:vector,list,deque,map,multimap,set,multiset.4.你如何理解MVC。简单举例来说明其应用。MVC模式是observer模式的•个特例,典型的有MFC里面的文档视图架构。5.多重继承如何消除向上继承的二义性。使用虚拟继承即可.

51.以下三条输出语句分别输出什么?[C易]charstrl[]="abc";charstr2[]="abc";constcharstr3[]="abc";constcharstr4[]="abc";constchar*str5=abc;constchar*str6=abc;cout«boolalpha«(strl==str2)«endl;/Z输出什么?cout«boolalpha«(str3==str4)«endl;/Z输出什么?cout«boolalpha«(str5==str6)«endl;/Z输出什么?2.非C++内建型别A和B,在哪几种情况下B能隐式转化为A?[C++中等]答:a.classB:publicA{}//B公有继承自A,可以是间接继承的b.classB{operatorA();}//B实现了隐式转化为A的转化c.classA{A(constB&);}//A实现了non-explicit的参数为B(可以有其他带默认值的参数)构造函数d.A&operator=(constA&);〃赋值操作,虽不是正宗的隐式类型转换,但也可以勉强算ー个3.以下代码中的两个sizeof用法有问题吗?[C易]voidUppercase(charstr[])〃将str中的小写字母转换成大写字母

6Ifor(sizeti=0;i

7returncountx;}假定x=9999〇答案:8思路:将x转化为2进制,看含有的1的个数。2.什么是“引用”?申明和使用“引用”要注意哪些问题?答:引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的ー个别名,它本身不是ー种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。3.将“引用”作为函数参数有哪些特点?(1)传递引用给函数与传递指针的效果是ー样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本:如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用”・指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。4.在什么时候需要使用“常引用”?如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式;const类型标识符&引用名=目标变量名;

8例1inta;constint&ra=a;ra=l;//错误a=l!〃正确例2stringfoo();voidbar(string&s);那么下面的表达式将是非法的:bar(foo());bar(*helloworld*);原因在于foo()和"helloworld”串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。引用型参数应该在能被定义为const的情况下,尽量定义为const。2.将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?格式:类型标识符&函数名(形参列表及类型说明){〃函数体}好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtimeerror!注意事项:(1)不能返回局部变量的引用。这条可以参照EffectiveC++[l]的Item31。主要原因

9是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。(2)不能返回函数内部new分配的内存的引用。这条可以参照EffectiveC++[l]的Item31„虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memoryleak〇(3)可以返回类成员的引用,但最好是const。这条原则可以参照EffectiveC++ロ]的Item30〇主要原因是当对象的属性是与某种业务规则(businessrule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在ー个、ル务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。(4)流操作符重载返冋值申明为“引用”的作用:流操作符〈く和・,这两个操作符常常希望被连续使用,例如:cout«”hello"«endl;因此这两个操作符的返回值应该是ー个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造ー个新的流对象,也就是说,连续的两个〈く操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用〈〈操作符。因此,返回一个流对象引用是惟ー选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。赋值操作符=。这个操作符象流操作符ー样,是可以连续使用的,例如:x=j=10;或者(x=10)=100;赋值操作符的返回值必须是ー个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返冋值选择。例3#includeint&put(intn);intvals[10];interror=-1;

10voidmain()put(0)=10;〃以pul(0)函数值作为左值,等价于vals[0]=10;put(9)=20;〃以put(9)函数值作为左值,等价于vals[9]=20;cout<=0&&nく二9)returnvals[n];else{coutくく“subscripterror";returnerror;}(5)在另外的一些操作符中,却千万不能返回引用:+-*Z四则运算符。它们不能返回引用,EffectiveC++[l]的Item23详细的讨论了这个问题。主要原因是这四个操作符没有sideeffect,因此,它们必须构造ー个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一个静态对象引用。根据前面提到的引用作为返回值的三个规则,第2、3两个方案都被否决了。静态对象的引用又因为((a+b)=(c+d))会永远为true而导致错误。所以可选的只剩下返回一个对象了。6.引用与多态的关系?引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。例4ClassA;ClassB:ClassA{...};Bb:A&ref=b:7.引用与指针的区别是什么?指针通过某个指针变量指向ー个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。此外,就是上面提到的对函数传ref和pointer的区别。

116.什么时候需要“引用”?流操作符くく和〉、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。以」:2-8参考:http://blog.csdn.net/wfwd/archive/2006/05/30/763551.aspx7.结构与联合有和区别?1.结构和联合都是由多个不同的数据类型成员组成,但在任何同一时刻,联合中只存放了一个被选中的成员(所有成员共用ー块地址空间),而结构的所有成员都存在(不同成员的存放地址不同)。2.对于联合的不同成员赋值,将会对其它成员重写,原来成员的值就不存在了,而对于结构的不同成员赋值是互不影响的。10.下面关于“联合”的题目的输出?a)#includeunionIinti;charx[2];}a;

12voidmain()(a.x[0]=10;a)x[l]=1;printf('%d",a.i);)答案:266(低位低地址,高位高地址,内存占用情况是OxOlOA)b)mainOunion(inti;struct{charfirst;charsecond;}half;}number;number,i=0x4241;printf("%c%c

13”,number,half,first,mumber.half,second);number,half,first='a';number,half.second='b';printfC%x

14”,number,i);

15getchO;}答案:AB(0x41对应'A',是低位;0x42对应'B',是高位)6261(number,i和number,half共用ー块地址空间)11.已知strcpy的函数原型:char*strcpy(char*strDest,constchar*strSrc)其中strDest是目的字符串,strSrc是源字符串。不调用C++/C的字符串库函数,请编写函数strcpyo

16答案:char*strcpy(char*strDest,constchar*strSrc)if(strDest==NULL|IstrSrc==NULL)returnNULL;if(strDest=strSrc)returnstrDest;char*tempptr=strDest;while((*strDest++=*strSrc++)!=‘、〇')returntempptr;)11.已知String类定义如下:classString(public:String(constchar*str=NULL);//通用构造函数StringO;/Z析构函数String&operator=(constString&rhs);/Z赋值函数private:

17char*m_data;/Z用于保存字符串};尝试写出类的成员函数实现。答案:String::String(constchar*str)(if(str=NULL)〃strlen在参数为NULL时会抛异常オ会有这步判断(m_data=newchar[1];m_data[0]=‘、〇';}elsem_data=newchar[strlen(str)+1];

18strcpy(m_data,str);String::String(constString&another)Im_data=newchar[strlen(another.m_data)+1];strcpy(m_data,other.m_data);}StringfeString::operator=(constString&rhs)(if(this==&rhs)return*this;delete[]m_data;〃删除原来的数据,新开一块内存m_data=newchar[strlen(rhs.m_data)+1];strcpy(m_data,rhs.m_data);return*this;String::"String()delete[]mdata;

1913..h头文件中的ifndef/define/endif的作用?答:防止该头文件被重复引用。14.#include与#include"file,h”的区别?答:前者是从StandardLibrary的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file,ho15.在C++程序中调用被C编译器编译后的函数,为什么要加extern"C”?首先,作为extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数extern"C"是连接申明(linkagedeclaration),被extern"C”修饰的变量和函数是按照C语言方式编译和连接的,来看看C++中对类似C的函数是怎样编译的:作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:voidfoo(intx,inty);该函数被C编译器编译后在符号库中的名字为ーfoo,而C++编译器则会产生像—foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为umangledname")。

20_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数voidfoo(intx,inty)与voidfoo(intx,floaty)编译生成的符号是不相同的,后者为_foo_int_float。同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以〃.”来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独ー无二的名字,这个名字与用户程序中同名的全局变量名字不同。未加extem"C〃声明时的连接方式假设在C++中,模块A的头文件如下:/Z模块A头文件moduleA.h#ifndefMODULE_A_H#defineM0DULE_A_Hintfoo(intx,inty);#endif在模块B中引用该函数:/Z模块B实现文件moduleB.cppttinclude"moduleA.h"foo(2,3);实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号!加extern"C”声明后的编译和连接方式加exte门!”C〃声明后,模块A的头文件变为:

21/Z模块A头文件moduleA.h#ifndefMODULE_A_H#defineMODULE_A_HexternACintfoo(intx,inty);#endif在模块B的实现文件中仍然调用foo(2,3),其结果是:(1)模块A编译生成fo。的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式:(2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_f000如果在模块A中函数声明了foo为extern"C,类型,而模块B中包含的是externintf〇〇(intx,inty),则模块B找不到模块A中的函数;反之亦然。所以,可以用一句话概括extern"C”这个声明的真实目的(任何语言中的任何语法特性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么做的,还要问ー问它为什么要这么做,动机是什么,这样我们可以更深入地理解许多问题):实现C++与C及其它语言的混合编程。明白了C++中extern的设立动机,我们下面来具体分析extern"C”通常的使用技巧:extern的惯用法(1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:extern"C"[#include“cExample.h"

22)而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern"C”声明,在.c文件中包含了extern"C"时会出现编译语法错误。C++引用C函数例子工程中包含的三个文件的源代码如下:#ifndefC_EXAMPLE_HttdefineC_EXAMPLE_Hexternintadd(intx,inty);#endif#include“cExample.h"intadd(intx,inty)returnx+y;}//c++实现文件,调用add:cppFile.cppextern"C"(#include“cExample.h")intmain(intargc,char*argvロ)add(2,3);

23return0;)如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern"C”{},(2)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern"C",但是在C语言中不能直接引用声明了extern"C”的该头文件,应该仅将C文件中将C++中定义的extern"C"函数声明为extern类型。C引用C++函数例子工程中包含的三个文件的源代码如下:〃C++头文件cppExample.httifndefCPP_EXAMPLEJISdefineCPP_EXAMPLE_HexternA(intadd(intx,inty);ttendif〃C++实现文件cppExample.cpp#includecppExample.hintadd(intx,inty)(returnx+y;}externintadd(intx,inty);intmain(intargc,char*argvL])add(2,3);return0;

2415题目的解答请参考《C++中extern“C”含义深层探索》注解:13.关联、聚合(Aggregation)以及组合(Composition)的区别?涉及到UML中的ー些概念:关联是表示两个类的一般性联系,比如“学生”和“老师”就是ー种关联关系:聚合表示has-a的关系,是ー种相对松散的关系,聚合类不需要对被聚合类负责,如下图所示,用空的菱形表示聚合关系:从实现的角度讲,聚合可以表示为:classA{...}classB{A*a;}而组合表示contains-a的关系,关联性强于聚合:组合类与被组合类有相同的生命周期,组合类要对被组合类负责,采用实心的菱形表示组合关系:实现的形式是:classA{...}classB{Aa;...)参考文章:httpノ/blog,csdn.net/wfwd/archive/2006/05/30/763753.aspxhttp:〃blog,csdn.net/wfwd/archive/2006/05/30/763760.aspx14.面向对象的三个基本特征,并简单叙述之?1.封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private,protected,public)2.继承:广义的继承有三种实现形式:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。前两种(类继承)和后一种(对象组合=>接口继承以及纯虚函数)构成了功能复用的两种方式。3.多态:是将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:

25允许将子类类型的指针赋值给父类类型的指针。18.重载(overload)和重写(overried,有的书也叫做'’覆盖'')的区别?常考的题目。从定义上来说:重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。重写:是指子类重新定义复类虚函数的方法。从实现原理上来说:重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:functionfunc(p:integer):integer;和functionfunc(p:string):integer;〇那么编译器做过修饰后的函数名称可能是这样的:int.func、stjfunc。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。(六)1)什么是预编译,何时需要预编译:总是使用不经常改动的大型代码体。程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为ー个预编译头。2)char*constp;charconst*pconstchar*p

26上述三个有什么区别?char*constp;〃常量指针,p的值不可以修改charconst*p;〃指向常量的指针,指向的常量值不可以改constchar*p:〃和charconst*p2)charstrl[]="abc”;charstr2[]="abc";constcharstr3ロ=abc”;constcharstr4ロ=abc”;constchar*str5=abc;constchar*str6=abc;char*str7=abc;char*str8="abc";cout«(strl==str2)«endl;cout«(str3==str4)«endl;cout«(str5==str6)<

27结果是:0011解答:strl,str2,str3,str4是数组变量,它们有各自的内存空间;而str5,str6,str7,str8是指针,它们指向相同的常量区域。4)以下代码中的两个sizeof用法有问题吗?voidUppercase(charstr[])〃将str中的小写字母转换成大写字母(for(size_ti=0;iくsizeof(str)/sizeof(str[0]);++i)if('a'く:str[i]&&str[i]<=*z*)str[i]-=('a'-'A');}charstr[]二aBcDe”;cout<<"str字符长度为:"«sizeof(str)/sizeof(str[0])<

285)ー个32位的机器,该机器的指针是多少位?指针是多少位只耍看地址总线的位数就行了。80386以后的机子都是32的数据总线。所以指针的位数就是4个字节了。6)main()inta[5]={l,2,3,4,5};int*ptr=(int*)(&a+l);printf(*%d,%d”,*(a+l),*(ptr-l));输出:2,5*(a+l)就是a[l],*(ptrT)就是a[4],执行结果是2,5&a+l不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)int*ptr=(int*)(&a+l);则ptr实际是&(a[5]),也就是a+5原因如下:&a是数组指针,其类型为int(*)[5]:

29而指针加1要根据指针类型加上一定的值,不同类型的指针+1之后增加的大小不同。a是长度为5的int数组指针,所以要加5*sizeof(int)所以ptr实际是a[5]但是prt与(&a+l)类型是不ー样的(这点很重要)所以prtT只会减去sizeof(int*)a,&a的地址是ー样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[l],&a+l是下ー个对象的地址,即a[5].7)请问以下代码有什么问题:intmain()chara;char*str=&a;strcpy(str,"hello");printf(str);return0;}没有为str分配内存空间,将会发生异常。问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。8)char*s="AAA";

30printf("%s",s);s[〇]='B';printf('%s",s);有什么错?"AAA"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。cosntchar*s='AAA";然后又因为是常量,所以対是s[0]的赋值操作是不合法的。9)写ー个“标准”宏,这个宏输入两个参数并返回较小的一个。7defineMin(X,Y)((X)>(Y)?(Y):(X))〃结尾没有;10)嵌入式系统中经常要用到无限循环,你怎么用C编写死循环。while(l){}或者for(;;)软件开发网www.mscto.cn11)关键字static的作用是什么?定义静态变量12)关键字const有什么含意?

31表示常量不可以修改的变量。13)关键字volatile有什么含意?并举出三个不同的例子?提示编译器对象的值可能在编译器未监测到的情况下改变。14)int(*s[10])(int)表示的是什么?int(*s[10])(int)函数指针数组,每个指针指向ー个intfunc(intparam)的函数。15)有以下表达式:inta=248;b=4;intconstc=21;constint*d=&a;int*conste=&b;intconst*fconst=&a;请问下列表达式哪些会被编译器禁止?为什么?*c=32;d=&b;*d=43;e=34;e=&a;f=0x321f;*c这是个什么东东,禁止

32*d说了是const,禁止e=&a说了是const禁止const*fconst=&a;禁止16)交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3;有两种解法,一种用算术算法,ー种用ス异或)a=a+b;b=a-b;a=a-b;ora=ab;/Z只能对!nt,char..b=ab;a=ab;ora*=b*=a;17)c和c++中的struct有什么不同?c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。C++中struct和class的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private。18)^include

33ttincludevoidgetmemory(char*p)p=(char*)malloc(lOO);strcpy(p,""helloworld");}intmain()(char*str=NULL;getmemory(str);printf("%s/n",str);free(str);return0;)程序崩溃,getmemory中的malloc不能返回动态内存,free()对str操作很危险17)charszstr[10];strcpy(szstr,"0123456789");产生什么结果?为什么?长度不一样,会造成非法的OS

3420)列举几种进程的同步机制,并比较其优缺点。原子操作信号量机制自旋锁管程,会合,分布式系统21)进程之间通信的途径共享存储系统消息传递系统管道:以文件系统为基础22)进程死锁的原因资源竞争及进程推进顺序非法23)死锁的4个必要条件互斥、请求保持、不可剥夺、环路24)死锁的处理鸵鸟策略、预防策略、避免策略、检测与解除死锁

3525)操作系统中进程调度策略有哪几种?FCFS(先来先服务),优先级,时间片轮转,多级反馈26)类的静态成员和非静态成员有何区别?类的静态成员每个类只有一个,非静态成员每个对象一个27)纯虚函数如何定义?使用时应注意什么?virtualvoidf()=0;是接口,子类必须要实现28)数组和链表的区别数组:数据顺序存储,固定大小连表:数据可以随机存储,大小可动态改变29)ISO的七层模型是什么?tcp/udp是属于哪ー层?tcp/udp有何优缺点?应用层表示层会话层运输层

36网络层物理链路层物理层tcp/udp属于运输层TCP服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。与TCP不同,UDP并不提供对IP协议的可靠机制、流控制以及错误恢复功能等。由于UDP比较简单,UDP头包含很少的字节,比TCP负载消耗少。tcp:提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好udp:不提供稳定的服务,包头小,开销小29)(void*)ptr和(*(void**))ptr的结果是否相同?其中ptr为同一个指针(void*)ptr和(*(void**))ptr值是相同的32)intmain()intx=3;printf(线d",x);return1;}

37问函数既然不会被其它函数调用,为什么耍返回1?mian中,c标准认为〇表示成功,非0表示错误。具体的值是某中具体出错信息33)要对绝对地址Ox100000赋值,我们可以用(unsignedint*)0x100000=1234;那么要是想让程序跳转到绝対地址是0x100000去执行,应该怎么做?*((void(*)())0x100000)();首先要将0x100000强制转换成函数指针,即:(void(*)())0x100000然后再调用它:*((void(*)())0x100000)();用typedef可以看得更直观些:typedefvoid(*)()voidFuncPtr;*((voidFuncPtr)0x100000)();34)已知一个数组table,用ー个宏定义,求出数据的元素个数#defineNTBLttdefineNTBL(sizeof(table)/sizeof(table[0]))35)线程与进程的区别和联系?线程是否具有相同的堆栈?dll是否有独立的堆栈?进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的

38时候操作系统就帮你创建了一个主线程。每个线程有自己的堆栈。DLL中有没有独立的堆栈?这个问题不好回答,或者说这个问题本身是否有问题。因为DLL中的代码是被某些线程所执行,只有线程拥有堆栈,如果DLL中的代码是EXE中的线程所调用,那么这个时候是不是说这个DLL没有自己独立的堆栈?如果DLL中的代码是由DLL自己创建的线程所执行,那么是不是说DLL有独立的堆栈?以上讲的是堆栈,如果对于堆来说,每个DLL有自己的堆,所以如果是从DLL中动态分配的内存,最好是从DLL中删除,如果你从DLL中分配内存,然后在EXE中,或者另外ー个DLL中删除,很有可能导致程序崩溃。36)unsignedshortA=10;printf("〜A=%u

39",〜A);charc=128;printf("c=%d

40,c);输出多少?并分析过程第一题,〜A=0xfffffff5,int值为ー11,但输出的是uint。所以输出4294967285第二题,c=OxlO,输出的是int,最高位为1,是负数,所以它的值就是0x00的补码就是128,所以输出一128。这两道题都是在考察二进制向int或uint转换时的最高位处理。37)分析下面的程序:

41voidGetMemory(char**p,intnum){*p=(char*)malloc(num);)intmain()Ichar*str=NULL;GetMemory(&str,100);strcpy(str,"hello");free(str);if(str!=NULL)strcpy(str,"world");printf("

42stris%s",str);软件开发网www.mscto.comgetchar();}

43问输出结果是什么?输出strisworld.,free只是释放的str指向的内存空间,它本身的值还是存在的.所以free之后,有ー个好的习惯就是将str=NULL.此时str指向空间的内存已被回收,如果输出语句之前还存在分配空间的操作的话,这段存储空间是可能被重新分配给其他变量的,尽管这段程序确实是存在大大的问题(上面各位已经说得很清楚了),但是通常会打印出world来。这是因为,进程中的内存管理一般不是山操作系统完成的,而是由库函数自己完成的。当你mallocー块内存的时候,管理库向操作系统申请一块空间(可能会比你申请的大一些),然后在这块空间中记录ー些管理信息(一般是在你申请的内存前面一点),并将可用内存的地址返回。但是释放内存的时候,管理库通常都不会将内存还给操作系统,因此你是可以继续访问这块地址的〇chara[10],strlen(a)为什么等于15?运行的结果38)ttinclude"stdio.h"#include“string,h"voidmain()(charaa[10];

44printfstrlen(aa));}sizeofO和初不初始化,没有关系;strlen()和初始化有关。38)char(*str)[20];char*str[20];39)long"0x801010;a+5二?0x801010用二进制表示为:“100000000001000000010000”,十进制的值为8392720.再加上5就是8392725罗41)给定结构structAchart:4;chark:4;unsignedshorti:8;unsignedlongm;

45};问sizeof(A)=?给定结构structAchart:4;4位chark:4;4位unsignedshorti:8;8位unsignedlongm;//偏移2字节保证4字节对齐);/Z共8字节42)下面的函数实现在ー个数上加一个数,有什么错误?请改正。intadd_n(intn)staticinti=100;i+=n;returni;

46当你第二次调用时得不到正确的结果,难道你写个函数就是为了调用一次?问题就出在static上?43)分析一下#include#include#include#include#includeftincludetypedefstructAAintbl:5;intb2:2;}AA;voidmain()(AAaa;charcc[100];strcpy(cc,*0123456789abcdefghijklmnopqrstuvwxyz^);

47memcpy(&aa,cc,sizeof(AA));cout«aa.bl«endl;cout«aa.b2«endl;)答案是-16和1首先sizeof(AA)的大小为4,bl和b2分别占5bit和2bit.经过strcpy和memcpy后,aa的4个字节所存放的值是:0,1,2,3的ASC码,BP00110000,00110001,00110010,00110011所以,最后ー步:显示的是这4个字节的前5位,和之后的2位分别为:10000,和。],因为int是有正负之分所以:答案是T6和144)求函数返回值,输入x=9999;intfunc(x)(int.countx=0;while(x)(countx++;x-x&(x-1);)returncountx;)

48结果呢?知道了这是统计9999的二进制数值中有多少个1的函数,且有9999=9X1024+512+256+159X1024中含有I的个数为2;512中含有1的个数为1;256中含有1的个数为1;15中含有1的个数为4:软件开发网www.mscto.com故共有1的个数为8,结果为8。1000-1=0111«正好是原数取反。这就是原理。用这种方法来求1的个数是很效率很高的。不必去ー个ー个地移位。循环次数最少。inta,b,c请写函数实现C=a+b,不可以改变数据类型,如将c改为longint,关键是如何处理溢出问题booladd(inta,intb,int*c)i*c=a+b;return(a>0&&b>0&&(*ca*c>b)));)

4945)分析:structbit

50intb:2;intc:3;);intmainO(bits;char*c=(char*)&s;cout<

51-4

52ffffffff因为0x99在内存中表示为10011001,a=001,b=11,c=100。当c为有符合数时,c=100,最高1为表示c为负数,负数在计算机用补码表示,所以c=-4;同理b=T;当c为有符合数时,c=100,即c=4,同理b=3。有些信息在存储时,并不需要占用ー个完整的字节,而只需占几个或一个二进制位。例如在存放ー个开关量时,只有〇和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把ー个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:struct位域结构名{位域列表):其中位域列表的形式为:类型说明符位域名:位域长度例如:structbsintb:2;intc:6;

53);位域变量的说明与结构变量说明的方式相同。可采用先定义后说明,同时定义说明或者宜接说明这三种方式。例如:structbs(inta:8;intb:2;intc:6;}data;说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:ー个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下ー单元起存放该位域。也可以有意使某位域从下ー单元开始。例如:structbs

54unsigned:〇unsignedb:4unsignedc:4在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:structk(inta:1int:2intb:3intc:2};从以上分析可以看出,位域在本质上就是一・种结构类型,不过其成员是按二进位分配

55的。位域的使用位域的使用和结构成员的使用相同,其一般形式为:位域变量名?位域名位域允许用各种格式输出。main()(structbs{unsigneda:1;unsignedb:3;unsignedc:4;)bit,*pbit;bit.a=l;bit.b=7;bit.c=15;pri47)改错:

56#includeintmain(void)int**p;intarr[100];p=&arr;return0;}解答:搞错了,是指针类型不同,int**p;〃ニ级指针&arr;〃得到的是指向第一维为100的数组的指针#includeintmain(void)(int**p,*q;intarr[100];q=arr;p=&q;return0;

5748)下面这个程序执行后会有什么错误或者效果:tfdefineMAX255intmainO(unsignedcharA[MAX],i;//i被定义为unsignedcharfor(i=0;i<=MAX;i++)A[i]=i;return0;)解答:死循环加数组越界访问(C/C++不进行数组越界检查)MAX=255数组A的下标范围为:0..MAXT,这是其ー..其二.当i循环到255时,循环内执行:A[255]=255;这句本身没有问题..但是返回for(i=〇;i〈=MAX;i++)语句时,由于unsignedchar的取值范围在(〇..255),i++以后i又为〇了..

58无限循环下去。

59charstr;shortx;intnum;structname2charstr;intnum;shortx;sizeof(structnamel)=8,sizeof(structname2)=12在第二个结构中,为保证num按四个字节对齐,char后必须留出3字节的空间;同时为保证整个结构的自然对齐(这里是4字节对齐),在x后还要补齐2个字节,这样就是12字节。50)intel:A.c和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。他们都放在数据区,但是编译器对他们的命名是不同的。如果要使变量在其他模块也有意义的话,需要使用extern关键字。

6051)structsi(inti:8;intj:4;inta:3;doubleb;);structs2{inti:8;intj:4;doubleb;inta:3;};printf("sizeof(sl)=%d

61”,sizeof(si));printf("sizeof(s2)=%d

62”,sizeof(s2));

63result:16,24第一个structsiinti:8;intj:4;inta:3;doubleb;);理论上是这样的,首先是i在相对〇的位置,占8位ー个字节,然后,j就在相对ー个字节的位置,由于ー个位置的字节数是4位的倍数,因此不用对齐,就放在那里了,然后是a,要在3位的倍数关系的位置上,因此要移一位,在15位的位置上放下,目前总共是18位,折算过来是2字节2位的样子,由于double是8字节的,因此要在相对。要是8个字节的位置上放下,因此从18位开始到8个字节之间的位置被忽略,直接放在8字节的位置了,因此,总共是16字节。第二个最后会对照是不是结构体内最大数据的倍数,不是的话,会补成是最大数据的倍数。(五)40.链表题:ー个链表的结点结构

64intdataNode*next;);typedefstructNodeNode;(1)已知链表的头结点head,写ー个函数把这个链表逆序(Intel)Node♦ReverseList(Node*head)//链表逆序(if(head==NULL||head->next=NULL)returnhead;Node*pl=head;Node*p2=pl->next;Node*p3=p2->next;pl->next=NULL;while(p3!=NULL)(p2->next=pl;pl=p2;p2=p3p3=p3ー〉next;

65p2ー〉next=pl;head=p2;returnhead;}(2)已知两个链表headl和head2各自有序,请把它们合并成一个链表依然有序。(保留所有结点,即便大小相同)Node*Merge(Node*headl,Node*head2)Iif(headl==NULL)returnhead2;if(head2==NULL)returnheadl;Node*head=NULL;Node*pl=NULL;Node*p2=NULL;if(headl->datanext;p2=head2;

66)else(head=head2;p2=head2ー〉next;pl=headl;)Node*pcurrent=head;while(pl!=NULL&&p2!=NULL)(if(pl->data<=p2->data)(pcurrent->next=pl;pcurrent=pl;pl=pl->next;elsepcurrent->next=p2;pcurrent=p2;p2=p2->next;)

67)if(pl!=NULL)pcurrent->next=pl;if(p2!=NULL)pcurrent->next=p2;returnhead;}(3)已知两个链表headl和head2各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。(Autodesk)答案:Node*MergeRecursive(Node*headl,Node*head2)if(headl==NULL)returnhead2;if(head2==NULL)returnheadl;Node*head=NULLif(headl->datanext=MergeRecursive(headl->next,head2);elsehead=head2;headー〉next=MergeRecursive(headl,head2->next);returnhead;

6841,分析一下这段程序的输出(Autodesk)classBIpublic:B()(coutくくdefaultconstructor〃くくendl;}、B()(coutくく“destructed”くくendl;}B(inti):data(i)//B(int)worksasaconverter(int->instanceofB)(cout«"constructedbyparameter"<

69intmain(intargc,char*argv[])constructedbyparameter5{destructedB(5)形参析构Btl=Play(5);Bt2=Play(tl);destructedtl形参析构return0;destructedt2注意顺序!}destructedtl(1)results:intmain(intargc,char*argvロ)constructedbyparameter5{destructedB(5)形参析构Btl=Play(5);Bt2=Play(10);constructedbyparameter10return0;destructedB(10)形参析构}destructedt2注意顺序!destructedt142.写ー个函数找出ー个整数数组中,第二大的数(Microsoft)答案:constintMINNUMBER=-32767;intfind_sec_max(intdataロ,intcount){intmaxnumber=data[0];intsecmax=MINNUMBER;

70for(inti=1;imaxnumber)(secmax=maxnumber;maxnumber=data;}else(if(data>secjnax)secmax=data;returnsec_max;)42.写ー个在ー个字符串(n)中寻找ー个子串(m)第一个位置的函数。KMP算法效率最好,时间复杂度是。(n+m).43.多帀继承的内存分配问题:比如有classA:publicclassB,publicclassC{}那么A的内存结构大致是怎么样的?这个是compiler-dependent的,不同的实现其细节可能不同。如果不考虑有虚函数、虚继承的话就相当简单;否则的话,相当复杂。

71可以参考《深入探索C++对象模型》,或者:http:〃blog.csdn.net/wfwd/archive/2006/05/30/763797.aspx42.如何判断ー个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针)structnode{charval;node*next;}boolcheck(constnode*head){}//returnfalse:无环;true:有环ー种0(n)的办法就是(搞两个指针,ー个每次递增ー步,ー个每次递增两步,如果有环的话两者必然重合,反之亦然):boolcheck(constnode*head)if(head==NULL)returnfalse;node*low=head,*fast=head->next;while(fast!=NULL&&fast->next!=NULL)(low=low->next;fast=fast->next->next;if(low==fast)returntrue;)returnfalse;}

721.C++的类和C里面的struct有什么区别?struct成员默认访问权限为public,而class成员默认访问权限为private2.析构函数和虚函数的用法和作用析构函数是在对象生存期结束时自动调用的函数,用来释放在构造函数分配的内存。虚函数是指被关键字virtual说明的函数,作用是使用C++语言的多态特性3.全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的?1)全局变量的作用用这个程序块,而局部变量作用于当前函数2)前者在内存中分配在全局数据区,后者分配在栈区3)生命周期不同:全局变量随主程序创建和创建,随主程序销毁而销毁,局部变量在局部函数内部,甚至局部循环体等内部存在,退出就不存在4)使用方式不同:通过声明后全局变量程序的各个部分都可以用到,局部变量只能在局部使用4.有N个大小不等的自然数(1一N),请将它们由小到大排序.要求程序算法:时间复杂度为0(n),空间复杂度为0(1)。voidsort(inteロ,intn)(inti;intt;for(i=l;iくn+1;i++)(

73t=e[e[i]];e[e[i]]=e[i];e[i]=t;1.堆与栈的去区别A.申请方式不同Stack由系统自动分配,而heap需要程序员自己申请,并指明大小。8.申请后系统的响应不同Stack:只要栈的剩余空间大于申请空间,系统就为程序提供内存,否则将抛出栈溢出异常Heap:当系统收到程序申请时,先遍历操作系统中记录空闲内存地址的链表,寻找第一个大于所申请空间的堆结点,然后将该结点从空间结点链表中删除,并将该结点的空间分配给程序。另外,大多数系统还会在这块内存空间中的首地址处记录本次分配的大小,以便于delete语句正确释放空间。而且,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动将多余的那部分重新放入空闲链表。C.申请大小限制的不同Stack:在windows下,栈的大小是2M(也可能是1M它是ー个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示。verflow。因此,能从栈获得的空间较小。Heap:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

74D.申请效率的比较:栈山系统自动分配,速度较快。但程序员是无法控制的。堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片ー,不过用起来最方便。另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。E.堆和栈中的存储内容栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的ドー条指令,程序由该点继续运行。堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。6.含参数的宏与函数的优缺点宏:优点:在预处理阶段完成,不占用编译时间,同时,省去了函数调用的开销,运行效率高缺点:不进行类型检查,多次宏替换会导致代码体积变大,而且由于宏本质上是字符串替换,故可能会由于ー些参数的副作用导致得出错误的结果。函数:优点:没有带参数宏可能导致的副作用,进行类型检查,计算的正确性更有保证。缺点:函数调用需要参数、返回地址等的入栈、出栈开销,效率没有带参数宏高PS:宏与内联函数的区别内联函数和宏都是在程序岀现的地方展开,内联函数不是通过函数调用实现的,是在调用该函数的程序处将它展开(在编译期间完成的);宏同样是;不同的是:内联函数可以在编译期间完成诸如类型检测,语句是否正确等编译功能:宏就

75不具有这样的功能,而且宏展开的时间和内联函数也是不同的(在运行期间展开)6.Windows程序的入口是哪里?写出Windows消息机制的流程Windows程序的入口是WinMainO函数。Windows应用程序消息处理机制;A.操作系统接收应用程序的窗口消息,将消息投递到该应用程序的消息队列中B.应用程序在消息循环中调用GetMessage函数从消息队列中取出一条一条的消息,取出消息后,应用程序可以对消息进行ー些预处理。C.应用程序调用DispatchMessage,将消息回传给操作系统。D.系统利用WNDCLASS结构体的IpfnWndProc成员保存的窗口过程函数的指针调用窗口过程,对消息进行处理。7.如何定义和实现ー个类的成员函数为回调函数A.什么是回调函数?简而言之,回调函数就是被调用者回头调用调用者的函数。使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的ー个函数(这个函数为回调函数)的地址作为参数传递给那个被调用函数。而该被调用函数在需要的时候,利用传递的地址调用回调函数。回调函数,就是由你自己写的,你需要调用另外一个函数,而这个函数的其中一个参数,就是你的这个回调函数名。这样,系统在必要的时候,就会调用你写的回调函数,这样你就可以在冋调函数里完成你要做的事。B.如何定义和实现ー个类的成员函数为回调函数要定义和实现ー个类的成员函数为回调函数需要做三件事:

76a.声明;b.定义;c.设置触发条件,就是在你的函数中把你的回调函数名作为一个参数,以便系统调用如:ー、声明回调函数类型typedefvoid(*FunPtr)(void);二、定义回调函数classA(public:AO;staticvoidcalIBackFun(void)〃回调函数,必须声明为staticcout«wcallBackFun,z«endl;virtualA(););三、设置触发条件voidFuntype(FunPtrp)(p();

77)voidmain(void)(Funtype(A::callBackFun);)C.回调函数与API函数回调和API非常接近,他们的共性都是跨层调用的函数。但区别是API是低层提供给高层的调用,一般这个函数对高层都是已知的;而回调正好相反,他是高层提供给底层的调用,对于低层他是未知的,必须由高层进行安装,这个安装函数其实就是ー个低层提供的API,安装后低层不知道这个回调的名字,但它通过ー个函数指针来保存这个回调函数,在需要调用时,只需引用这个函数指针和相关的参数指针。其实:回调就是该函数写在高层,低层通过ー个函数指针保存这个函数,在某个事件的触发下,低层通过该函数指针调用高层那个函数。1、局部变量能否和全局变量重名?能,局部会屏蔽全局。要用全局变量,需要使用"::"局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义•个同名的局部变量,而那个局部变量的作用域就在那个循环体内。2、如何引用ー个已经定义过的全局变量?extern可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头

78文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。3、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?可以,在不同的C文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会岀错。4、语句for(;1;)有什么问题?它是什么意思?无限循环,和while(l)相同。5、dowhile和whiledo有什么区别?前一个循环一遍再判断,后ー个判断以后再循环。6、请写出下列代码的输出内容#includemain()iinta,b,c,d;a=10;b=a++;c=++a;

79d=10*a++;printfC'b,c,d:%d,%d,%d”,b,c,d);return0;}答:10,12,1207、请找出下面代码中的所以错误说明:以下代码是把ー个字符串倒序,如“abed”倒序后变为“deba”ttincludestring,hmain()char*src=/zhello,world”;char*dest=NULL;intlen=strlen(src);dest=(char*)malloc(len);char*d=dest;char*s=src[len];while(len-!=0)d++=s-;printf("%s",dest);return0;}

80答:方法1:intmainO(char*src=hello,world";intlen=strlen(src);char*dest=(char*)malloc(len+l);〃要为、〇分配ー个空间char*d=dest;char*s=&src[lenT];〃指向最后一个字符while(len一!=0)*d++=*s-;*d=0;//尾部要加、〇printf("版、n〃,dest);free(dest);〃使用完,应当释放空间,以免造成内存汇泄露return0;}方法2:#includeftincludemain()

81{charstr口=“hello,world”;intlen:strlen(str);chart;for(inti二〇;i

829、用两个栈实现ー个队列的功能?要求给出算法和思路!设2个栈为A,B,一开始均为空.入队:将新元素push入栈A;出队:(1)判断栈B是否为空;(2)如果不为空,则将栈A中所有元素依次pop出并push到栈B;(3)将栈B的栈顶元素pop出;这样实现的队列入队和出队的平摊复杂度都还是0(1),比上面的几种方法要好。10、在c语言库函数中将一个字符转换成整型的函数是atool()吗,这个函数的原型是什么?函数名:atol功能:把字符串转换成长整型数用法:longatol(constchar*nptr);程序例:#include#includeintmain(void)!long1;

83char*str="98765432”;1=atol(Istr);printf("string=%sinteger=%ld

84",str,1);return(0);)Ik对于ー个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?c用宏定义,c++用inline12、直接链接两个信令点的ー组链路称作什么?PPP点到点连接13、接入网用的是什么接口?14、voip都用了那些协议?15、软件测试都有那些种类?黑盒:针对系统功能的测试白合:测试函数功能,各函数接口16、确定模块的功能和模块的接口是在软件设计的那个队段完成的?概要设计阶段17、enumstring(

85xl,x2,x3=10,x4,x5,}x;问x=0x801005,0x801Of4;17、unsignedchar*pl;unsignedlong*p2;pl=(unsignedchar*)0x801000;p2=(unsignedlong*)0x810000;请问pl+5=0x801005;p2+5=0x801014;18.多态的作用?主要是两个:1.隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用;2.接口重用;为了类在继承和派生的时候,保证使用家族中任一类的实例的某ー属性时的正确调用。19.Ado与Ado.net的相同与不同?除了“能够让应用程序处理存储于DBMS中的数据’‘这一基本相似点外,两者没有太多共同之处。但是Ado使用OLEDB接口并基于微软的COM技术,而ADO.NET拥有自己的AD0.NET接口并且基于微软的.NET体系架构。众所周知.NET体系不同于COM体系,ADO.NET接口也就完全不同于ADO和OLEDB接口,这也就是说ADO.NET和ADO是两种数据访问方式。ADO.net提供对XML的支持。20.Newdelete与mallocfree的联系与区别?都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new会自动调用对象的构造函数。delete会调用对象的destructor,而free不会调用对象的destructor.21.^defineDOUBLE(x)x+x,i=5*DOUBLE(5);i是多少?

86答案:i为30。17.有哪几种情况只能用intializationlist而不能用assignment?答案:当类中含有const,reference成员变量;基类的构造函数都需要初始化表。18.C++是不是类型安全的?答案:不是。两个不同类型的指针之间可以强制转换(用reinterpretcast)«C#是类型安全的。19.main函数执行以前,还会执行什么代码?答案:全局对象的构造函数会在main函数之前执行。20.描述内存分配方式以及它们的区别?1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期山程序员决定,使用非常灵活,但问题也最多。21.struct和class的区别struct的成员默认是公有的,而类的成员默认是私有的。struct和class在其他方面是功能相当的。从感情上讲,大多数的开发者感到类和结构有很大的差别。感觉上结构仅仅象一堆缺乏封装和功能的开放的内存位,而类就象活的并且可靠的社会成员,它有智能服务,有牢固的

87封装屏障和一个良好定义的接口。既然大多数人都这么认为,那么只有在你的类有很少的方法并且有公有数据(这种事情在良好设计的系统中是存在的!)时,你也许应该使用struct关键字,否则,你应该使用class关键字。17.当ー个类A中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少,如果不是零,请解释ー下编译器为什么没有让它为零。(Autodesk)肯定不是零。举个反例,如果是零的话,声明ー个classA[10]对象数组,而每一个对象占用的空间是零,这时就没办法区分A[O],A[1]…了。18.在8086汇编ド,逻辑地址和物理地址是怎样转换的?(Intel)通用寄存器给出的地址,是段内偏移地址,相应段寄存器地址・10H+通用寄存器内地址,就得到了真正要访问的地址。19.比较C++中的4种类型转换方式?请参考:hltp:/ハ)leg.esdn.netハvl'nd/archive/2()()6/()5ハ")(763785.aspx,重点是staticcast,dynamic_cast和reinterpretcast的区别和应用。20.分别写出BOOL,int,float,指针类型的变量a与“零”的比较语句。答案:BOOL:if(!a)orif(a)int:if(a=0)float:constEXPRESSIONEXP=0.000001if(a"EXP)pointer:if(a!=NULL)orif(a==NULL)21.请说出const与#define相比,有何优点?答案:1)const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检査,并且在字符替换可能会产生意料不到的错误。2)有些集成化的调试工具可以对const常量进行调试,但是不能対宏常量进行调试。

8833.简述数组与指针的区别?数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。(1)修改内容上的差别chara[]="hello";a[0]='X';char*p="world"://注意p指向常量字符串p[0]='X';//编译器不能发现该错误,运行时错误(2)用运算符sizeof可以计算出数组的容量(字节数)。sizeof(p),p为指针得到的是ー个指针变量的字节数,而不是p所指的内存容量。C++/C语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。charaロ="helloworld";char*p=a;cout«sizeof(a)«endl;//12字节cout«sizeof(p)«endl;//4字节计算数组和指针的内存容量voidFunc(chara[100])[cout«sizeof(a)«endl;//4字节而不是100字节)

8933.类成员函数的重载、覆盖和隐藏区别?答案:a.成员函数被重载的特征:(1)相同的范围(在同一个类中);(2)函数名字相同;(3)参数不同;(4)virtua!关键字可有可无。b.覆盖是指派生类函数覆盖基类函数,特征是:(1)不同的范围(分别位于派生类与基类);(2)函数名字相同;(3)参数相同;(4)基类函数必须有virtual关键字。c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关健字,基类的函数将被隐藏(注意别与重载混淆)。(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtua1关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)35.Therearetwointvariables:aandb,don'tuse"if","?:","switch"orotherjudgementstatements,findoutthebiggestoneofthetwonumbers.答案:

90((a+b)+abs(a-b))/235.如何打印出当前源文件的文件名以及源文件的当前行号?答案:cout«_FILE_;cout«_LINE_;_FILE_和_LINE_是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。36.main主函数执行完毕后,是否可能会再执行一段代码,给出说明?答案:可以,可以用—onexit注册ー个函数,它会在main之后执行intfnl(void),fn2(void),fn3(void),fn4(void);voidmain(void)IStringstr("zhanglin");onexit(fnl);onexit(fn2);onexit(fn3);

91onexit(fn4);printfiThisisexecutedfirst.

92zz);}intfnl()printftnext.

93);return0;intfn2()(printfiexecuted");return0;}intfn3()Iprintf("is");return0;}intfn4()(printf("This");

94return0;}The_onexitfunctionispassedtheaddressofafunction(func)tobecalledwhentheprogramterminatesnormally.Successivecallsto_onexitcreatearegisteroffunctionsthatareexecutedinLIFO(last-in-first-out)order.Thefunctionspassedto_onexitcannottakeparameters.35.如何判断一段程序是由C编译程序还是由C++编译程序编译的?答案:#ifdefcpluspluscoutくく"c++”;ttelsecout«"c";ttendif36.文件中有一组整数,要求排序后输出到另ー个文件中答案:#include#includeくfstream〉usingnamespacestd;voidOrder(vector&data)//bubblesort

95iintcount=data,size();inttag=false;/Z设置是否需要继续冒泡的标志位for(inti=0;i

96if(data[j]>data[j+l])Itag=true;inttemp=data[j];data[j]=data[j+l];data[j+1]=temp;}}if(!tag)break;)}voidmain(void)ectordata;

97ifstreamin("c:\\data.txt");if(!in)(cout«"fileerror!";exit(1);}inttemp;while(!in.eof())(in»temp;data,pushback(temp);)in.close();〃关闭输入文件流Order(data);ofstreamout("c:\\result.txt");if(!out)icout«"fileerror!";exit(1);

98for(i=0;i

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
最近更新
更多
大家都在看
近期热门
关闭