计算机面试题.docx
《计算机面试题.docx》由会员分享,可在线阅读,更多相关《计算机面试题.docx(18页珍藏版)》请在冰豆网上搜索。
计算机面试题
Q2:
请你详细的解释一下IP协议的定义,在哪个层上面,主要有什么作用?
TCP与UDP呢?
解:
与IP协议配套使用的还有三个协议:
ARP-地址解析协议
RARP-逆地址解析协议
ICMP-因特网控制报文协议ICMP
IP协议-网际协议
IP地址、IP包头
----------------------------------------
Q3:
请问交换机和路由器分别的实现原理是什么?
分别在哪个层次上面实现的?
将网络互相连接起来要使用一些中间设备(或中间系统),ISO的术语称之为中继(relay)系统。
根据中继系统所在的层次,可以有以下五种中继系统:
1.物理层(即常说的第一层、层L1)中继系统,即转发器(repeater)。
2.数据链路层(即第二层,层L2),即网桥或桥接器(bridge)。
3.网络层(第三层,层L3)中继系统,即路由器(router)。
4.网桥和路由器的混合物桥路器(brouter)兼有网桥和路由器的功能。
5.在网络层以上的中继系统,即网关(gateway).
当中继系统是转发器时,一般不称之为网络互联,因为这仅仅是把一个网络扩大了,而这仍然是一个网络。
高层网关由于比较复杂,目前使用得较少。
因此一般讨论网络互连时都是指用交换机和路由器进行互联的网络。
本文主要阐述交换机和路由器及其区别。
第二层交换机和路由器的区别:
传统交换机从网桥发展而来,属于OSI第二层即数据链路层设备。
它根据MAC地址寻址,通过站表选择路由,站表的建立和维护由交换机自动进行。
路由器属于OSI第三层即网络层设备,它根据IP地址进行寻址,通过路由表路由协议产生。
因特网的路由选择协议:
内部网关协议IGP和外部网关协议EGP
第三层交换机和路由器的区别:
在第三层交换技术出现之前,几乎没有必要将路由功能器件和路由器区别开来,他们完全是相同的:
提供路由功能正在路由器的工作,然而,现在第三层交换机完全能够执行传统路由器的大多数功能。
综上所述,交换机一般用于LAN-WAN的连接,交换机归于网桥,是数据链路层的设备,有些交换机也可实现第三层的交换。
路由器用于WAN-WAN之间的连接,可以解决异性网络之间转发分组,作用于网络层。
他们只是从一条线路上接受输入分组,然后向另一条线路转发。
这两条线路可能分属于不同的网络,并采用不同协议。
相比较而言,路由器的功能较交换机要强大,但速度相对也慢,价格昂贵,第三层交换机既有交换机线速转发报文能力,又有路由器良好的控制功能,因此得以广播应用。
-----------------------------------------------
Q4:
请问C++的类和C里面的struct有什么区别?
c++中的类具有成员保护功能,并且具有继承,多态这类oo特点,而c里的struct没有
-----------------------------------------------
Q5:
请讲一讲析构函数和虚函数的用法和作用?
析构函数也是特殊的类成员函数,它没有返回类型,没有参数,不能随意调用,也没有重载。
知识在类对象生命期结束的时候,由系统自动调用释放在构造函数中分配的资源。
这种在运行时,能依据其类型确认调用那个函数的能力称为多态性,或称迟后联编。
另:
析构函数一般在对象撤消前做收尾工作,比如回收内存等工作,虚拟函数的功能是使子类可以用同
名的函数对父类函数进行重载,并且在调用时自动调用子类重载函数,如果是纯虚函数,则纯粹是为了
在子类重载时有个统一的命名而已。
-----------------------------------------------
Q6:
全局变量和局部变量有什么区别?
实怎么实现的?
操作系统和编译器是怎么知道的?
全局变量的生命周期是整个程序运行的时间,而局部变量的生命周期则是局部函数或过程调用的时
间段。
其实现是由编译器在编译时采用不同内存分配方法。
全局变量在main函数调用后,就开始分配,
如果是静态变量则是在main函数前就已经初始化了。
而局部变量则是在用户栈中动态分配的(还是建议
看编译原理中的活动记录这一块)
----------------------------------------------
Q7:
一些寄存器的题目,主要是寻址和内存管理等一些知识。
。
。
。
--------------------------------------------
Q8:
8086是多少尉的系统?
在数据总线上是怎么实现的?
8086系统是16位系统,其数据总线是20位
--------------------------------------
--------------------------------------
C++
一、请填写BOOL,float,指针变量与“零值”比较的if语句。
(10分)
请写出BOOLflag与“零值”比较的if语句。
(3分)
标准答案:
if(flag)
if(!
flag)
如下写法均属不良风格,不得分。
if(flag==TRUE)
if(flag==1)
if(flag==FALSE)
if(flag==0)
请写出floatx与“零值”比较的if语句。
(4分)
标准答案示例:
constfloatEPSINON=0.00001;
if((x>=-EPSINON)&&(x<=EPSINON)
不可将浮点变量用“==”或“!
=”与数字
比较,应该设法转化成“>=”或“<=”此
类形式。
如下是错误的写法,不得分。
if(x==0.0)
if(x!
=0.0)
请写出char*p与“零值”比较的if语句。
(3分)
标准答案:
if(p==NULL)
if(p!
=NULL)
如下写法均属不良风格,不得分。
if(p==0)
if(p!
=0)
if(p)
if(!
)
二、以下为WindowsNT下的32位C++程序,请计算sizeof的值(10分)
voidFunc(charstr[100])
{
请计算
sizeof(str)=4(2分)
}
charstr[]=“Hello”;
char*p=str;
intn=10;
请计算
sizeof(str)=6(2分)
sizeof(p)=4(2分)
sizeof(n)=4(2分)
void*p=malloc(100);
请计算
sizeof(p)=4(2分)
三、简答题(25分)
1、头文件中的ifndef/define/endif干什么用?
(5分)
答:
防止该头文件被重复引用。
2、#include和#include“filename.h”有什么区别?
(5分)
答:
对于#include,编译器从标准库路径开始搜索filename.h
对于#include“filename.h”,编译器从用户的工作路径开始搜索filename.h
3、const有什么用途?
(请至少说明两种)(5分)
答:
(1)可以定义const常量
(2)const可以修饰函数的参数、返回值,甚至函数的定义体。
被const修饰的东
西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
4、在C++程序中调用被C编译器编译后的函数,为什么要加extern“C”?
(5分)
答:
C++语言支持函数重载,C语言不支持函数重载。
函数被C++编译后在库中的名字
与C语言的不同。
假设某个函数的原型为:
voidfoo(intx,inty);
该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像
_foo_int_int之类的名字。
C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。
5、请简述以下两个for循环的优缺点(5分)
for(i=0;i{
if(condition)
DoSomething();
else
DoOtherthing();
}
if(condition)
{
for(i=0;iDoSomething();
}
else
{
for(i=0;iDoOtherthing();
}
优点:
程序简洁
缺点:
多执行了N-1次逻辑判断,并且
打断了循环“流水线”作业,使得编译
器不能对循环进行优化处理,降低了效
率。
优点:
循环的效率高
缺点:
程序不简洁
四、有关内存的思考题(每小题5分,共20分)
voidGetMemory(char*p)
{
p=(char*)malloc(100);
}
voidTest(void)
{
char*str=NULL;
GetMemory(str);
strcpy(str,"helloworld");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:
程序崩溃。
因为GetMemory并不能传递动态内存,
Test函数中的str一直都是NULL。
strcpy(str,"helloworld");将使程序崩
溃。
char*GetMemory(void)
{
charp[]="helloworld";
returnp;
}
voidTest(void)
{
char*str=NULL;
str=GetMemory();
printf(str);
}
请问运行Test函数会有什么样的结果?
答:
可能是乱码。
因为GetMemory返回的是指向“栈内存”
的指针,该指针的地址不是NULL,但其原
现的内容已经被清除,新内容不可知。
voidGetMemory2(char**p,intnum)
{
*p=(char*)malloc(num);
}
voidTest(void)
{
char*str=NULL;
GetMemory(&str,100);
strcpy(str,"hello");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:
(1)能够输出hello
(2)内存泄漏
voidTest(void)
{
char*str=(char*)malloc(100);
strcpy(str,“hello”);
free(str);
if(str!
=NULL)
{
strcpy(str,“world”);
printf(str);
}
}
请问运行Test函数会有什么样的结果?
答:
篡改动态内存区的内容,后果难以预
料,非常危险。
因为free(str);之后,str成为野指针,
if(str!
=NULL)语句不起作用。
五、编写strcpy函数(10分)
已知strcpy函数的原型是
char*strcpy(char*strDest,constchar*strSrc);
其中strDest是目的字符串,strSrc是源字符串。
(1)不调用C++/C的字符串库函数,请编写函数strcpy
char*strcpy(char*strDest,constchar*strSrc);
{
assert((strDest!
=NULL)&&(strSrc!
=NULL));//2分
char*address=strDest;//2分
while((*strDest++=*strSrc++)!
=‘\0’)//2分
NULL;
returnaddress;//2分
}
(2)strcpy能把strSrc的内容复制到strDest,为什么还要char*类型的返回值?
答:
为了实现链式表达式。
//2分
例如intlength=strlen(strcpy(strDest,“helloworld”));
六、编写类String的构造函数、析构函数和赋值函数(25分)
已知类String的原型为:
classString
{
public:
String(constchar*str=NULL);//普通构造函数
String(constString&other);//拷贝构造函数
~String(void);//析构函数
String&operate=(constString&other);//赋值函数
private:
char*m_data;//用于保存字符串
};
请编写String的上述4个函数。
标准答案:
//String的析构函数
String:
:
~String(void)//3分
{
delete[]m_data;
//由于m_data是内部数据类型,也可以写成deletem_data;
}
//String的普通构造函数
String:
:
String(constchar*str)//6分
{
if(str==NULL)
{
m_data=newchar[1];//若能加NULL判断则更好
*m_data=‘\0’;
}
else
{
intlength=strlen(str);
m_data=newchar[length+1];//若能加NULL判断则更好
strcpy(m_data,str);
}
}
//拷贝构造函数
String:
:
String(constString&other)//3分
{
intlength=strlen(other.m_data);
m_data=newchar[length+1];//若能加NULL判断则更好
strcpy(m_data,other.m_data);
}
//赋值函数
String&String:
:
operate=(constString&other)//13分
{
//
(1)检查自赋值//4分
if(this==&other)
return*this;
//
(2)释放原有的内存资源//3分
delete[]m_data;
//(3)分配新的内存资源,并复制内容//3分
intlength=strlen(other.m_data);
m_data=newchar[length+1];//若能加NULL判断则更好
strcpy(m_data,other.m_data);
//(4)返回本对象的引用//3分
return*this;
}
-------------------------------
winsocket编程
#include
#include
voidmain()
{
WORDwVersionRequested;
WSADATAwsaData;
interr;
wVersionRequested=MAKEWORD(1,1);
err=WSAStartup(wVersionRequested,&wsaData);
if(err!
=0){
return;
}
if(LOBYTE(wsaData.wVersion)!
=1||
HIBYTE(wsaData.wVersion)!
=1){
WSACleanup();
return;
}
SOCKETsockSrv=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_INaddrSrv;
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
listen(sockSrv,5);
SOCKADDR_INaddrClient;
intlen=sizeof(SOCKADDR);
while
(1)
{
SOCKETsockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
charsendBuf[100];
sprint(sendBuf,"Welcome%stohttp:
//www.sunxin.org",
inet_ntoa(addrClient.sin_addr));
send(sockConn,sendBuf,strlen(sendBuf)+1,0);
charrecvBuf[100];
recv(sockConn,recvBuf);
printf("%s\n",recvBuf);
closesocket(sockConn);
WSACleanup();
}
}
注:
这是Server端;File->New->Win32ConsoleApplication,工程名:
TcpSrv;然后,File->New->C++SourceFile,文件名:
TcpSrv;在该工程的Setting的Link的Object/librarymodules项要加入ws2_32.lib
-------------------------------------------
#include
#include
voidmain()
{
WORDwVersionRequested;
WSADATAwsaData;
interr;
wVersionRequested=MAKEWORD(1,1);
err=WSAStartup(wVersionRequested,&wsaData);
if(err!
=0){
return;
}
if(LOBYTE(wsaData.wVersion)!
=1||
HIBYTE(wsaData.wVersion)!
=1){
WSACleanup();
return;
}
SOCKETsockClient=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_INaddrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSrv.sin_family=AF_INET;
addrSrv.sin_porthtons(6000);
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
charrecvBuf[100];
recv(sockClient,recvBuf,100,0);
printf("%s\n",recvBuf);
send(sockClient,"Thisiszhangsan",strlen("Thisiszhangsan")+1,0);
closesocket(sockClient);
WSACleanup();
}
注:
这是Client端;File->New->Win32ConsoleApplication,工程名:
TcpClient;然后,File->New->C++SourceFile,文件名:
TcpClient;同理,在该工程的Setting的Link的Object/librarymodules项要加入ws2_32.lib
--------------------------------------------
C++
#include
classhuman
{
public:
human(){human_num++;};
staticinthuman_num;
~human(){
human_num--;
print();
}
voidprint()
{
cout<<"humannumis:
"<}
protected:
private:
};
inthuman:
:
human_num=0;
humanf1(humanx)
{
x.print();
returnx;
}
intmain(intargc,char*argv[])
{
humanh1;
h1.print();
humanh2=f1(h1);
h2.print();
return0;
}
输出:
1
1
0
0
-1
-2
----------------------------
分析:
humanh1; //调用构造函数,---hum_num=1;
h1.print(); //输出:
"humanis1"
humanh2=f1(h1);
//再调用f1(h1)的过程中,由于函数参数是按值传递对象,调用默认的复制构造函数,它并没有对hum_num++,所以hum_num仍=1,所以x.print()输出:
"humanis1"; 在推出f1函数时,要销毁X,调用析构函数(human_num--),输出:
"humanis0"(,由于该函数返回一个human对象,所以又调用默认构造函数,创建一个临时对象(human_num=0;),把临时对象赋给h2,又调用默认构造函数(human_num=0);
h2.print(); //输出:
humanis0;
//在退出main()函数是,先销毁h2,调用析构函数(human_num--),输出"human_numis-1"
然后销毁h1,调用析构函数(--),输出"human_numis-2"
-----------------------------
冒泡排序:
voidBubbleSort(elemtypex[],intn)
{
inti,j;
elemtypetemp;
for(i=1;i for(j=0;j {
if(x[j]