CVTE2017秋季校招笔试题回忆(C++后台岗)

1.概述

2016.09.06晚参加了CVTEC++岗的在线笔试。笔试题型分为不定向选择题和编程题,总共27题。其中不定项选择题为25道,编程题2道。其特点是不定项选择题不告诉你是单选还是多选,编程题不能复制黏贴,不用线上编译验证代码的正确性,提交代码即可!

运气不佳,浏览器中途退出,吐槽一下,CVTE考试系统没有时时保存功能,导致我的最后一道编程内容丢失,最终时间不够,没能写完。(不能给自己找借口,下次不能再出现这种情况,考试,要争分夺秒,把握时间!)

下面将能够回忆起的有疑问的题目列出来与大家分享。

2.笔试内容

2.1选择题

(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<<SIX<<endl;

#define SIX 2 * 3
cout<<SIX<<endl;

程序输出: 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。

2.2编程题

编程题难度不大,最重要的是不要出现浏览器意外关闭,注意把握好时间,切记切记,这是在考试,不是平时的编程!就像国乒男队教练刘国梁对藏獒张继科在里约奥运会上说的:“醒醒吧,这是在比赛。”

题目: 编程实现大整数相加,大整数范围是[−10100-10^{100},1010010^{100}]。比如 6666666666+1111111111=7777777777; -5555555555+2222222222=-3333333333。

思路 将大整数字符串按数位转换称相应的数值存储到数组中,然后再对数组进行运算,例如大整数字符串”66666688”,转换到int数组就是 int array={8,8,6,6,6,6,6,6}。

实现代码参考如下:

#include <iostream>
#include <string>
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;i<bigInt1.length();++i) 
        if(bigInt1[i]!='-'&&(bigInt1[i]<'0'||bigInt1[i]>'9'))
            return -1;
        else if(i>0&&bigInt1[i]=='-')
            return -1;

    for(int i=0;i<bigInt2.length();++i)
        if(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
}

上面的实现加入了严格的输入合法性检查,代码稍显冗余,有兴趣者可重构。按照上面的思路读者可给出自己的实现,而无需痛苦的看我那杂乱的代码。

3.小结

京东和CVTE两场笔试,有诸多不顺,均未达到自己的预期。不泄气,不放弃,继续努力,再接再厉,校招注定是个持久战。


参考文献

[1]Linux操作系统的主机名Hostname详细介绍 [2]ARP 属于哪层协议

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏游戏杂谈

php正则表达式的分组捕获

经过测试,发现php正则表达式获取分组捕获是从$0开始,而平时工作中JavaScript中的正则是$1..$9

1503
来自专栏逍遥剑客的游戏开发

Tiled源码分析(三): Undo/Redo实现

3227
来自专栏Python爬虫实战

Python爬虫之二:自制简易词典

运行平台: Windows Python版本: Python3.6 IDE: PyCharm 其他工具: Chrome浏览器

1152
来自专栏向治洪

Mpg123源代码详解

Mpg123与libmad一样,支持mpeg1,2,2.5音频解码。目前来看mpg123比libmad支持了网络播放功能。而且libmad基本上开源社区在200...

2257
来自专栏逸鹏说道

初级.NET程序员,你必须知道的EF知识和经验

注意:以下内容如果没有特别申明,默认使用的EF6.0版本,code first模式。 推荐MiniProfiler插件 工欲善其事,必先利其器。 我们使用EF和...

37810
来自专栏漏斗社区

CTF| SQL注入之获取数据类

上周发了一篇 SQL注入登录类的题型文章分析,这种题目一般是绕过登录限制。常规的SQL注入题需要我们一步步注入出数据,大部分题目需要我们有一定代码审计的能力,分...

4217
来自专栏北京马哥教育

有关bash,我希望我能知晓的十件事

1795
来自专栏开发 & 算法杂谈

基于Lockset的数据竞争检测方法汇总(二)

前一篇文章提到的是使用Lockset最经典的方法,但是存在很多误报,针对这些误报产生的原因,有很多分析并改进了原始的Lockset方法,今天主要和大家谈的就是有...

1747
来自专栏为数不多的Android技巧

请不要滥用SharedPreference

SharedPreference是Android上一种非常易用的轻量级存储方式,由于其API及其友好,得到了很多很多开发者的青睐。但是,SharedPrefer...

2314
来自专栏owent

Rust的第二次接触-写个小服务器程序

蛮久前入门了一下 Rust 语言。它的设计模型非常地吸引C/C++的开发者。但是学习语言嘛还是要练习一下,之前也用它给我们项目写了个命令行小工具。这回拿来写个小...

1.3K3

扫码关注云+社区

领取腾讯云代金券