程序员面试题整理非算法题Word格式文档下载.docx
- 文档编号:16471576
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:79
- 大小:873.27KB
程序员面试题整理非算法题Word格式文档下载.docx
《程序员面试题整理非算法题Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《程序员面试题整理非算法题Word格式文档下载.docx(79页珍藏版)》请在冰豆网上搜索。
externvoid*memset(void*buffer,intc,intcount);
把buffer所指内存区域的前count个字节设置成字符c。
返回指向buffer的指针。
4.C++的空类有哪些成员函数
缺省构造函数。
缺省拷贝构造函数。
缺省析构函数。
缺省赋值运算符。
缺省取址运算符。
缺省取址运算符const。
5.写出floatx与“零值”比较的if语句。
if(x>
0.000001&
&
x<
-0.000001)
6.Internet采用哪种网络协议?
该协议的主要层次结构?
Tcp/Ip协议
主要层次结构为:
应用层/传输层/网络层/数据链路层/物理层
7.Internet物理地址和IP地址转换采用什么协议?
ARP(AddressResolutionProtocol)(地址解析協議)
8.IP地址的编码分为哪俩部分?
IP地址由两部分组成,网络号和主机号。
不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。
9.变量的声明和定义有什么区别
为变量分配地址和存储空间的称为定义,不分配地址的称为声明。
一个变量可以在多个地方声明,但是只在一个地方定义。
加入extern修饰的是变量的声明,说明此变量将在文件以外或在文件后面部分定义。
10.sizeof和strlen的区别
sizeof和strlen有以下区别:
sizeof是一个操作符,strlen是库函数。
sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为‘\0‘的字符串作参数。
编译器在编译时就计算出了sizeof的结果。
而strlen函数必须在运行时才能计算出来。
并且sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度。
数组做sizeof的参数不退化,传递给strlen就退化为指针了。
11.C中的malloc和C++中的new有什么区别
malloc和new有以下不同:
(1)new、delete是操作符,可以重载,只能在C++中使用。
(2)malloc、free是函数,可以覆盖,C、C++中都可以使用。
(3)new可以调用对象的构造函数,对应的delete调用相应的析构函数。
(4)malloc仅仅分配内存,free仅仅回收内存,并不执行构造和析构函数
(5)new、delete返回的是某种数据类型指针,malloc、free返回的是void指针
12.一个指针可以是volatile吗
volatile类似于大家所熟知的const也是一个类型修饰符。
volatile是给编译器的指示来说明对它所修饰的对象不应该执行优化。
volatile的作用就是用来进行多线程编程。
可以,因为指针和普通变量一样,有时也有变化程序的不可控性。
常见例:
子中断服务子程序修改一个指向一个buffer的指针时,必须用volatile来修饰这个指针
13.static有什么用途?
对于局部变量改变其生存期,对于全局变量改变其可见性
主要从两个方面考虑:
(1)静态存储:
a.函数体内static变量的作用范围为该函数体,该内存在静态数据区上分配且只被分配一次,下次再调用该函数时依然维持上一次的值。
b.类中的static成员变量属于整个类所有,对类的所有对象只有一份拷贝
c.在类中的static成员函数属于整个类所拥有,这个函数不接受this指针,因而只能访问类的static成员变量。
(2)控制名字可见性
a.在模块内的static全局变量可以被模块内的所有函数访问,但是不能被模块外的其他函数访问
b.在模块内的static成员函数只可被这一模块内的其他函数调用,这个函数的使用范围被限制在声明它的模块内。
14.引用与指针有什么区别
1)引用必须被初始化,指针不必。
2)引用初始化以后不能被改变,指针可以改变所指的对象。
3)不存在指向空值的引用,但是存在指向空值的指针。
15.描述实时系统的基本特性
在特定时间内完成特定的任务,实时性与可靠性。
16.简述C、C++程序编译的内存分配情况
C、C++中内存分配方式可以分为三种:
(1)从静态存储区域分配:
内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。
速度快、不容易出错,因为有系统会善后。
例如全局变量,static变量等。
(2)在栈上分配:
在执行函数时,函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。
栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)从堆上分配:
即动态内存分配。
程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在何时用free或delete释放内存。
动态内存的生存期由程序员决定,使用非常灵活。
如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,另外频繁地分配和释放不同大小的堆空间将会产生堆内碎块。
一个C、C++程序编译时内存分为5大存储区:
堆区、栈区、全局区、文字常量区、程序代码区
17.谈谈你对拷贝构造函数和赋值运算符的认识
拷贝构造函数和赋值运算符重载有以下两个不同之处:
(1)拷贝构造函数生成新的类对象,而赋值运算符不能。
(2)由于拷贝构造函数是直接构造一个新的类对象,所以在初始化这个对象之前不用检验源对象是否和新建对象相同。
而赋值运算符则需要这个操作,另外赋值运算中如果原来的对象中有内存分配要先把内存释放掉
注意:
当有类中有指针类型的成员变量时,一定要重写拷贝构造函数和赋值运算符,不要使用默认的。
18.不能被继承的类
(1)构造函数private
此时我们可以通过static成员函数获得该类的实例(我们只能得到位于堆上的实例)
classFinalClass1
public:
staticFinalClass1*GetInstance()
{
returnnewFinalClass1;
}
staticvoidDeleteInstance(FinalClass1*pInstance)
deletepInstance;
pInstance=0;
private:
FinalClass1(){}
~FinalClass1(){}
};
(2)
想法:
实现一个和一般类除了不能被继承之外其他用法都一样的类
typenameT>
classMakeFinal
friendT;
MakeFinal(){}
~MakeFinal(){}
classFinalClass2:
virtualpublicMakeFinal<
FinalClass2>
FinalClass2(){}
~FinalClass2(){}
此时FinalClass2就不能再被继承了,由于类FinalClass2是从类MakeFinal<
虚继承过来的,在调用Try的构造函数的时候,会直接跳过FinalClass2而直接调用MakeFinal<
的构造函数。
(虚继承的一个特征就是虚基类的构造函数由最终子类负责构造)非常遗憾的是,Try不是MakeFinal<
的友元,因此不能调用其私有的构造函数。
基于上面的分析,试图从FinalClass2继承的类,一旦实例化,都会导致编译错误,因此是FinalClass2不能被继承。
这就满足了我们设计要求。
19.访问基类的私有虚函数
很好的题目,借这个题目学习虚函数。
解题思路就是:
虽然不能通过对象调用这个虚函数,但是因为虚函数会在子类的那段内存中保存虚函数表的入口地址,拿到虚函数的地址就可以转换成函数指针来调用他。
下面主要解释这一行代码:
pFun=(Fun)*((int*)*(int*)(&
b)+i);
(1)在子类内存空间中最开始(就是子类对象的地址&
b)的地方存了一个指向虚函数表的指针(这里的最开始的说法应该是大多数编译器的做法),为了获得这个指向虚函数表的指针,需要做这个操作*(int*)&
b,解释:
对象b的地址强制转换成一个int指针(因为地址都是整型数),然后再解引用该指针获得虚表的指针值。
(2)再做一次(int*)获得虚表首地址的值,然后+i,每次+1都指向下一个虚函数的入口地址
(3)最后(Fun),将虚函数入口地址强制转换为函数指针,用函数指针来完成这个私有虚函数的调用。
iostream.h>
classA
{
virtualvoidg(){cout<
A:
:
g"
<
endl;
}
private:
virtualvoidf(){cout<
f"
classB:
publicA
voidg(){cout<
B:
virtualvoidh(){cout<
h"
typedefvoid(*Fun)(void);
voidmain()
Bb;
FunpFun;
for(inti=0;
i<
3;
i++)
pFun();
}
20.类成员函数的重载、重写和隐藏
成员函数被重载的特征
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual关键字可有可无。
覆盖是指派生类函数覆盖基类函数,特征是
(1)不同的范围(分别位于派生类与基类);
(3)参数相同;
(4)基类函数必须有virtual关键字。
“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下
(1)如果派生类的函数与基类的函数同名,但是参数不同。
此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。
此时,基类的函数被隐藏(注意别与覆盖混淆)
21.简述多态实现的原理
编译器发现一个类中有虚函数,便会立即为此类生成虚函数表vtable。
虚函数表的各表项为指向对应虚函数的指针。
编译器还会在此类中隐含插入一个指针vptr(对vc编译器来说,它插在类的第一个位置上)指向虚函数表。
调用此类的构造函数时,在类的构造函数中,编译器会隐含执行vptr与vtable的关联代码,将vptr指向对应的vtable,将类与此类的vtable联系了起来。
另外在调用类的构造函数时,指向基础类的指针此时已经变成指向具体的类的this指针,这样依靠此this指针即可得到正确的vtable,。
如此才能真正与函数体进行连接,这就是动态联编,实现多态的基本原理。
22.inline
使用内联函数应注意的事项
内联函数具有一般函数的特性,它与一般函数所不同之处只在于函数调用的处理。
一般函数进行调用时,要将程序执行权转到被调用函数中,然后再返回到调用它的函数中;
而内联函数在调用时,是将调用表达式用内联函数体来替换。
在使用内联函数时,应注意如下几点:
1.在内联函数内不允许用循环语句和开关语句。
如果内联函数有这些语句,则编译将该函数视同普通函数那样产生函数调用代码,递归函数(自己调用自己的函数)是不能被用来做内联函数的。
内联函数只适合于只有1~5行的小函数。
对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数实现。
2.内联函数的定义必须出现在内联函数第一次被调用之前。
3.本栏目讲到的类结构中所有在类说明内部定义的函数是内联函数。
23.Const成员函数
const成员函数可以被相同参数表的非const成员函数重载。
在这种情况下,类对象的常量性决定了调用哪个函数。
构造函数和析构函数是两个例外,即使构造函数和析构函数不是const成员函数,const对象也可以调用它们。
23.几个实例
问题(16):
运行如下的C++代码,输出是什么?
public:
virtualvoidFun(intnumber=10)
std:
cout<
Funwithnumber"
number;
classB:
publicA
virtualvoidFun(intnumber=20)
intmain()
Bb;
A&
a=b;
a.Fun();
答案:
输出B:
Funwithnumber10。
由于a是一个指向B实例的引用,因此在运行的时候会调用B:
Fun。
但缺省参数是在编译期决定的。
在编译的时候,编译器只知道a是一个类型a的引用,具体指向什么类型在编译期是不能确定的,因此会按照A:
Fun的声明把缺省参数number设为10。
这一题的关键在于理解确定缺省参数的值是在编译的时候,但确定引用、指针的虚函数调用哪个类型的函数是在运行的时候。
问题(17):
运行如下的C代码,输出是什么?
char*GetString1()
charp[]="
HelloWorld"
;
returnp;
char*GetString2()
char*p="
int_tmain(intargc,_TCHAR*argv[])
printf("
GetString1returns:
%s.\n"
GetString1());
GetString2returns:
GetString2());
return0;
输出两行,第一行GetString1returns:
后面跟的是一串随机的内容,而第二行GetString2returns:
HelloWorld.两个函数的区别在于GetString1中是一个数组,而GetString2中是一个指针。
当运行到GetString1时,p是一个数组,会开辟一块内存,并拷贝"
初始化该数组。
接着返回数组的首地址并退出该函数。
由于p是GetString1内的一个局部变量,当运行到这个函数外面的时候,这个数组的内存会被释放掉。
因此在_tmain函数里再去访问这个数组的内容时,结果是随机的。
当运行到GetString2时,p是一个指针,它指向的是字符串常量区的一个常量字符串。
该常量字符串是一个全局的,并不会因为退出函数GetString2而被释放掉。
因此在_tmain中仍然根据GetString2返回的地址得到字符串"
。
问题(19):
运行下图中C代码,输出的结果是什么?
charstr1[]="
helloworld"
charstr2[]="
char*str3="
char*str4="
if(str1==str2)
str1andstr2aresame.\n"
);
else
str1andstr2arenotsame.\n"
if(str3==str4)
str3andstr4aresame.\n"
str3andstr4arenotsame.\n"
输出两行。
第一行是str1andstr2arenotsame,第二行是str3andstr4aresame。
str1和str2是两个字符串数组。
我们会为它们分配两个长度为12个字节的空间,并把"
的内容分别拷贝到数组中去。
这是两个初始地址不同的数组,因此比较str1和str2的值,会不相同。
str3和str4是两个指针,我们无需为它们分配内存以存储字符串的内容,而只需要把它们指向"
helloworld“在内存中的地址就可以了。
由于"
helloworld”是常量字符串,它在内存中只有一个拷贝,因此str3和str4指向的是同一个地址。
因此比较str3和str4的值,会是相同的。
题目(13):
编译运行下图中的C++代码,结果是什么?
(A)编译错误;
(B)编译成功,运行时程序崩溃;
(C)编译运行正常,输出10。
请选择正确答案并分析原因。
iostream>
intvalue;
A(intn)
value=n;
A(Aother)
value=other.value;
voidPrint()
value<
Aa=10;
Ab=a;
b.Print();
编译错误。
在复制构造函数中传入的参数是A的一个实例。
由于是传值,把形参拷贝到实参会调用复制构造函数。
因此如果允许复制构造函数传值,那么会形成永无休止的递归并造成栈溢出。
因此C++的标准不允许复制构造函数传值参数,而必须是传引用或者常量引用。
在VisualStudio和GCC中,都将编译出错。
题目(七):
运行下列C++代码,输出什么?
A()
Print();
virtualvoidPrint()
Aisconstructed.\n"
B()
Bisconstructed.\n"
A*pA=newB();
deletepA;
先后打印出两行:
Aisconstructed.Bisconstructed.调用B的构造函数时,先会调用B的基类及A的构造函数。
然后在A的构造函数里调用Print。
由于此时实例的类型B的部分还没有构造好,本质上它只是A的一个实例,他的虚函数表指针指向的是类型A的虚函数表。
因此此时调用的Print是A:
Print,而不是B:
Print。
接着调用类型B的构造函数,并调用Print。
此时已经开始构造B,因此此时调用的Print是B:
同样是调用虚拟函数Print,我们发现在类型A的构造函数中,调用的是A:
Print,在B的构造函数中,调用的是B:
因此虚函数在构造函数中,已经失去了虚函数的动态绑定特性。
题目
(一):
我们可以用static修饰一个类的成员函数,也可以用const修饰类的成员函数(写在函数的最后表示不能修改成员变量,不是指写在前面表示返回值为常量)。
请问:
能不能同时用static和const修饰类的成员函数?
分析:
答案是不可以。
C++编译器在实现const的成员函数的时候为了确保该函数不能修改类的实例的状态,会在函数中添加一个隐式的参数constthis*。
但当一个成员为static的时候,该函数是没有this指针的。
也就是说此时static的用法和const是冲突的。
我们也可以这样理解:
两者的语意是矛盾的。
static的作用是表示该函数只作用在类型的静态变量上,与类的实例没有关系;
而const的作用是确保函数不能修改类的实例的状态,与类型的静态变量没有关系。
因此不能同时用它们。
题目
(二):
运行下面的代码,输出是什么?
classB
B(){}
~B(){}
classC
C(){}
virtual~C(){}
%d,%d,%d\n"
sizeof(A),
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 程序员 试题 整理 算法