C++八股文(一)

🏳‍🌈C++基础

🌱1.C++特点

1. C++ C 语言基础上引入了 面对对象 的机制,同时也 兼容 C 语言
2. C++ 有三大特性 1 )封装。( 2 )继承。( 3 )多态;
3. C++ 语言编写出的程序结构清晰、易于扩充,程序 可读性好
4. C++ 生成的代码 质量高 效率高
5. C++ 更加安全,增加了 const 常量、引用、四类 cast 转换( static_cast dynamic_cast
const_cast reinterpret_cast )、智能指针、 try—catch 等等;
6. C++ 可复用性 高, C++ 引入了 模板 的概念,标准模板库 STL Standard Template Library )。

🍸2 说说C语言和C++的区别

1. C 语言是 C++ 的子集, C++ 可以很好兼容 C 语言。但是 C++ 又有很多 新特性 ,如引用、智能指针、
auto 变量等。
2. C++ 面对对象 的编程语言; C 语言是 面对过程 的编程语言。
3. C 语言有一些不安全的语言特性,如指针使用的潜在危险、强制转换的不确定性、内存泄露等。而
C++ 对此增加了不少新特性来 改善安全性 ,如 const 常量、引用、 cast 转换、智能指针、 try—catch
等等;
4. C++ 可复用性 高, C++ 引入了 模板 的概念,后面在此基础上,实现了方便开发的标准模板库 STL
C++ STL 库相对于 C 语言的函数库 更灵活、更通用

🍍3 说说 C++ struct class 的区别

1. struct 一般用于描述一个 数据结构集合 ,而 class 是对一个 对象数据的封装
2. struct 中默认的访问控制权限 public ,而 class 中默认的访问控制权限 private
3. 在继承关系中, struct 默认是 公有继承 ,而 class 私有继承
4. class 关键字可以用于定义模板参数,就像 typename ,而 struct 不能用于定义模板参数。

🍗4 include头文件的顺序以及双引号""和尖括号<>的区别

1. 区别:
1 )尖括号 <> 的头文件是 系统文件 ,双引号 "" 的头文件是 自定义文件
2 )编译器预处理阶段查找头文件的路径不一样。
2. 查找路径:
1 )使用尖括号 <> 的头文件的查找路径:编译器设置的头文件路径 --> 系统变量。
2 )使用双引号 "" 的头文件的查找路径:当前头文件目录 --> 编译器设置的头文件路径 --> 系统变
量。

🍦5 说说C++结构体和C结构体的区别

区别:
1 C 的结构体内 不允许有函数存在 C++ 允许有内部成员函数,且允许该函数是虚函数
2 C 的结构体对内部成员变量的 访问权限只能是 public ,而 C++ 允许 public,protected,private 三种
3 C 语言的结构体是 不可以继承的 C++ 的结构体 可继承
4 C 使用结构体需要加上 struct 关键字 ,而 C++ 中可以省略 struct 关键字直接使用。
1. C++ 中的 struct 是对 C 中的 struct 进行了扩充,它们在声明时的区别如下:

🌸6 导入C函数的关键字是什么,C++编译时和C有什么不同?

1. 关键字: C++ 中,导入 C 函数的关键字是 extern ,表达形式为 extern “C” extern "C" 的主要作 用就是为了能够正确实现C++ 代码调用其他 C 语言代码。加上 extern "C" 后,会指示编译器这部分代 码按C 语言 的进行编译,而不是 C++ 的。
2. 编译区别: 由于 C++ 支持函数重载,因此编译器编译函数的过程中会将函数的 参数类型 也加到编译 后的代码中,而不仅仅是函数名 ;而 C 语言并不支持函数重载,因此编译 C 语言代码的函数时不会带 上函数的参数类型,一般只包括函数名

🥩7 C++从代码到可执行二进制文件的过程

