Jianghc's Blog

Back

写在前面的#

主要内容转自思佳同学的博客,后续可能有些自己的补充,如果有新的心得我会更新上去。算法部分的其他知识可以多看看柯大佬的博客

Q1: malloc/free 和 new/delete 的区别#

相同点:都用来申请/释放动态内存#

不同点:#

  1. malloc 与 free 是 C 的标准库函数,new/delete 是 C++的运算符
  2. new/delete 除了分配/释放内存,还会执行构造函数/析构函数 对于非内部数据类的对象而言,光用 maloc/free 无法满足动态对象的要求。对象在创建的 同时要自动执行构造函数,对象消亡之前要自动执行析构函数。由于 malloc/free 是库函数 而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加 malloc/free。
  3. malloc 需要指定所申请内存的长度,而 new 可以自动计算长度
  4. 返回值类型不一样,malloc 返回的是 void 指针,new 返回的是目标类型的指针

Q2: delete 与 delete [] 的区别#

  1. delete 只会调用一次析构函数,而 delete[]会调用每一个成员的析构函数
  2. delete 与 new 配套,delete [] 与 new [] 配套

Q3: 指针与引用的区别#

指针与引用都是让你间接引用其他对象,一个引用必须指向某个对象,不能指向空值。指针可以;指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定 的对象,以后不能改变。

相同点:#

  1. 都是地址的概念; 指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名

不同点:#

  1. 指针是一个实体,而引用仅是个别名
  2. 引用使用时无需解引用*,指针需要解引用
  3. 引用只能在定义时被初始化一次,之后不可变;指针可变
  4. 引用没有 const,指针有 const,const 的指针不可变
  5. 引用不能为空,指针可以为空
  6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针 本身(所指向的变量或对象的地址)的大小 typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,但是当引用作 为成员时,其占用空间与指针相同(没找到标准的规定)
  7. 指针和引用的自增(++)运算意义不一样

Q4: extern “C” 是什么#

C++ 支持函数重载,而过程式语言C则不支持。函数被 C++编译后在 symbol 库中的名字与 C 语言的不同。例如,假设某个函数的原型为: void foo(int x, int y); 该函数被 C 编译器编译后在 symbol 库中的名字为_foo,而 C++编译器则会产生像_foo_int_int之类的名字。foo_int_int这样的名字包含了函数名和函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。 为了实现C和C++的混合编程,C++提供了C连接交换指定符号extern “C”来解决名字匹配问题,函数声明前加上 extern “C”后,则编译器就会按照 C 语言的方式将该函数编译为_foo, 这样C语言中就可以调用C++的函数了。

Q5: 内存的分配方式有哪些#

  1. 静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行 期间都存在。例如全局变量,static 变量
  2. 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行 结束时这些存储单元自动被释放
  3. 从堆上分配,亦称动态内存分配。程序在运行的时候用 malloc 或 new 申请任意多少的 内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定, 使用非常灵活

Q6: 数组与指针的区别与联系#

  1. 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任 意类型的内存块
  2. 用运算符 sizeof 可以计算出数组的容量(字节数) ,而指针不可以
  3. 当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针

Q7: 介绍一下智能指针(这个我也考到过)#

智能指针就是 “类指针对象”,体现了以对象管理资源的思想。 如果用裸指针的话,每个 new 都应与 delete 配对使用,此时如果使用 new 的函数由于引发异常而提前结束,将导致内存泄漏。 c++11 提供的智能指针 unique_ptr、shared_ptr 提供了以对象管理资源的解决方案。 shared_ptr: 引用计数型的智能指针,持续追踪共有多少对象指向某笔资源,在无人指向它时自动删除该资源。 shared_ptr 无法解决环状引用问题,例如两个其实已经没有被使用的对象彼此互指,则两个 对象都无法析构,产生了内存泄漏,解决方法是把任意一个成员变量设置为 weak_ptr。

