C/C++培训
美国上市C/C++培训机构

400-111-8989

热门课程

北理大佬一万多字的C++面试总结

  • 时间:2017-11-28
  • 发布:牛客网
  • 来源:西瓜橙子雨

自报家门,北理工软件学院本科生。

本文主要部分:

1、毕业去向选择

2、春招过程

3、暑期实习

4、秋招辛酸路程

5、一点感悟

毕业去向选择问题

从大一开始,就决定毕业找工作,方向是有了,但是三年多过去了,到现在才发现,大学期间并没有为这个方向做出太大的努力,这也成为我一个本科生找工作的很大障碍,实践能力严重不足。

我的情况是:我决定工作,但是由于高中的思维,太看重学习成绩,成绩搞的很好,虽然有保研资格,但是又不读研,找工作的时候,好的互联网公司不看成绩,看能力,所以大厂的笔面试都挂掉了。

现在反思过后,给学弟学妹一点建议,如果你打算读研,搞好成绩保研是最轻松的。如果你想工作,多实践,多写项目,多去开源社区fork别人的项目,多动手,找到自己的兴趣所在,并深入研究。我的一个同学,毕业根本不需要找工作,很多公司来抢着要他,技术大牛!如果你想出国,英语方面多积累总是没错的,多说多记。

春招过程

因为有就业打算,暑期准备实习,所以大三下学期就去参加春招了,基本从3月份开始,各大厂就开始春招实习生了,但是由于没有经验,没有准备,吃了太多的亏:当时课程项目做网站,对web开发熟悉,于是网易就报了前端实习生,结果笔试直接就挂掉,考的全是html+css;腾讯笔试挂,编程题不会;阿里笔试挂,连题都看不懂;百度一面挂,基础知识太弱,问啥啥不会。

给学弟学妹的建议:既然已经决定找暑期实习,那么就好好好准备春招,操作系统、计算机网络、数据库、算法和数据结构等基础知识一定要掌握扎实!有出色项目经验更好,但大部分本科生来说没有,所以面试官也更看重你的基础知识掌握程度。 另外在投递实习公司的时候,最好问清楚转正几率大不大;想好自己准备从事的行业,金融、教育、互联网、游戏等等,找到一份自己毕业准备从事的行业公司去实习,不然就像LZ一样,实习完才反应过来自己想喜欢游戏,然后秋招的时候发现不同岗位的实习经历也不会给你加太多分。

暑期实习

春招的尾巴拿到了华为的软件开发实习offer,7月初到本研所实习,入职时才发现被调剂了岗位,有点坑。实习期间很轻松,但是最后由于行业和方向不喜欢放弃了转正offer。

两个月实习的收获:更加清楚了未来自己要从事什么行业,什么方向,你的职业规划,这对于一个毕业生来说十分重要!!因为全栈大神不是人人都能做到,公司需要专才,并且对自已的职业生涯有清楚认识的人。

我是准备先从游戏c++客户端程序员干起,在项目中熟悉各个分工的任务内容和工作流程,积累经验,然后向项目、产品和管理方面发展。因为你一个刚毕业的本科生,啥也不会,怎么可能一去公司就去做管理,让你管人家你管的了吗,必须把一个项目的每个流程走几遍,熟悉了之后才行。所以学弟学妹一定要找准自己的位置,行业-》方向-》职位-》职业规划。

之前参加几个偏国企的群面,很多人被问到你想从事哪个方向的开发,都因为太想得到offer说我做这个也行,做那个也行,实在不行做那个也行,看公司需要吧。我个人认为,如果你这样说公司把你招了,这种公司不去也罢,你未来能有什么成长和发展!

秋招心酸历程

好事多磨!好事多磨!好事多磨!

9月底从华为离职,然后放弃学校的保研名额,各位可以想象当时LZ是多么的自信和年轻。

之后就是秋招开始了,各种宣讲会笔试面试蜂拥而来,各种撞车,各种一天来回跑,参加过秋招的同学应该都有体会,真的很过瘾!

说下我的情况,我到10月下旬时,还是0offer。从最开始的自信满满,到笔试挂掉,面试挂掉,看到别人收offer,看到别人谈薪资,心态真的爆炸坏了,有时候晚上跑完宣讲会坐在回学校的公交车上,看着窗外繁华的夜景,过来过往的人群,很是迷茫和感伤。

