史上最全C/C++面试题汇总

16 篇文章 0 订阅
1 篇文章 0 订阅

总结一些常见面试题,包括准备面试查阅的和自己实际面试中遇到的。不建议全篇的去背面试题,要学会将面试的知识点进行分类总结,聚合成一块块的知识点,然后去学习串联,推荐《王道程序员面试宝典》这本求职复习书籍,应付一般小厂的面试绰绰有余,内容很全面,建议反复阅读记忆。

一、C/C++部分

  • 多态的实现
    在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。
    如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数,此为多态的表现;

  • Cpp四种强制类型转换
    const_cast:从字面意思上就可以理解,去除变量的const属性。
    static_cast:静态类型转换,一般用于基本类型间的转换,如char->int
    dynamic_cast:动态转换,同于多态之间的类型转换
    reinterpret_cast:用于不同类型的指针类型的转换。

  • 类的static成员的特点
    static成员只有一份拷贝,被该类的所有对象所共享;
    static成员只能在类外初始化,并存放在全局(静态)存储区,不计入类的大小中;
    static可以通过类名直接访问,也可以通过对象访问;
    static成员函数只能访问static成员变量,因为其他的数据成员与生成的对象是绑定的,static成员函数不属于任何对象,没有this指针;

  • 指针和引用的区别
    引用是被引用对象的一个别名,其只能在定义的时候初始化,并且其值不能改变不能为空
    指针可以在任何时候给其赋值,并且其可以为nullptr
    sizeof引用为其引用对象的大小,sizeof指针为指针本身的大小
    对引用取地址为其引用对象的地址

  • 谈谈对Cpp内存的理解
    1、栈区(stack)― 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
    2、堆区(heap)― 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
    3、全局区(静态区)(static)― 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
    4、文字常量区 ― 常量字符串就是放在这里的。 程序结束后由系统释放
    5、程序代码区 ― 存放函数体的二进制代码。

  • 谈谈new、delete、malloc、free
    1.malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
    2.对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
    3.因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数

  • const关键字
    1.const 修饰类的成员变量,表示成员常量,不能被修改。
    2.const修饰函数承诺在本函数内部不会修改类内的数据成员,不会调用其它非 const 成员函数。
    3.如果 const 构成函数重载,const 对象只能调用 const 函数,非 const 对象优先调用非 const 函数。
    4.const 函数只能调用 const 函数。非 const 函数可以调用 const 函数。
    5.类体外定义的 const 成员函数,在定义和声明处都需要 const 修饰符。。
    int const *p / const int *p; //value是常数
    int * const p; //常指针
    int *const p const; //常指针、value值也是常数

  • static关键字

  • 构造函数为什么不能是虚函数

  • select、poll、epoll

  • 字符串的操作(C和C++都说一说)

  • 知道STL吗,挑两个你最常用的容器说一说
    vector:动态扩容数组
    map:key-value数据,自动排序去重。有以下几种不同的map(map、multimap、unordered_map、unordered_multimap),其中map用的是红黑树,unordered_map用的是hash表。

  • 怎么确定一个程序是C编译的还是C++编译的
    如果编译器在编译cpp文件,那么__cplusplus就会被定义,如果是一个C文件被编译,那么 _STDC_就会被定义,_STDC_是预定义宏,当它被定义后,编译器将按照ANSIC标准来编译C语言程序。

  • 说一下什么是内存泄漏,如何避免

  • 一个文件从源码到可执行文件所经历的过程
    1.预处理,产生.ii文件
    2.编译,产生汇编文件(.s文件)
    3.汇编,产生目标文件(.o或.obj文件)
    4.链接,产生可执行文件(.out或.exe文件)

  • 了解C++新特性吗
    1.关键字及新语法:auto、nullptr、for
    2.STL容器:std::array、std::forward_list、std::unordered_map、std::unordered_set
    3.多线程:std::thread、std::atomic、std::condition_variable
    4.智能指针内存管理:std::shared_ptr、std::weak_ptr
    5.其他:std::function、std::bind和lamda表达式

  • C++构造函数和析构函数在父子类之间的调用顺序

  • 什么是纯虚函数
    相当于一个函数接口,只声明不定义。在其派生类里会重写。有纯虚函数的类为抽象类,不能实例化出对象。

  • 构造函数和析构函数可以为虚函数吗
    构造函数不可以,析构函数可以甚至有时候必须声明为虚函数。

  • 栈和堆的区别,什么时候必须使用堆
    栈是由程序分配的,而堆是由程序员手动去分配释放的。当需要的空间特别大的时候,就必须使用堆,因为栈的大小是有限制的,一般为5MB左右,所以当需要一个大块空间是,必须在堆上开辟空间。

  • 如何不用sizeof判断一个机器是16位还是32位

  • 用宏定义实现swap
    #define F(a, b) (a = a ^ b);(b = a ^ b);(a = a ^ b);

  • 头文件<>和""的区别
    遇到#include<math.h>时,系统先从系统默认的头文件目录中查找头文件
    遇到#include"math.h"时,系统先从当前的目录中搜索,若没有找到,再从系统默认的头文件中找
    故包含系统提供的库函数用#include<math.h>更快
    当包含用户自定义的.h文件时,使用#include"math.h"更快

  • 编写string的构造函数、拷贝构造函数、赋值操作符重载和析构函数

