admin管理员组

文章数量:1608632

C++面试题汇总

  • 1. C基础
    • 1.1 内存模型
      • 1.1.0 内存四区
      • 1.1.1 简述C、C++程序编译的内存分配情况
      • 1.1.2 分配函数与释放函数
        • 1.1.2.1 malloc / free
        • 1.1.2.2 new / delete
        • 1.1.2.3 new/delete 与 malloc/free 区别
        • 1.1.2.5 calloc 、realloc
        • 1.1.2.6 在C++中,使用malloc申请的内存能否通过delete释放?使用new申请的内存能否用free?
    • 1.2 预编译
      • 1.2.1 头文件问题
      • 1.2.2 const 与 #define相比有什么优点
    • 1.3 宏,内联函数
      • 1.3.1 内联函数
      • 1.3.2 内联函数与宏的差别
      • 1.3.3 写一个 “标准”宏MIN
      • 1.3.4 typedef 和define 有什么区别
    • 1.4 指针
      • 1.4.1 指针常量和常量指针
      • 1.4.2 指针函数和函数指针
      • 1.4.3 指针数组数组指针
      • 1.4.4 函数传参
      • 1.4.5 一些定义
      • 1.4.6 指针与引用的区别
      • 1.4.7 this指针
      • 1.4.8 指针和句柄
      • 1.4.9 如何避免“野指针”
      • 1.4.10 空指针与迷途指针区别
    • 1.5 const
      • 1.5.1 const 使用
      • 1.5.2 const 作用
      • 1.5.3 如何修改const成员函数
      • 1.5.4 将Const类型转化为非Const类型
    • 1.6 sizeof
      • 1.6.1 sizeof 和strlen 的区别
      • 1.6.2 sizeof 的使用场合
    • 1.7 强制类型转换运算符
    • 1.8 什么是右值引用,跟左值又有什么区别?
      • 1.9 变量的声明和定义有什么区别
      • 1.10 说一说extern“C”
  • 2. C++面向对象
    • 2.1 面对对象的三大特性(基本特征)
    • 2.2 封装
    • 2.3 继承
    • 2.4 多态
    • 2.5 成员函数
      • 2.5.1 构造函数与析构函数
      • 2.5.2 初始化列表方式
      • 2.5.3 构造函数调用方式
      • 2.5.4 C++的空类默认产生哪些成员函数
      • 2.5.5 继承中子类和父类的构造和析构顺序
      • 2.5.6 深拷贝与浅拷贝
      • 2.5.6 拷贝构造函数与赋值运算符
      • 2.5.7 C 语言的关键字 static 和 C++ 的关键字 static 有什么区别
      • 2.5.8 静态成员
      • 2.5.9 常函数与常对象
    • 2.6 引用
      • 2.6.1 引用
      • 2.6.2 常引用
      • 2.6.3 引用与指针区别
    • 2.7 虚函数
      • 2.7.1 虚函数与纯虚函数
      • 2.7.2 抽象类
      • 2.7.3 虚析构与纯虚析构
      • 2.7.4 多态类中的虚函数表是compile-Time建立的还是Run-Time建立的
      • 2.7.5 析构函数可为virtual型,构造函数不能,为什么?
      • 2.7.6 能否把每个函数都声明为虚函数?
    • 2.8 隐藏、重载与重写
    • 2.9 class 与struct 区别
    • 2.10 友元
  • 3. STL
    • 3.1 vector的底层原理
    • 3.2 vector中的reserve和resize的区别
    • 3.3 vector中的size和capacity的区别
    • 3.4 vector中erase方法与algorithn中的remove方法区别
    • 3.5 vector迭代器失效的情况
    • 3.6 正确释放vector的内存(clear(), swap(), shrink_to_fit())
    • 3.7 list的底层原理
    • 3.8 什么情况下用vector,什么情况下用list,什么情况下用deque
    • 3.9 priority_queue的底层原理
    • 3.10 map 、set、multiset、multimap的底层原理
    • 3.11 为何map和set的插入删除效率比其他序列容器高
    • 3.12 为何map和set每次Insert之后,以前保存的iterator不会失效?
    • 3.13 当数据元素增多时(从10000到20000),map的set的查找速度会怎样变化?
    • 3.14 map 、set、multiset、multimap的特点
    • 3.15 为何map和set的插入删除效率比其他序列容器高,而且每次insert之后,以前保存的iterator不会失效?
    • 3.16 为何map和set不能像vector一样有个reserve函数来预分配数据?
    • 3.17 set的底层实现实现为什么不用哈希表而使用红黑树?
    • 3.18 hash_map与map的区别?什么时候用hash_map,什么时候用map?
    • 3.19 迭代器失效的问题
    • 3.20 STL线程不安全的情况
  • 4. C++ 11
    • 4.1 NULL与nullptr
      • 4.1.1 C语言中的NULL
      • 4.1.2 C++中的NULL
      • 4.1.3 C++中的nullptr
    • 4.2 智能指针