C++ C 语言类似,一个 C++ 程序从源码到执行文件,有四个过程, 预编译、编译、汇编、链接
预编译: 这个过程主要的处理操作如下:
将所有的 #define 删除,并且展开所有的宏定义
处理所有的条件预编译指令,如 #if #ifdef
处理 #include 预编译指令,将被包含的文件插入到该预编译指令的位置。
过滤所有的注释
添加行号和文件名标识。
编译: 这个过程主要的处理操作如下:
词法分析:将源代码的字符序列分割成一系列的记号。
语法分析:对记号进行语法分析,产生语法树。
语义分析:判断表达式是否有意义。
代码优化。
目标代码生成:生成汇编代码。
目标代码优化。
汇编: 这个过程主要是将汇编代码转变成机器可以执行的指令。
链接: 将不同的源文件产生的目标文件进行链接,从而形成一个可以执行的程序。
链接分为 静态链接和动态链接
静态链接 ,是在链接的时候就已经把要调用的函数或者过程链接到了生成的可执行文件中,就算你在去 把静态库删除也不会影响可执行程序的执行;生成的静态链接库,Windows 下以 .lib 为后缀, Linux 下 以 .a 为后缀。
动态链接 ,是在链接的时候没有把调用的函数代码链接进去,而是在执行的过程中,再去找要链接的函 数,生成的可执行文件中没有函数代码,只包含函数的重定位信息,所以当你删除动态库时,可执行程 序就不能运行。生成的动态链接库,Windows 下以 .dll 为后缀, Linux 下以 .so 为后缀。

⏱8 说说 static关键字的作用

1. 定义全局静态变量和局部静态变量 :初始化的静态变量会在数据段分配内存,未初始化的静态变量 会在BSS 段分配内存。直到程序结束,静态变量始终会维持前值。
2. 定义静态函数 :静态函数只能在 本源文件 中使用;如 static void func() ;
3. 定义静态变量 静态变量只能在本源文件中使用
4. 定义 类中的静态成员变量 :使用静态数据成员,它既可以被当成全局变量那样去存储,但又被隐藏 在类的内部。类中的static 静态数据成员拥有一块单独的存储区,而不管创建了多少个该类的对 象。所有这些对象的静态数据成员都共享 这一块静态存储空间。
5. 定义类中的静态成员函数 :如静态成员函数也是类的一部分,而不是对象的一部分。所有这些对象 的静态数据成员都共享 这一块静态存储空间。
此外:
当调用一个对象的非静态成员函数时,系统会把该对象的起始地址赋给成员函数的 this 指针。而 静态成 员函数不属于任何一个对象,因此 C++ 规定静态成员函数没有 this 指针 。既然它没有指向某一对象,也 就无法对一个对象中的非静态成员进行访问。

🍝9 数组和指针的区别

1. 概念:
1 )数组:数组是用于 储存多个相同类型数据的集合 数组名是首元素的地址。
2 )指针:指针相当于一个 变量 ,它存放的是其它变量在 内存中的地址 。 指针名指向了内存的首地址。
2. 区别:
1 赋值 :同类型指针变量可以相互赋值;数组不行,只能一个一个元素的赋值或拷贝
2 存储方式
数组:数组在内存中是 连续存放的 ,数组的存储空间,不是在静态区就是在栈上。
指针:指针很灵活,它可以指向任意类型的数据。指针的类型说明了它所指向地址空间的内存。由于指针本身就是一个变量,再加上它所存放的也是变量,所以指针的存储空间不能确定。
3 sizeof : 数组所占存储空间的内存大小:sizeof (数组名) /sizeof (数据类型)
32 位平台下,无论指针的类型是什么, sizeof (指针名)都是 4 ,在 64 位平台下,无论指针的类型是什么,sizeof (指针名)都是 8

🧀10 说说什么是函数指针,如何定义函数指针,有什么使用场景

1. 概念: 函数指针就是 指向函数 的指针变量。每一个函数都有一个入口地址,该入口地址就是函数指 针所指向的地址。
2. 定义 形式如下:
int func(int a);
int (*f)(int a);
f = &func;
1. 函数指针的 应用场景 回调 callback )。我们调用别人提供的 API 函数 (Application
Programming Interface, 应用程序编程接口 ) ,称为 Call ;如果别人的库里面调用我们的函数,就叫 Callback。

🍊11 静态变量什么时候初始化?

对于 C 语言的全局和静态变量, 初始化发生在任何代码执行之前 ,属于编译期初始化。
C++ 标准规定:全局或静态对象当且仅当对象 首次用到时才进行构造

🥕12 nullptr调用成员函数可以吗?为什么?

能。
原因:因为在 编译时对象 就绑定了 函数地址 ,和指针空不空没关系。