#include<cstring>
#include<iostream>

using namespace std;

class MyString {
public:
    MyString(const char* pcData = nullptr) {
        if(pcData == nullptr) {
            m_pdata = new char[1];
            *m_pdata = '\0';
        }
        else {
            int len = strlen(pcData);
            m_pdata = new char[len+1];
            strcpy(m_pdata, pcData);
        }
    }

    MyString(const MyString& other) {
        int len = strlen(other.m_pdata);
        m_pdata = new char[len+1];
        strcpy(m_pdata, other.m_pdata);
    }
	
    MyString& operator =(const MyString &str) {
		if(this == &str)
			return *this;
		delete [] m_pdata;
		m_pdata = nullptr;
		m_pdata = new char[strlen(str.m_pdata)+1];
		strcpy(m_pdata, str.m_pdata);
		return *this;
    }

    void Print() {
        cout << this->m_pdata << endl;
    }

    ~MyString() {
        delete [] m_pdata;
    }

private:
    char* m_pdata;
};

int main() {
    MyString mstr;
	MyString mstr2("hello world!");
	mstr = mstr2;
	mstr.Print();
	mstr2.Print();

	return 0;
}

二、操作系统部分

  • 进程和线程间的通信方式
    Linux进程:管道、有名管道、信号、信号量、共享内存、消息队列、套接字
    Linux线程:互斥体、信号量、条件变量
    Windows进程:管道、共享内存、消息队列、信号量、套接字
    Windows线程:临界区、互斥量、信号量、事件

  • 死锁产生的原因和死锁的条件
    原因:系统资源的竞争、进程推进顺序非法
    条件:互斥条件、不剥夺条件、请求和保持条件、循环等待条件

  • 如何采用单线程处理高并发
    采取I/O复用来提高单线程处理多请求的能力(epoll和select)
    采用事件驱动模型,基于异步回调来处理事件

  • 线程的状态
    新建(NEW)、可运行(RUNNABLE)、运行(RUNNING)、阻塞(BLOCKED)、死亡(DEAD)

  • 进程的状态
    运行状态:进程正在处理器上运行,在单处理器环境下,每一时刻最多只有一个进程处于运行状态。
    就绪状态:进程已处于准备运行的状态,即进程获得了除处理器之外的一切所需要的资源,一旦得到处理器即可运行。
    阻塞状态:又称为等待状态,进程正在等待某一事件而暂停运行。如等待某资源为可用(不包括处理器)或等待输入/输出完成。即使处理器空闲,该进程也不能运行。
    创建状态:进程正在被创建,尚未转到就绪状态。
    结束状态:进程正从系统中消失。可能是进程正常结束或其它原因中断退出运行。

  • 系统调用brk和mmap
    从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)。
    1、brk是将数据段(.data)的最高地址指针_edata往高地址推;
    2、mmap是在进程的虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空闲的虚拟内存。
    这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。
    在标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的。

  • 进程和线程的区别

  • 常用的Linux命令

  • Makefile

  • gcc/g++

  • gdb

  • shell

  • 什么是虚拟内存

  • 说说三种内存管理机制
    页式管理:
    段式管理:
    分段分页管理:

  • 大端和小端,用C++代码怎么确定
    大端低地址存放高位,高地址存放地位。小端相反。