Q8: 介绍一下 c++ 中的各种 cast#

  1. static_cast 内置类型的隐式类型转换、父类子类之间的转换(不加检查) 进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
  2. dynamic_cast 父类子类之间的转换(加检查)、所有非法转换都返回空指针 dynamic_cast 主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换(使 用 dynamic_cast 的转换则是允许的,结果是空指针)。 在进行上行转换时,dynamic_cast 和 static_cast 的效果是一样的; 在进行下行转换时,dynamic_cast 具有类型检查的功能,比 static_cast 更安全。如果 downcast 是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算 符会传回适当转型过的指针。如果 downcast 不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)

运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表,只有定义了虚函数 的类才有虚函数表,没有定义虚函数的类是没有虚函数表的。

Q9: 多态有几种类型?虚函数实现多态的原理是什么?(这个我也考到过)#

  1. 静态多态(也就是泛型,以模板技术实现)
  2. 函数多态(也就是重载,基于不同的函数参数列表,相同名称的函数可以指向不同的函 数定义)
  3. 宏多态(也就是带变量的宏)
  4. 动态多态(基于继承机制与虚函数)

首先明确一个概念,为什么要有多态,多态主要应用于函数重载和继承当中,派生类通过继承基类的相关函数,通过虚函数的方式重载基类的函数,这样使得程序大为灵活。虚函数实现的多态为动态多态,这里的“动态”指的是多态行为发生在运行期,而不是编译期。实现原理如下:每一个含有虚函数的类都至少有一个与之对应的虚函数表,其中存放着该类所有的虚函数对应的函数指针。有虚函数的类内部有一个称为“虚表”的指针,指向该表。在编译器,无法获得具体的类型是什么。但是能够获得其调用函数的虚函数表,和在表中的偏移量。在运行时,能够获得具体的类型,获得其虚函数表指针,然后指针加上偏移量,就能够获得对应的函数。

C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。(一个接口,多个行为) 虚函数的用法:可以让派生类重写基类的成员函数实现多态。虚函数实现多态的机制,严格来说是动态多态,是在出现运行的时候实现的。 每个虚函数都会有一个与之对应的虚函数表,该虚函数表的实质是一个指针数组,存放的是每一个对象的虚函数入口地址。对于一个派生类来说,他会继承基类的虚函数表同时增加自己的虚函数入口地址,如果派生类重写了基类的虚函数的话,那么继承过来的虚函数入口地址将被派生类的重写虚函数入口地址替代。那么在程序运行时会发生动态绑定,将父类指针绑定到实例化的对象实现多态

Q10: 怎么判断一个链表有没有环,链表和数组的差别是什么#

一个快指针(每次走2)一个慢指针(每次走1),看会不会相遇,链表是链式的存储结构,数组是顺序的存储结构,链表通过指针来连接元素。数组是按顺序将元素一次存储。链表插入和删除很快。链表不支持随机访问。

Q11: list,vector,map,set的区别#

  1. List(双向链表)封装了链表,Vector封装了数组, list和vector得最主要的区别在于vector使用连续内存存储的,他支持[]运算符,而list是以链表形式实现的,不支持[]。List可以进行高效的插入和删除。
  2. Vector对于随机访问(直接访问节点,因为是顺序存储)的速度很快,但是对于插入尤其是在头部插入元素速度很慢,在尾部插入速度很快。List对于随机访问速度慢得多(存储空间不连续),因为可能要遍历整个链表才能做到,但是对于插入就快的多了,不需要拷贝和移动数据,只需要改变指针的指向就可以了。另外对于新添加的元素,Vector有一套算法,而List可以任意加入。
  3. Map,Set属于标准关联容器,使用了非常高效的平衡检索二叉树:红黑树,他的插入删除效率比其他序列容器高是因为不需要做内存拷贝和内存移动,而直接替换指向节点的指针即可。
  4. Set和Vector的区别在于Set不包含重复的数据。Set和Map的区别在于Set只含有Key,而Map有一个Key和Key所对应的Value两个元素。
  5. Map和Hash_Map的区别是Hash_Map使用了Hash算法来加快查找过程,但是需要更多的内存来存放这些Hash桶元素,因此可以算得上是采用空间来换取时间策略。
c++常见面试题总结
https://525511.xyz/blog/c-%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98%E6%80%BB%E7%BB%93
Author Haochen Jiang
Published at August 25, 2019
Comment seems to stuck. Try to refresh?✨