🎀13 说说什么是野指针,怎么产生的,如何避免

1. 概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
2. 产生原因 :释放内存后指针不及时置空(野指针),依然指向了该内存,那么可能出现非法访问的 错误。这些我们都要注意避免。
3. 避免办法:
1 )初始化置 NULL
2 )申请内存后判空
3 )指针释放后置 NULL
4 )使用智能指针auto

🍒14 说说静态局部变量,全局变量,局部变量的特点,以及使用场景

1. 首先从作用域考虑 C++ 里作用域可分为 6 种:全局,局部,类,语句,命名空间和文件作用域。
全局变量:全局作用域,可以通过 extern 作用于其他非定义的源文件。
静态全局变量 :全局作用域 + 文件作用域,所以无法在其他文件中使用。
局部变量:局部作用域,比如函数的参数,函数内的局部变量等等。
静态局部变量 :局部作用域,只被初始化一次,直到程序结束。
2. 从所在空间考虑 :除了局部变量在栈上外,其他都在静态存储区。因为静态变量都在静态存储区,
所以下次调用函数的时候还是能取到原来的值。
3. 生命周期 : 局部变量在栈上,出了作用域就回收内存;而全局变量、静态全局变量、静态局部变量
都在静态存储区,直到程序结束才会回收内存。

🌹15 说说内联函数和宏函数的区别

区别:
1. 宏定义不是函数 ,但是使用起来像函数。预处理器用复制宏代码的方式代替函数的调用,省去了函 数压栈退栈过程,提高了效率;而内联函数本质上是一个函数 ,内联函数一般用于函数体的代码比 较简单的函数,不能包含复杂的控制语句,while switch ,并且内联函数本身不能直接调用自身。
2. 宏函数 是在预编译的时候把所有的宏名用宏体来替换,简单的说就是字符串替换 ; 而内联函数 则是 在编译的时候进行代码插入,编译器会在每处调用内联函数的地方直接把内联函数的内容展开,这 样可以省去函数的调用的开销,提高效率。
3. 宏定义 没有类型检查的 ,无论对还是错都是直接替换; 而内联函数(inline) 在编译的时候会进行类型的检查,内联函数满足函数的性质,比如有返回值、参数列表等。
内联函数使用的条件: 内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果 执行函数体内代码的时间,相比于函数调用的开销较大,那么效率 的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜 使用内联:
1 )如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
2 )如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
内联不是什么时候都能展开的,一个好的编译器将会根据函数的定义体,自动地取消不符合要求的内联。

⭐17 说说newmalloc的区别,各自底层实现原理。

1. new 是操作符,而 malloc 是函数。
2. new 在调用的时候 先分配内存,再调用构造函数,释放的时候调用析构函数 ;而 malloc 没有构造函 数和析构函数。
3. malloc 需要给定申请内存的大小, 返回的指针需要强转; new 会调用构造函数,不用指定内存的大 小,返回指针不用强转。
4. new 可以被重载 malloc 不行
5. new 分配内存更直接和安全
6. new 发生错误抛出异常 malloc 返回 null
malloc 底层实现: 当开辟的空间小于 128K 时,调用 brk ()函数;当开辟的空间大于 128K 时,调用 mmap()。 malloc 采用的是内存池的管理方式,以减少内存碎片。先申请大块内存作为堆区,然后将 堆区分为多个内存块。当用户申请内存时,直接从堆区分配一块合适的空闲快。采用隐式链表将所有空 闲块,每一个空闲块记录了一个未分配的、连续的内存地址。
new 底层实现: 关键字 new 在调用构造函数的时候实际上进行了如下的几个步骤:
1. 创建一个新的对象
2. 将构造函数的作用域赋值给这个新的对象(因此 this 指向了这个新的对象)
3. 执行构造函数中的代码(为这个新对象添加属性)
4. 返回新对象

🍥18 说说constdefine的区别。

const 用于定义 常量 ;而 define 用于 定义宏 ,而宏也可以用于定义常量。都用于常量定义时,它们的区别
有:
1. const 生效于编译的阶段; define 生效于预处理阶段。
2. const 定义的常量,在 C 语言中 是存储在内存中、需要额外的内存空间的 define 定义的常量,运行 时 是直接的操作数,并不会存放在内存中
3. const 定义的常量 是带类型的 define 定义的常量 不带类型 。因此 define 定义的常量不利于类型检查。