国庆期间我的心态爆炸到极点,书也看不进去,天天肝阴阳师,打屁股,都不想找工作了。但是我还是熬了过来,重新拾起信心,投身到新一波的跑宣讲会和笔面试中!这中间的心理变化和成长我觉得对我个人而言太宝贵了!然后这周开始,我陆续收到了一个游戏公司和一个半国企的两个offer,其中游戏公司的薪资远远超出我的预期,非常满意!爆炸满意!我在收到第一个offer的前一天,还奔波在各种笔面试之间!

结合自己的经历,给学弟学妹的建议:

好好准备编程题,因为如果是在线笔试,一般都是大公司,你不能AK的话3道至少也要AC两道吧,不然前边客观题答得再好,作为一个程序员不会写代码要你干嘛;

项目经验一定要准备好,没有经验的话看看别人都是怎么准备项目的,之前看了牛客上一个情商爆炸的哥们的面试准备,那叫一个牛,项目的展开,如何引导面试官向自己擅长的方向提问等等,不服不行;

另外如果编程能力确实不行的话,去跑宣讲会的线下笔试,一般会稍微简单一些(LZ的offer都是线下笔试);

多总结,每次笔面试后想一想遇到的问题你真的会了吗,不会赶紧补习,因为下一场真的会遇到一模一样的题目(LZ遇到好几次一样的题目,然后好几次不会,后来才每个都认真总结,复习)。

一点感悟

上面的经验是根据每个阶段反思后得出的,最后说一下总的思路(个人看法,辩证对待):

1.赶紧找到自己的毕业去向,工作、读研、出国、公务员等

2. 如果是毕业准备工作的话,大学期间多动手,专业知识掌握扎实的同时,多动手,多写代码,找到自己的兴趣所在,深入研究

3.想好自己将来要从事的行业,方向,未来几年的职业规划

4.大三暑假找一份有意义!!的实习,通过实习感受理想与现实的不同,直接转正更好,秋招时也会是你的加分项

5.秋招复习基础知识,多编程,别眼高手低,好好准备项目,学学 如何引导面试官, 能力不行多跑宣讲会的线下笔试

6.一定不要放弃,不要灰心,天生我材必有用!坚持住!好事多磨!最后祝大家前程似锦!

下面是我的一个一万多字的c++笔面试总结,包含数据库,计网,操作系统,算法,数据结构,设计模式和c++等多方面的笔面试总结,有的是提纲,大部分都展开详细有描述了,可能有错误,看的时候小心查证。

范式

第一范式:数据库表的每一项都是不可分割的原子数据项,不能是集合。比如班级信息表里面不能有班级的学生。

第二范式:在第一范式的基础上,所有属性完全依赖于主键,完全依赖就是不能取决于主键的一部分

第三范式:在第二范式的基础上,消除传递依赖,比如学生表里有学生属于的班级编号,但不能有班级的名称,班级人数等班级信息,因为班级信息可有由班级编号通过班级表推出来,有传递依赖

第一范式->第二范式->第三范式

→→→数据冗余越来越少,查询越来越复杂

←←←有数据冗余,但查询简单

事 务

并发控制的单位,是用户定义的一个操作序列,要么全做,要么全不做,是不可分割的。

1原子性

2一致性:

使数据库从一个一致性状态到另一个一致性状态

3隔离性:

一个事物的执行不被其他事务干扰

4永久性:

一个事务一旦提交,它对数据库的改变就是永久性的

常用 SQL语句

分组查询(avg max min)、复杂连接查询、嵌套查询、结果排序(逆序ansc)、

错题

虚存=min (主存+辅存,逻辑地址)

进程和线程

进程是程序的一次执行,包括代码和数据,是CPU分配资源的基本单位,一个进程可以包括多个线程。进程之间通信方式:管道、SOCKET、信号量(互斥、同步)等。

子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品。

线程是独立运行和独立调度的基本单位(线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度),线程之间共享进程的数据空间(借此通信)

进程的调度算法

文件系统

内存分配策略

HTTP协议

基于TCP协议的应用层协议

H TTP是一个普通用在浏览器和web服务器之间进行数据交换的 文本 协议

HTTP协议的ETAG响应头主要用于信息的过期验证

HTML错误代码

(1) 常见错误代码:

200服务器成功返回了网页,成功处理了请求

304未修改,自从上次请求后,请求的页面未被修改过,此时服务器不会返回网页内容,节省带宽和开销

