2016.09.06晚参加了CVTEC++岗的在线笔试。笔试题型分为不定向选择题和编程题,总共27题。其中不定项选择题为25道,编程题2道。其特点是不定项选择题不告诉你是单选还是多选,编程题不能复制黏贴,不用线上编译验证代码的正确性,提交代码即可!
运气不佳,浏览器中途退出,吐槽一下,CVTE考试系统没有时时保存功能,导致我的最后一道编程内容丢失,最终时间不够,没能写完。(不能给自己找借口,下次不能再出现这种情况,考试,要争分夺秒,把握时间!)
下面将能够回忆起的有疑问的题目列出来与大家分享。
(1)进程调度中,进程切换(上下文切换)时,被换出的进程的上下文保存在哪里?
首先说一下什么是进程调度。因用户进程数一般都多于CPU数或CPU核数,这将导致它们互相争夺CPU资源,因此操作系统需要进行进程调度,合理的安排CPU资源的分配,安排的方法就是进程调度算法。
因进程的调度,所以就需要将进程从CPU中换入和换出,这就是进程切换,也叫上下文切换(Context Switch)。进程的上下文由PCB(进程控制块)表示,它包括进程状态,CPU寄存器的值,中断位置,堆栈上的内容等,当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。
关于PCB的位置,PCB Wikipedia描述如下:
Since PCB contains the critical information for the process, it must be kept in an area of memory protected from normal user access. In some operating systems the PCB is placed in the beginning of the kernel stack of the process since that is a convenient protected location。
PCB保存在内存中,一般存储在内核栈的开始位置,便于阻止用户访问,保护PCB不被修改。所以,被换出的进程的上下文保存在内存中,便于频繁进程间的切换,如果存储在磁盘中,那切换的速度将无法忍受。
(2)宏定义#define SIX 2*3和#define SIX 2 * 3
有区别吗?
宏定义的格式:
#define 标识符 字符串
宏定义只是简单的文本替换,字符串中当然可以有空格,所以题目中的宏定义是没有区别的。测试代码如下:
#define SIX 2*3
cout<#define SIX 2 * 3
cout<
程序输出:
6
6
(3)驱动程序一定要与具体的硬件设备关联吗?
驱动程序一般指的是设备驱动程序(Device Driver),是一种可以使计算机和设备通信的特殊程序。相当于硬件的接口,操作系统只有通过这个接口,才能控制硬件设备的工作,假如某设备的驱动程序未能正确安装,便不能正常工作。
按照百度百科对驱动程序的解释,个人觉得驱动程序一定要与具体的硬件设备关联。但听到网友的回复,不一定,可参考虚拟光驱。这个也言之有理,就不深究了,如有错误,请批评指正。
(4)Linux中,什么配置文件包含主机名到IP地址和映射?
A etc/networks
B etc/hosts
C etc/HOSTNAME
D etc/resolv.conf
答案选择B。
每台主机一定有一个或多个IP地址,一个IP地址可以绑定一个或多个域名,一个IP地址也可以映射成一个或多个主机名。主机名与域名都可以唯一指定一台主机,但主机名与域名是不同的。域名存在于公网,主机名存在于局域网。
主机名的配置文件是etc/hosts,其内容大致如下:
第一部份:网络IP地址;
第二部份:主机名.域名,注意主机名和域名之间有个半角的点,比如 localhost.localdomain;
第三部份:主机名。
例如局域网中的三台主机,每台做不同的事,一台做MAIL服务器,一台做FTP服务器,一台做SMB服务器,那么etc/hosts配置称如下内容。
127.0.0.1 localhost.localdomain localhost
192.168.1.2 ftp.localdomain ftp
192.168.1.3 mail.localdomain mail
192.168.1.4 smb.localdomin smb
(5)TCP/IP网络参考模型有哪几层?
TCP/IP网络参考模型将网络层级结构分为四层,简介如下。
名称 | 功能 | 协议 |
---|---|---|
应用层(Application Layer) | 负责实现一切与应用程序相关的功能,对应OSI参考模型的上三层(应用层,表示层和会话层) | FTP(文件传输协议) HTTP(超文本传输协议) DNS(域名系统) SMTP(简单邮件传输协议) NFS(网络文件系统协议 |
传输层(Transport Layer) | 为应用层实体提供端到端的通信功能,保证了数据包的顺序传送及数据的完整性。对应于OSI参考模型的第四层——传输层。 | TCP(控制传输协议) UDP(用户数据报协议) |
网际层(Internet Layer) | 负责网络间的寻址、数据传输,对应OSI参考模型的第五层——网络层 | IP(网际协议) ICMP(互联网控制报文协议) IGMP(互联网组管理协议) ARP(地址解析协议) RARP(反向地址解析协议) |
网络接入层(Network Access Layer) | 负责实际数据的传输,对应OSI参考模型的下两层(数据链路层和物理层) | HDLC(高级链路控制协议) PPP(点对点协议) SLIP(串行线路接口协议) |
注意: ARP和RARP在OSI参考模型中属于数据链路层,而非网络层。
(6)Linux内核配置命令是什么?
Linux内核的配置系统由三个部分组成,分别是:
Makefile:分布在 Linux 内核源代码根目录及各层目录中,定义 Linux 内核的编译规则;
配置文件:给用户提供配置选择的功能;
配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于 Ncurses 图形界面以及基于 Xwindows 图形界面的用户配置界面,各自对应于Make config、Make menuconfig 和 make xconfig)。
所以Linux内核配置命令是 Make config、Make menuconfig 和 make xconfig。
(7)FAT32文件系统最大支持的文件大小?
常见文件系统情况如下:
FAT16(Windows):支持最大分区2GB,最大文件2GB;
FAT32(Windows):支持最大分区128GB,最大文件4GB;
NTFS(Windows):支持最大分区2TB,最大文件2TB;
HPFS(OS/2):支持最大分区2TB,最大文件2GB;
EXT2EXT3(Linux):支持最大分区4TB,最大文件2GB;
JFS(AIX):支持最大分区4P(block size=4k),最大文件4P;
XFS(IRIX):这是个正经的64位的文件系统,可以支持9E(2的63次方)的分区;
知其然,更要知其所以然,那么FAT32为什么最大只支持4G的文件呢?
FAT32(32bits File Allocation Table)是Windows系统硬盘分区格式的一种,这种格式采用32位的文件分配表,即FAT32文件系统寻址单位为32位,因为FAT32规定文件长度一项属性占4个字节,所以单个文件最大只能是4GB-1。
编程题难度不大,最重要的是不要出现浏览器意外关闭,注意把握好时间,切记切记,这是在考试,不是平时的编程!就像国乒男队教练刘国梁对藏獒张继科在里约奥运会上说的:“醒醒吧,这是在比赛。”
题目:
编程实现大整数相加,大整数范围是[ −10100 , 10100 ]。比如
6666666666+1111111111=7777777777;
-5555555555+2222222222=-3333333333。
思路
将大整数字符串按数位转换称相应的数值存储到数组中,然后再对数组进行运算,例如大整数字符串”66666688”,转换到int数组就是 int array={8,8,6,6,6,6,6,6}。
实现代码参考如下:
#include
#include
using namespace std;
/**********************
*@brief:检查输入的合法性
*@ret:0:合法;-1:非法
**********************/
int check(const string& bigInt1,const string& bigInt2){
//为空报错
if(bigInt1==""||bigInt2=="")
return -1;
//包含除'-'和'0'-'9'字符外的字符且'-不能出现在其它位置'
for(int i=0;iif(bigInt1[i]!='-'&&(bigInt1[i]<'0'||bigInt1[i]>'9'))
return -1;
else if(i>0&&bigInt1[i]=='-')
return -1;
for(int i=0;iif(bigInt2[i]!='-'&&(bigInt2[i]<'0'||bigInt2[i]>'9'))
return -1;
else if(i>0&&bigInt2[i]=='-')
return -1;
//最高数字位不能为0
if(bigInt1[0]=='-'&&bigInt1[1]=='0'||bigInt1[0]=='0')
return -1;
if(bigInt2[0]=='-'&&bigInt2[1]=='0'||bigInt2[0]=='0')
return -1;
return 0;
}
/**********************
*@brief:检查输入的合法性
*@ret:成功返回对应的大整数字符串,错误返回空串
**********************/
string bigIntegerAdd(const string& bigInt1,const string& bigInt2){
if(check(bigInt1,bigInt2))
return "";
int maxLen=bigInt1.length()>bigInt2.length()?bigInt1.length():bigInt2.length();
int* num1=new int[maxLen+1];
int* num2=new int[maxLen+1];
memset(num1,0,sizeof(int)*(maxLen+1));
memset(num2,0,sizeof(int)*(maxLen+1));
int j=0;
for(int i=bigInt1.length()-1;i>=0;--i)
if(bigInt1[i]!='-')
num1[j++]=bigInt1[i]-'0';
j=0;
for(int i=bigInt2.length()-1;i>=0;--i)
if(bigInt2[i]!='-')
num2[j++]=bigInt2[i]-'0';
//两数位正数
if(bigInt1[0]!='-'&&bigInt2[0]!='-'){
j=0;
while(bigInt2[j]){ //将num2加到num1
if(num1[j]+num2[j]>=10){
num1[j]=num1[j]+num2[j]-10;
num1[j+1]+=1; //进位
}else
num1[j]+=num2[j];
++j;
}
j=0;
string res;
while(num1[j])
res=to_string(num1[j++])+res;
return res;
}
//两负数相加
if(bigInt1[0]=='-'&&bigInt2[0]=='-'){
j=0;
while(bigInt2[j+1]){ //将num2加到num1
if(num1[j]+num2[j]>=10){
num1[j]=num1[j]+num2[j]-10;
num1[j+1]+=1; //进位
}else
num1[j]+=num2[j];
++j;
}
j=0;
string res;
while(num1[j])
res=to_string(num1[j++])+res;
return "-"+res;
}
//两数一正一负
string negativeBigInt=bigInt1[0]=='-'?bigInt1:bigInt2;
string positiveBigInt=bigInt1[0]!='-'?bigInt1:bigInt2;
string negativeBigIntAbs=negativeBigInt.erase(0,1);
j=0;
for(int i=negativeBigIntAbs.length()-1;i>=0;--i)
num1[j++]=negativeBigIntAbs[i]-'0';
j=0;
for(int i=positiveBigInt.length()-1;i>=0;--i)
num2[j++]=positiveBigInt[i]-'0';
if(negativeBigIntAbs.length()>=positiveBigInt.length()&&negativeBigIntAbs>positiveBigInt){ //负数绝对值大于正数
j=0;
while(positiveBigInt[j]){ //将num2加到num1
if(num1[j]-num2[j]<0){
num1[j]=num1[j]+10-num2[j];
num1[j+1]-=1; //借位
}else
num1[j]-=num2[j];
++j;
}
j=0;
string res;
while(num1[j])
res=to_string(num1[j++])+res;
return "-"+res;
}else{ //负数绝对值大于正数
j=0;
while(negativeBigIntAbs[j]){ //将num2加到num1
if(num2[j]-num1[j]<0){
num2[j]=num2[j]+10-num1[j];
num2[j+1]-=1; //借位
}else
num2[j]-=num1[j];
++j;
}
j=0;
string res;
while(num2[j])
res=to_string(num2[j++])+res;
return res;
}
}
//测试代码
int main(){
string res;
res=bigIntegerAdd("0066666666666","7"); //输入非法,结果:空串
res=bigIntegerAdd("-6-6666666666","7"); //输入非法,结果:空串
res=bigIntegerAdd("66666666666a","7"); //输入非法,结果:空串
res=bigIntegerAdd("66666666666a","0"); //输入非法,结果:空串
res=bigIntegerAdd("66666666666","1111111111"); //结果:67777777777
res=bigIntegerAdd("-66666666666","-1111111111"); //结果:-68888888888
res=bigIntegerAdd("66666666666","-7"); //结果:66666666659
}
上面的实现加入了严格的输入合法性检查,代码稍显冗余,有兴趣者可重构。按照上面的思路读者可给出自己的实现,而无需痛苦的看我那杂乱的代码。
京东和CVTE两场笔试,有诸多不顺,均未达到自己的预期。不泄气,不放弃,继续努力,再接再厉,校招注定是个持久战。
[1]Linux操作系统的主机名Hostname详细介绍
[2]ARP 属于哪层协议