C++知识点总结: 快速跳转

1. C基础

1.1 内存模型

1.1.0 内存四区

意义在于:赋予其不同的生命周期,给编程带来更大的灵活性

  • 运行前
    • 代码区:存放函数体的二进制代码,由操作系统管理
      • 共享的
      • 只读的:防止程序意外修改其指令
    • 全局区:存放全局变量和静态变量以及常量,结束后由系统释放
      • 全局区还包括常量区(字符串常量,const修饰的全局常量)
  • 运行后
    • 栈区:由编译器自动分配和释放,存放函数体的参数值、局部变量
      • 不能返回局部变量的地址,当离开作用域后,开辟在栈区的局部变量会被编译器自动回收
    • 堆区:由程序员分配和释放,若不释放,程序结束后由操作系统释放
      • 分全局堆和局部堆
      • 全局堆就是所有没有分配的空间,局部堆就是用户分配的空间
      • 堆在操作系统对进程 初始化的时候分配,运行过程中也可以向系统要额外的堆

1.1.1 简述C、C++程序编译的内存分配情况

  • 从静态存储区域分配
    内存在程序 编译 时 就已 经 分配 好,这块内 存在 程序 的整 个运行 期间 都存在 。速 度快、不容易出错 , 因 为 有系 统 会善 后。例 如全 局变 量, sta tic 变量, 常量 字符 串等。
  • 在栈上分配
    在执行函数时, 函数内局部变量的存储单元都在栈上创建,函数执行结束时这些存储单元自动被释放。 栈内存分配运算内置于处理器的指令集中, 效率很高, 但是 分配的内存容量有限 。大小为2M。
  • 从堆上分配
    即动态内存分配。程序在运行的时候用 malloc 或 new 申请任意大小的内存,程序员自己负责在何时用 free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活。如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏 ,另外频繁地分配和释放不同大小的堆空间将会产生堆内碎块 。

一个C、C++ 程序****编译时内存分为5大存储区:堆区、栈区、全局区、文字常量区、程序代码区

1.1.2 分配函数与释放函数

  • C:malloc、calloc、realloc / free
  • C++:new / delete
1.1.2.1 malloc / free

大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度,指向下一个分配块的指针等等

  • malloc函数向内存申请一块连续可用的空间
  • 开辟成功则返回一个指向该空间的void* 型指针,所以需要对其进行强制类型转换,转换成我们想要的类型
  • 开辟失败则返回 NULL,所以一定要对malloc的返回值进行检查
  • free 用来释放动态开辟的内存,而不是释放指针
int* ptr = NULL;
ptr = (int*)malloc(1000*sizeof(int));//开辟一千个int大小的内存,并强制类型转换
if(NULL == ptr){
   
	exit(1);
}
free(ptr);
ptr = NULL;
  • 释放只能一次,如果释放两次及两次以上会出现错误
  • 释放空指针例外,释放空指针其实也等于什么都没做,所以释放空指针释放多少次都没有问题
1.1.2.2 new / delete

new分配内存步骤

  • 调用operator new 函数
  • 调用相应的构造函数构造对象,并传入初值
  • 对象构造完成后,返回一个指向该对象的指针

delete释放内存步骤

  • 调用对象的析构函数
  • 调用operator delete 函数释放内存空间