404请求的网页不存在

500服务器内部错误

503服务器暂时不可用(超载、停机维护),通常只是暂时状态

(2) 1xx:临时响应,服务器端响应成功, 等待请求者进一步操作

(3) 2xx:响应成功

202接受请求,未处理

204处理了请求,但没有返回任何内容

(4) 3xx重定向,要完成响应,服务器需要进一步处理

301网页已被永久移动到新位置

302临时移动到新位置

305要求只能使用代理才能访问

(5) 4xx请求错误

400不理解请求语法

401要求身份验证,先登陆才能请求

403禁止访问,服务器拒绝请求

405请求中的方法被禁用

408请求超时

(6) 5xx服务器在处理请求时内部发生错误,来自服务器本身的错误

501服务器不具备完成该请求的功能

502服务器作为网关或代理,从上游服务器收到无效响应

504网关超时

505 HTTP版本不支持

TCP/IP与UDP

TCP与UDP

TCP面向连接、可靠的数据传输,有拥塞控制和流量控制,大量数据,速度慢

UDP非连接,不可靠的数据传输,少量数据,速度快

TCP建立连接的三次握手

详细过程和状态变化

为什么要三次?

TCP关闭连接的四次挥手

FIN- ->

<--FINACK

ß FIN

FINACK-->

如何提高UDP的可靠性

应用层 实现超时重传,客户端发送一个包,服务器返回一个包表示收到,如果客户端超过一定时间没有收到该包,就需要重传

备用

SOCKET编程

当recv函数在接受数据时是阻塞的,当返回值<0,说明连接出错

当返回值=0,表示对端关闭了连接

返回值>0,接受到的数据的大小

TCP/IP分层,各层作用

应用层:为操作系统、应用程序提供访问网络的接口(Telnet、FTP、HTTP、SNMP、DNS域名解析)

(表示层)

(会话层)

传输层:两点之间的根据使用的协议(TCP、UDP),传输相应数据报文,

网络层:整个网络的传输路径选择,路由(IP、RIP)

网络访问层:数据链路层、物理层的结合,数据链路层相邻节点之间数据帧传输,物理层就是光纤上比特级的数据传输。

PING操作的原理

使用ICMP,在IP主机、路由器之间传递控制消息

网络层的协议

IP协议 根据IP地址决定转发、路由的协议

ICMP本质理解为带差错报告的IP协议,在主机和路由器之间传递控制信息(网络通不通,主机可不可达,路由可不可达到)

ARP:将IP地址转化为MAC地址

RARP:物理地址转为IP地址

RIP

传输层的协议

TCP

UDP

SPX

应用层协议

HTTP

SMTP:简单邮件传输协议

DNS:

Telnet

FTP:文件传输协议

WWW:

NFS: 网络文件系统

DNS的完整流程(域名->IP地址)

DNS采用 分布式 的域名系统,减少故障发生

当一个应用需要把主机名解析为IP地址时,该应用程序就会调用解析程序,把待解析的域名放在DNS请求报文中,以 UDP数据报 方式发送给本地域名服务器,本地服务器在查找域名后,把对应的IP地址放在回答报文中返回,应用程序获得目的主机的IP地址后即可进行通信。若本地域名服务器不能解析该域名,则向上级域名服务器继续发送查询请求,直到可以解析为止。

备用

HTTP1.0/1.1区别

HTTP1.1中才有 cache-control响应头,主要用于控制信息在浏览器的缓存

1. HTTP 1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求

缺陷:访问一个包含有许多图像的网页文件的整个过程包含了多次请求和响应,每次请求和响应都需要建立一个单独的连接,每次连接只是传输一个文档和图像,器端每次建立和关闭连接却是一个相对比较费时的过程,并且会严重影响客户机和服务器的性能

2. HTTP 1.1支持持久连接,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟

HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果

HTTP 1.1还提供了Host、身份认证、状态管理和Cache缓存等机制相关的请求头和响应头

C++

一定要弄懂c++的内存分配机制,父类,子类继承时的内存如何分配,封装、继承、多态、虚函数的实现机制和原理。

小细节

实现String类

String类的原型如下

class String

{

public:

String(const char *str=NULL); //构造函数

String(const String &other); //拷贝构造函数

~String(void); //析构函数

String& operator=(const String &other); //等号操作符重载

ShowString();

private:

char *m_data; //指针

};

