十八万字吐血整理的C/C++、嵌入式常见面试题!!!!

欢迎订阅,希望能点个赞!!!!

正在持续更新!!!!!欢迎探讨!!!

完整专栏地址:https://blog.nowcoder.net/zhuanlan/gmPWX0


相关知识点都能零星在网上找到,这个文章系列将目前遇到的所有常见面试问题进行一个汇总。

文中很多资料避免不了从网上或是其他复习资料里收集整理,十分感谢前辈的辛勤付出,如果存在侵权请一定联系我进行删除

也有相当一部分是本人在经历提前批以及秋招的过程中遇到和验证过的。


系列文章PDF下载地址:《最全C_C++及嵌入式软开面试题宝典.pdf》



121、怎样判断两个浮点数是否相等?

对两个浮点数判断大小和是否相等不能直接用==来判断,会出错!明明相等的两个数比较反而是不相等!对于两个浮点数比较只能通过相减并与预先设定的精度比较,记得要取绝对值!浮点数与0的比较也应该注意。与浮点数的表示方式有关。

const float EPSINON = 0.00001;

if (((a-b) >= - EPSINON) && ((a-b) <= EPSINON);

122、宏定义一个取两个数中较大值的功能

#define MAXx,y((x>y?)x:y)

123、defineconsttypedefinline使用方法?

一、const#define的区别:

1.const定义的常量是变量带类型,而#define定义的只是个常数不带类型;

2.define只在预处理阶段起作用,简单的文本替换,而const在编译、链接过程中起作用;

3.define只是简单的字符串替换没有类型检查。而const是有数据类型的,是要进行判断的,可以避免一些低级错误;

4.define预处理后,占用代码段空间,const占用数据段空间;

5.const不能重定义,而define可以通过#undef取消某个符号的定义,进行重定义;

6.define独特功能,比如可以用来防止文件重复引用。

二、#define和别名typedef的区别

1.执行时间不同,typedef在编译阶段有效,typedef有类型检查的功能;#define是宏定义,发生在预处理阶段,不进行类型检查;

2.功能差异,typedef用来定义类型的别名,定义与平台无关的数据类型,与struct的结合使用等。#define不只是可以为类型取别名,还可以定义常量、变量、编译开关等。

3.作用域不同,#define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用。而typedef有自己的作用域。

三、defineinline的区别

1.#define是关键字,inline是函数;

2.宏定义在预处理阶段进行文本替换,inline函数在编译阶段进行替换;

3.inline函数有类型检查,相比宏定义比较安全;

124、printf实现原理?

1.C/C++中,对函数参数的扫描是从后向前的。C/C++的函数参数是通过压入堆栈的方式来给函数传参数的(堆栈是一种先进后出的数据结构),最先压入的参数最后出来,在计算机的内存中,数据有2块,一块是堆,一块是栈(函数参数及局部变量在这里),而栈是从内存的高地址向低地址生长的,控制生长的就是堆栈指针了,最先压入的参数是在高地址,最后压入的参数在低地址,结构上看起来是第一个,所以最后压入的参数总是能够被函数找到,因为它就在堆栈指针的上方。

2.printf的第一个被找到的参数就是那个字符指针,就是被双引号括起来的那一部分,函数通过判断字符串里控制参数的个数来判断参数个数及数据类型,通过这些就可算出数据需要的堆栈指针的偏移量了,下面给出printf("%d,%d",a,b);(其中ab都是int型的)的汇编代码.

125、#include 的顺序以及尖括号和双引号的区别

1.<> 尖括号表示编译器只在系统默认目录或尖括号内的工作目录下搜索头文件,并不去用户的工作目录下寻找,所以一般尖括号用于包含标准库文件;

2." " 双引号表示编译器先在用户的工作目录下搜索头文件,如果搜索不到则到系统默认目录下去寻找,所以双引号一般用于包含用户自己编写的头文件。

126、lambda函数

1.定义

利用lambda表达式可以编写内嵌的匿名函数,用以替换独立函数或者函数对象;每当你定义一个lambda表达式后,编译器会自动生成一个匿名类(这个类当然重载了()运算符),我们称为闭包类型(closure type)。那么在运行时,这个lambda表达式就会返回一个匿名的闭包实例,其实一个右值。可以通过传值或者引用的方式捕捉其封装作用域内的变量,前面的方括号就是用来定义捕捉模式以及变量,我们又将其称为lambda捕捉块。

2.用法

lambda表达式的语法定义如下:

[capture list] (params list) mutable exception-> return type { function body }

各项具体含义如下:

capture list:捕获外部变量列表

params list:形参列表

mutable指示符:用来说用是否可以修改捕获的变量

exception:异常设定

return type:返回类型

function body:函数体

3.lamda的几种捕获方式

捕获形式

说明

[]

不捕获任何外部变量

[变量名, …]

默认以值得形式捕获指定的多个外部变量(用逗号分隔),如果引用捕获,需要显示声明(使用&说明符)

[this]

以值的形式捕获this指针

[=]

以值的形式捕获所有外部变量

[&]

以引用形式捕获所有外部变量

[=, &x]

变量x以引用形式捕获,其余变量以传值形式捕获

[&, x]

变量x以值的形式捕获,其余变量以引用形式捕获

4.lambda必须使用尾置返回来指定返回类型,可以忽略参数列表和返回值,但必须永远包含捕获列表和函数体;

127、模板类和模板函数的区别是什么?

函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由程序员在程序中显式地指定。即函数模板允许隐式调用和显式调用而类模板只能显示调用。在使用时类模板必须加<T>,而函数模板不必。

128、为什么模板类一般都是放在一个h文件中

1.模板定义很特殊。由template<…>处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。

2.在分离式编译的环境下,编译器编译某一个.cpp文件时并不知道另一个.cpp文件的存在,也不会去查找(当遇到未决符号时它会寄希望于连接器)。这种模式在没有模板的情况下运行良好,但遇到模板时就傻眼了,因为模板仅在需要的时候才会实例化出来,所以,当编译器只看到模板的声明时,它不能实例化该模板,只能创建一个具有外部连接的符号并期待连接器能够将符号的地址决议出来。然而当实现该模板的.cpp文件中没有用到模板的实例时,编译器懒得去实例化,所以,整个工程的.obj中就找不到一行模板实例的二进制代码,于是连接器也黔驴技穷了。

129、C++中类成员的访问权限和继承权限问题。

一、三种访问权限

  • public:用该关键字修饰的成员表示公有成员,该成员不仅可以在类内可以被  访问,在类外也是可以被访问的,是类对外提供的可访问接口;
  • private:用该关键字修饰的成员表示私有成员,该成员仅在类内可以被访问,在类体外是隐藏状态;
  • protected:用该关键字修饰的成员表示保护成员,保护成员在类体外同样是隐藏状态,但是对于该类的派生类来说,相当于公有成员,在派生类中可以被访问。

二、三种继承方式

  • 若继承方式是public,基类成员在派生类中的访问权限保持不变,也就是说,基类中的成员访问权限,在派生类中仍然保持原来的访问权限;
  • 若继承方式是private,基类所有成员在派生类中的访问权限都会变为私有(private)权限;
  • 若继承方式是protected,基类的共有成员和保护成员在派生类中的访问权限都会变为保护(protected)权限,私有成员在派生类中的访问权限仍然是私有(private)权限。

130、coutprintf有什么区别?

cout<<是一个函数,cout<<后可以跟不同的类型是因为cout<<已存在针对各种类型数据的重载,所以会自动识别数据的类型。输出过程会首先将输出字符放入缓冲区,然后输出到屏幕。

cout是有缓冲输出:cout << "abc " <<endl;或cout << "abc\n ";cout < <flush; 这两个才是一样的。endl相当于输出回车后,再强迫缓冲输出。flush立即强迫缓冲输出。printf是无缓冲输出。有输出时立即输出(lsy注:在嵌入式里尽量不用用printf打印信息,耗时!)