//开辟变量
int* a = new int(10);
delete a;

//开辟数组
int* arr = new int[10];
delete[] arr;
1.1.2.3 new/delete 与 malloc/free 区别
  • 开辟位置
    • 严格来说,malloc动态开辟的内存在堆区,new开辟的叫做自用存储区
    • 若不重载new操作符,c++编译器一般默认使用堆来实现自用存储,此时等价于堆区
    • 特别:new可以不为对象分配内存
  • 重载
    • new 、delete 是操作符,可以重载,只能在C++ 中使用。 malloc、free 是函数,可以覆盖,C、C++ 中都可以使用。
  • 是否调用构造与析构函数
    • new 可以调用对象的构造函数,对应的delete 调用相应的析构函数。malloc 仅仅分配内存,free 仅仅回收内存,并不执行构造和析构函数
  • 是否需要指定内存大小
    • malloc 需要显式指出开辟内存的大小,new 无需指定,编译器会自动计算
  • 返回值类型
    • new返回的是某种数据类型指针,malloc返回的是void 指针,new比malloc更安全
    • new内存分配失败时,会抛出bac_alloc异常,不会返回NULL;malloc开辟内存失败会返回NULL指针,所以需要判断
1.1.2.5 calloc 、realloc

calloc(number,size):为number个大小为size的元素开辟一块空间,并把每个字节初始化为0
realloc(内存地址,大小):用于调整申请的空间大小

1.1.2.6 在C++中,使用malloc申请的内存能否通过delete释放?使用new申请的内存能否用free?

不能,malloc/free主要为了兼容C,new和 delete 完全可以取代malloc/free的。malloc/free 的操作对象都是必须明确大小的。而且不能用在动态类上。new 和 delete会自动进行类型检查和大小 ,malloc/free不能执行构造函数与析构函数 ,所 以动态对象它是不行的。当然从理论上说使用malloc 申请的内存是可以通过delete释放的 。不过一般不这样写的。而且也不能保证每个C++的运行时都能正常

1.2 预编译

1.2.1 头文件问题

  • #include < >:只搜索系统目录,不会搜索本地目录
  • #include " ":首先搜索本地目录,若找不到才会搜索系统目录
  • #include<>相较于#include" " 快一些

1.2.2 const 与 #define相比有什么优点

  • const 常量有数据类型,而宏常量没有数据类型,编译器可以对前者进行安全检查。对后者只进行字符替换,没有安全类型检查,并且在字符替换可能会产生意想不到的错误
  • 有些集成化的调试工具可用对const进行调试,但是不能对宏常量进行调试

1.3 宏,内联函数

1.3.1 内联函数

  • 定义:在函数定义体前加入关键字inline,使函数成为内联函数
  • 增加空间消耗换取效率提高,这点与宏一样
  • 内联函数和普通函数相比可以加快程序运行的速度,因为不需要中断调用
void fun(int x,int y);
inline void fun(int x,int y){
   //必须放在定义体前面,不能放在声明前面
	...
}
  • 适用情况
    • 一个函数不断被重复调用
    • 函数只有简单几行,且函数内不包括for、while、switch语句

1.3.2 内联函数与宏的差别

  • 内联函数要做类型检查,而宏不需要
  • 宏是在代码处不加任何验证的简单替代,而内联函数是将代码直接插入到调用处,而减少了普通函数调用时的资源消耗

1.3.3 写一个 “标准”宏MIN

#define min( a, b)( (a )<=(b) ?( a) :(b ))

1.3.4 typedef 和define 有什么区别

  • 用法不同:typedef 用来定义一种数据类型的别名,增强程序的可读性。define 主要用来定义 常量,以及书写复杂使用频繁的宏。
  • 执行时间不同:typedef 是编译过程的一部分,有类型检查的功能。define 是宏定义,是预编译的部分,其发生在编译之前,只是简单的进行字符串的替换,不进行类型的检查。
  • 作用域不同:typedef 有作用域限定。define 不受作用域约束,只要是在define 声明后的引用 都是正确的。
  • 对指针的操作不同:typedef 和define 定义的指针时有很大的区别。
    注意:typed

本文标签: 面试题就够了