String::~String()

{

delete [] m_data; //析构函数,释放地址空间

}

String::String(const char *str)

{

if (str==NULL)//当初始化串不存在的时候,为m_data申请一个空间存放'\0';

{

m_data=new char[1];

*m_data='\0';

}

else//当初始化串存在的时候,为m_data申请同样大小的空间存放该串;

{

int length=strlen(str);

m_data=new char[length+1];

strcpy(m_data,str);

}

}

String::String(const String &other)//拷贝构造函数,功能与构造函数类似。

{

int length=strlen(other.m_data);

m_data=new [length+1];

strcpy(m_data,other.m_data);

}

String& String::operator =(const String &other)

{

if (this==&other)//当地址相同时,直接返回;

return *this;

delete [] m_data;//当地址不相同时,删除原来申请的空间,重新开始构造;

int length= strlen (other.m_data);

m_data=new [length+1];

strcpy(m_data,other.m_data);

return *this;

}

String::ShowString()//由于m_data是私有成员,对象只能通过public成员函数来访问;

{

cout<<this->m_data<<endl;

}

Str cmp strcpy的返回类型

C++如何限制类对象只能静态分配或者只能只能动态分配

动态分配就是用运算符new来创建一个类的对象,在堆上分配内存。

静态分配就是A a;这样来由编译器来创建一个对象,在栈 上分配内存。

(1)动态分配(在堆上分配内存)

将类的构造函数和析构函数设为protected属性,这样类对象不能够访问,但是派生类能够访问,能够正常的继承。同时创建另外两个create和destory函数类创建对象。(将create设为static原因是:创建对象的时候是A *p = A::create();只有静态成员函数才能够通过类名来访问。)

[cpp] view plaincopy

1. class A

2. {

3. protected :

4. A(){}

5. ~A(){}

6. public :

7. static A* create()

8. {

9. return new A();

10. }

11. void destory()

12. {

13. delete this ;

14. }

15. };

(2)静态分配(在栈上)

把new、delete运算符重载为private属性就可以了。

[cpp] view plaincopy

1. class A

2. {

3. private :

4. void * operator new ( size_t t){} // 注意函数的第一个参数和返回值都是固定的

5. void operator delete ( void * ptr){} // 重载了new就需要重载delete

6. public :

7. A(){}

8. ~A(){}

9. };

实现strcpy()

char * strcpy(char* dest, const char* src)

{

assert(dest!=NULL&&src!=NULL);

char* res=dest;

while((*dest++=*src++)!=’\0’);

return res;

}

内联函数与宏

用内联取代宏:

1.内联函数在运行时可调试,而宏定义不可以;

2.编译器会对内联函数的参数类型做安全检查或自动类型转换(同普通函数),而宏定义则不会;

3.内联函数可以访问类的成员变量,宏定义则不能;

4.在类中声明同时定义的成员函数,自动转化为内联函数。

抽象类、接口

抽象类是包含纯虚函数的类

虚继承

作用: 为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。

这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题。

底层实现原理: 底层实现原理与编译器相关,一般通过虚基类指针实现,即各对象中只保存一份父类的对象,多继承时通过

虚基类指针引用该公共对象,从而避免菱形继承中的二义性问题。

多继承的二义性

构造函数中可不可以抛出异常?析构函数呢?

理论上都可以抛出异常。

但析构函数最好不要抛出异常,将会导致析构不完全,从而有内存泄露

构造函数和析构函数中调用虚函数

可以,虚函数底层实现原理

C++中的空类,默认产生哪些类成员函数

class Empty

{

public:

Empty(); // 缺省构造函数

Empty( const Empty& ); // 拷贝构造函数

~Empty(); // 析构函数

Empty& operator=( const Empty& ); // 赋值运算符

Empty* operator&(); // 取址运算符

const Empty* operator&() const; // 取址运算符 const

};

函数指针

Int and(int a,int b){return a+b;}

int (*p)(int ,int );

p=and;

int c=(*p)(1,2);

Int型变量作为bool使用

除了 0是false其余都为true

Int a=-2;while(a++);//执行2次

int c=-2;

int a=c||0;//a=1

面向对象的特性

抽象、继承、封装、多态

重载运算符

. * :: sizeof ?: 不能重载

const A operator +(A &b)

{

return A(this.data+b.data)

}