🥝19 说说C++中函数指针和指针函数的区别。

参考回答
1. 定义不同
指针函数本质是一个函数,其返回值为指针。
函数指针本质是一个指针,其指向一个函数。
2. 写法不同
指针函数:int *fun(int x,int y);
函数指针:int (*fun)(int x,int y);
3. 用法不同
  • 指针函数:主要用于返回一个地址值,这个地址值可以是动态分配的内存、静态变量的地址或指针形参所指向的实参地址。
  • 函数指针:主要用于通过指针调用函数,使得函数的调用更加灵活,可以实现回调函数等高级功能。

🍹20 说说const int *a, int const *a, const int a, int *const a, const int *const a分别是什么,有什么特点。

详解:👉const有关解析

1. const int a; //指的是a是一个常量,不允许修改。
2. const int *a; //a指针所指向的内存里的值不变,即(*a)不变
3. int const *a; //同const int *a;
4. int *const a; //a指针所指向的内存地址不变,即a不变
5. const int *const a; //都不变,即(*a)不变,a也不变

🍻21 说说使用指针需要注意什么?

1. 定义指针时,先初始化为 NULL
2. malloc new 申请内存之后,应该 立即检查 指针值是否为 NULL 。防止使用指针值为 NULL 的内存。
3. 不要忘记为数组和动态内存 赋初值 。防止将未被初始化的内存作为右值使用。
4. 避免数字或指针的下标 越界 ,特别要当心发生 1” 或者 1” 操作
5. 动态内存的申请与释放必须配对,防止 内存泄漏
6. free delete 释放了内存之后,立即将指针 设置为 NULL ,防止 野指针

🥗22 说说内联函数和函数的区别,内联函数的作用。

1. 内联函数比普通函数多了关键字 inline
2. 内联函数避免了函数调用的 开销 ;普通函数有调用的开销
3. 普通函数在被调用的时候,需要 寻址(函数入口地址) ;内联函数不需要寻址。
4. 内联函数有一定的限制,内联函数体要求 代码简单 ,不能包含复杂的结构控制语句;普通函数没有 这个要求。
内联函数的作用 :内联函数在调用时,是将调用表达式用内联函数体来替换。避免函数调用的开销。

🍨23 简述C++有几种传值方式,之间的区别是什么?

参考回答
传参方式有这三种: 值传递、引用传递、指针传递
1. 值传递:形参即使在函数体内值发生变化,也不会影响实参的值;
2. 引用传递:形参在函数体内值发生变化,会影响实参的值;
3. 指针传递:在指针指向没有发生改变的前提下,形参在函数体内值发生变化,会影响实参的值;
值传递用于对象时,整个对象会拷贝一个副本,这样效率低;而引用传递用于对象时,不发生拷贝行为,只是绑定对象,更高效;指针传递同理,但不如引用传递安全。

🎄24 简述const(星号)和(星号)const的区别


//const* 是指针常量,*const 是常量指针
int const *a; //a指针所指向的内存里的值不变,即(*a)不变,指针可变
int *const a; //a指针所指向的内存地址不变,即a不变,其所指内存值可变。

🌻25.malloc,free和new,delete的区别

a.new自动计算所需要的内存大小,malloc需要手动计算,
如:

int *ptr=new int[10];
delete [] ptr;

int * ptr=(int*)malloc(sizeof(int)*10);
free ptr;

b.new返回的是对象类型的指针,malloc返回的是void*,需要之后进行强制类型转换

c.new分配失败会抛出异常,malloc分配失败返回的是null

d.new是free store上分配内存,malloc是堆上分配的

e.malloc,free是c语言的库函数,new,delete是c++的运算符,运算符可以重载,库函数不行。

f.malloc只能分配内存,new可以分配内存也可以构造对象;delete能释放内存以及调用析构函数,free只能释放内存。

g.如果内存分配不够,malloc还能用realloc重新分配内存,new没有这个功能

1)malloc调用后是否立即得到物理内存

先分配虚内存,再映射物理内存

2)free(p)怎么知道释放多大空间

因为malloc的时候用16个字节的头部来存储了指针类型信息,以及开辟空间大小

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值