union un {
	char a;
	int b;
}
un tmp.b = 1;
if(tmp.a) {
	cout << "小端" << endl;
}
else {
	cout << "大端" << endl;
}

三、计算机网络部分

  • TCP和UDP的区别
    用户数据报协议 UDP(User Datagram Protocol) 是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加UDP首部),支持一对一、一对多、多对一和多对多的交互通信。
    传输控制协议 TCP(Transmission Control Protocol) 是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一)。

    1.TCP面向连接, UDP面向无连接的
    2.TCP有保障的,UDP传输无保障的
    3.TCP是效率低的,UDP效率高的
    4.TCP是基于流的,UDP基于数据报文
    5.TCP传输重要数据,UDP传输不重要的数据

  • TCP三次握手
    首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。A 向 B 发送连接请求报文,SYN=1,ACK=0,选择一个初始的序号 x。
    B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。
    A 收到 B 的连接确认报文后,还要向 B 发出确认,确认号为 y+1,序号为 x+1。
    B 收到 A 的确认后,连接建立。

  • 三次握手的原因
    第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。
    客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打开连接。

  • TCP四次挥手
    以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。
    A 发送连接释放报文,FIN=1。
    B 收到之后发出确认,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
    当 B 不再需要连接时,发送连接释放报文,FIN=1。
    A 收到后发出确认,进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。
    B 收到 A 的确认后释放连接。

  • 四次挥手的原因
    客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。

  • TIME_WAIT
    客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
    确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
    等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。

  • 一个URL从输入到浏览器地址栏开始都发生了什么

  • 编写socket套接字的步骤

  • Http协议
    http(超文本传输协议)是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式,HTTP1.1版本中给出一种持续连接的机制,绝大多数的Web开发,都是构建在HTTP协议之上的Web应用。

四、数据结构算法部分

  • 几种常见的排序算法
    快排、插入、选择,这是最基本的三个,建议背下来,最有可能让你手撕的。

  • 链表的一些性质和操作
    链表是最常用也是比较简单的一个基本数据结构,几乎是构成所有高级结构的基础,面试常拿链表做文章。建议了解链表的一些常见问题:

    • 如何判断链表有环
      使用快慢指针,当两个指针重合证明有环
    • 转置链表O(n)时间、O(1)空间
      三个指针,改变next指针指向
  • 常见的查找算法

    • 二分法
  • 动态规划

    • 最长公共子序列

五、个人面试经验总结

其实就应届生来说,面试官考察的时候还是很仁慈的,不会问得很深,而且专挑你会的问。基本上你简历上写什么他就问什么。
建议可以去实习的同学一定要去实习,实习经历和实习项目将会是一个重要的加分项和谈资,有一次面试,我和人家技术全程就在谈我实习期间的工作和项目。大概进行了半个多小时,直接通过。而且每次面试,针对项目和实习经历这一块,都会聊至少半个小时。所以,有条件一定要去实习,有基础一定要做一个有得说的项目。
就C/C++而言,一般你只需要把语言和Linux(shell、gcc/g++、makefile、gdb这些是你应该了解的,并且以后工作中一定会用到的)学好,基本上就没什么大问题,数据结构和算法尽量学,但是基本的一定要会,然后就是操作系统和计算机网络,这是做后端开发必备的技能点,能学多好学多好,不过对应届生而言,差点也没关系。至于数据库,能学就学,反正我是没有系统的去学,会写SQL语句一般问题就不大。然后有兴趣和时间,推荐学习一些开源组件,类似于Nginx、各大MQ、docker。。。反正多学点指定没有坏处。

  • 101
    点赞
  • 1157
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值