指针和引用

★ 区别:

1.指针是一个实体,而引用仅是个别名;

2.引用使用时无需解引用(*),指针需要解引用;

3.引用只能在定义时被初始化一次,之后不可变;指针可变;

4.引用没有const,指针有const;

5.引用不能为空,指针可以为空;

6.“sizeof引用”得到的是所指向的变量(对象)的大小,而“sizeof指针”得到的是指针本身(所指向的变量或对象的地址)的大小;

7.指针和引用的自增(++)运算意义不一样;

8.从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域

基类析构函数为虚函数

在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生,如果只调用基类的析构函数,则派生类没有释放掉,造成内存泄漏

C++11

a uto i= 10;

auto s=” hello ”;

强制类型转换符

dynamic_cast

该转换符用于 将一个指向派生类的基类指针或引用转换为派生类的指针或引用

//B 是D的基类,D是派生类

B* pb;

D* pd,md ;

pb = &md;

pd=dynamic_cast<D *>(pb);

把指向派生类D的基类指针pb转换为派生类D的指针,然后将这个指针赋给派生类D的指针pd。

如果指向派生类的基类指针B想访问派生类D中的除虚函数之外的成员时就需要把该指针转换为指向派生类D的指针,以达到访问派生类D中特有的成员的目的,比如派生类D中含有特有的成员函数g(),这时可以这样来访问该成员 dynamic_cast<D *>(pb)->g(); 因为dynamic_cast转换后的结果是一个指向派生类的指针,所以可以这样访问派生类中特有的成员。但是该语句不影响原来的指针的类型,即基类指针pb仍然是指向基类B的。如果单独使用该指针仍然不能访问派生类中特有的成员。

dynamic_cast的注意事项

dynamic_cast转换符只能用于指针或者引用。dynamic_cast转换符只能用于含有虚函数的类。dynamic_cast转换操作符在执行类型转换时首先将检查能否成功转换,如果能成功转换则转换之,如果转换失败,如果是指针则反回一个0值,如果是转换的是引用,则抛出一个bad_cast异常,所以在使用dynamic_cast转换之间应使用if语句对其转换成功与否进行测试,比如 pd = dynamic_cast(pb); if(pd){…}else{…} ,或者这样测试if(dynamic_cast(pb)){…}else{…} 。

因此, dynamic_cast操作符一次执行两个操作。 首先验证被请求的转换是否有效,只有转换有效,操作符才实际进行转换。基类的指针可以赋值为指向派生类的对象,同样,基类的引用也可以用派生类对象初始化,因此,dynamic_cast操作符执行的验证必须在运行时进行。

const_cast操作符

该操作符用于改变const和volatile, const_cast最常用的用途就是删除const属性;

操作符不能改变类型的其他方面,他只能改变const或volatile,即const_cast不能把int改变为double,但可以把const int改变为int。const_cast只能用于指针或引用。

int a=3; const int *b=&a; int* c=const_cast(b); *c=4; cout<<a<<*c; 输出为两个4

static_cast操作符

该操作符用于非多态类型的转换,任何标准转换都可以使用他,即static_cast可以把int转换为double,但不能把两个不相关的类对象进行转换,比如类A不能转换为一个不相关的类B类型。static_cast本质上是传统c语言强制转换的替代品。

reinterpret_cast操作符

该操作符用于将一种类型转换为另一种不同的类型,比如可以把一个整型转换为一个指针,或把一个指针转换为一个整型,因此使用该操作符的危险性较高,一般不应使用该操作符。

reinterpret_cast(重述转换)主要是将数据从一种类型的转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释

String to int

#include <sstream>

stringstream ss;

int a=15454;

ss<<a;

string c=”str:”+ss.str();

cout<<c<<endl;

构造函数调用顺序

先调用 基类 构造函数

在调用 成员类 构造函数

最后调用 本身 的构造函数

析构顺序 相反

。。。。。。

本文内容转载自网络,本着分享与传播的原则,版权归原作者所有,如有侵权请联系我们进行删除!

上一篇:C++培训:C++开发程序员如何进阶?
下一篇:2017年阿里面试必会20道C++面试题!

2017年阿里面试必会20道C++面试题!

北理大佬一万多字的C++面试总结

做C++开发是否面临职业生涯短暂的问题?

常见的十道C/C++程序员面试题

选择城市和中心
贵州省

广西省

海南省