目录

1、 编码实现某一变量某位清0或置1

2、 分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。

3、 局部变量全局变量的问题?

4、 数组和指针的区别?

5、 C++如何阻止一个类被实例化?一般在什么时候将构造函数声明为private?

6、 如何禁止自动生成拷贝构造函数?

7、 assert与NDEBUGE

8、 Debug和release的区别

9、 main函数有没有返回值

10、 写一个比较大小的模板函数

11、 c++怎么实现一个函数先于main函数运行

12、 成员函数里memset(this,0,sizeof(*this))会发生什么

13、 方法调用的原理(栈,汇编)

14、 MFC消息处理如何封装的?

15、 函数指针

16、 回调函数的作用

17、 随机数的生成

18、 for(;;)和while(true)的区别

19、 数据结构中的常见树结构

20、 什么是平衡二叉树


1、 编码实现某一变量某位清0或置1

#define BIT3 (0x1 << 3 ) Satic int a;
//设置a的bit 3:
void set_bit3( void )
{a |= BIT3; //将a第3位置1
}//清a的bit 3
void set_bit3( void )
{a &= ~BIT3; //将a第3位清零
}

2、 分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。

BOOL : if ( !a ) or if(a)
int : if ( a == 0)
float : const EXPRESSION EXP = 0.000001
if ( a < EXP && a >-EXP)
pointer : if ( a != NULL) or if(a == NULL)

无论是float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。

3、 局部变量全局变量的问题?

1.局部会屏蔽全局。要用全局变量,需要使用"::"局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。

2.如何引用一个已经定义过的全局变量,可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。

3.全局变量可不可以定义在可被多个.C文件包含的头文件中,在不同的C文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错。

4、 数组和指针的区别?

1、数组在内存中是连续存放的,开辟一块连续的内存空间;数组所占存储空间:sizeof(数组名);数组大小:sizeof(数组名)/sizeof(数组元素数据类型);

2、用运算符sizeof 可以计算出数组的容量(字节数)。sizeof(p),p 为指针得到的是一个指针变量的字节数,而不是p所指的内存容量。

3、编译器为了简化对数组的支持,实际上是利用指针实现了对数组的支持。具体来说,就是将表达式中的数组元素引用转换为指针加偏移量的引用。

4、在向函数传递参数的时候,如果实参是一个数组,那用于接受的形参为对应的指针。也就是传递过去是数组的首地址而不是整个数组,能够提高效率;

5、在使用下标的时候,两者的用法相同,都是原地址加上下标值,不过数组的原地址就是数组首元素的地址是固定的,指针的原地址就不是固定的。

5、 C++如何阻止一个类被实例化?一般在什么时候将构造函数声明为private?

1、将类定义为抽象基类或者将构造函数声明为private;(lsy注:考虑下单例模式的实现)

2、不允许类外部创建类对象,只能在类内部创建对象

6、 如何禁止自动生成拷贝构造函数?

1.为了阻止编译器默认生成拷贝构造函数和拷贝赋值函数,我们需要手动去重写这两个函数,某些情况下,为了避免调用拷贝构造函数和拷贝赋值函数,我们需要将他们设置成private,防止被调用。

2.类的成员函数和friend函数还是可以调用private函数,如果这个private函数只声明不定义,则会产生一个连接错误;

3.针对上述两种情况,我们可以定一个base类,在base类中将拷贝构造函数和拷贝赋值函数设置成private,那么派生类中编译器将不会自动生成这两个函数,且由于base类中该函数是私有的,因此,派生类将阻止编译器执行相关的操作。

7、 assert与NDEBUGE

1.assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:

#include <assert.h>
void assert( int expression );

assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。如果表达式为真,assert什么也不做。

2.NDEBUG宏是Standard C中定义的宏,专门用来控制assert()的行为。如果定义了这个宏,则assert不会起作用。定义NDEBUG能避免检查各种条件所需的运行时开销,当然此时根本就不会执行运行时检查。

3.C Standard中规定了assert以宏来实现。<assert.h>被设计来可以被多次包含,其中一上来就undef assert,然后由NDEBUG宏来决定其行为。

8、 Debug和release的区别

1.调试版本,包含调试信息,所以容量比Release大很多,并且不进行任何优化(优化会使调试复杂化,因为源代码和生成的指令间关系会更复杂),便于程序员调试。Debug模式下生成两个文件,除了.exe或.dll文件外,还有一个.pdb文件,该文件记录了代码中断点等调试信息;

2.发布版本,不对源代码进行调试,编译时对应用程序的速度进行优化,使得程序在代码大小和运行速度上都是最优的。(调试信息可在单独的PDB文件中生成)。Release模式下生成一个文件.exe或.dll文件。

3.实际上,Debug 和 Release 并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。事实上,我们甚至可以修改这些选项,从而得到优化过的调试版本或是带跟踪语句的发布版本。

9、 main函数有没有返回值

1.程序运行过程入口点main函数,main()函数返回值类型必须是int,这样返回值才能传递给程序激活者(如操作系统)表示程序正常退出。main(int args, char **argv) 参数的传递。参数的处理,一般会调用getopt()函数处理,但实践中,这仅仅是一部分,不会经常用到的技能点。

10、 写一个比较大小的模板函数

#include<iostream>
using namespace std;
template<typename type1,typename type2>//函数模板
type1 Max(type1 a,type2 b)
{
return a > b ? a : b;
}
void main()
{
cout<<"Max = "<<Max(5.5,'a')<<endl;
}

11、 c++怎么实现一个函数先于main函数运行

1.如果在main函数之前声明一个类的全局的对象。那么其执行顺序,根据全局对象的生存期和作用域,肯定先于main函数。

class simpleClass {public:simpleClass( );{ cout << "simpleClass constructor.." << endl;         }};simpleClass g_objectSimple;         //step1全局对象 int _tmain(int argc, _TCHAR* argv[])  //step3 { return 0; }

2.定义在main( )函数之前的全局对象、静态对象的构造函数在main( )函数之前执行。

3.main函数执行之前,主要就是初始化系统相关资源;

1设置栈指针

2初始化static静态和global全局变量,即data段的内容

3将未初始化部分的全局变量赋初值:数值型short,int,long等为0,bool为FALSE,指针为NULL,等等,即.bss段的内容

4全局对象初始化,在main之前调用构造函数

5将main函数的参数,argc,argv等传递给main函数,然后才真正运行main函数

4.main函数执行之后

1全局对象的析构函数会在main函数之后执行;

2可以用_onexit 注册一个函数,它会在main 之后执行;

12、 成员函数里memset(this,0,sizeof(*this))会发生什么

1.有时候类里面定义了很多int,char,struct等c语言里的那些类型的变量,我习惯在构造函数中将它们初始化为0,但是一句句的写太麻烦,所以直接就memset(this, 0, sizeof *this);将整个对象的内存全部置为0。对于这种情形可以很好的工作,但是下面几种情形是不可以这么使用的;

2.类含有虚函数表:这么做会破坏虚函数表,后续对虚函数的调用都将出现异常;

3.类中含有C++类型的对象:例如,类中定义了一个list的对象,由于在构造函数体的代码执行之前就对list对象完成了初始化,假设list在它的构造函数里分配了内存,那么我们这么一做就破坏了list对象的内存。

13、 方法调用的原理(栈,汇编)

1.机器用栈来传递过程参数、存储返回信息、保存寄存器用于以后恢复,以及本地存储。而为单个过程分配的那部分栈称为帧栈;帧栈可以认为是程序栈的一段,它有两个端点,一个标识起始地址,一个标识着结束地址,两个指针结束地址指针esp,开始地址指针ebp;

2.由一系列栈帧构成,这些栈帧对应一个过程,而且每一个栈指针+4的位置存储函数返回地址;每一个栈帧都建立在调用者的下方,当被调用者执行完毕时,这一段栈帧会被释放。由于栈帧是向地址递减的方向延伸,因此如果我们将栈指针减去一定的值,就相当于给栈帧分配了一定空间的内存。如果将栈指针加上一定的值,也就是向上移动,那么就相当于压缩了栈帧的长度,也就是说内存被释放了。

3.过程实现

1备份原来的帧指针,调整当前的栈帧指针到栈指针位置;

2建立起来的栈帧就是为被调用者准备的,当被调用者使用栈帧时,需要给临时变量分配预留内存;

3使用建立好的栈帧,比如读取和写入,一般使用mov,push以及pop指令等等。

4恢复被调用者寄存器当中的值,这一过程其实是从栈帧中将备份的值再恢复到寄存器,不过此时这些值可能已经不在栈顶了

5恢复被调用者寄存器当中的值,这一过程其实是从栈帧中将备份的值再恢复到寄存器,不过此时这些值可能已经不在栈顶了。

6释放被调用者的栈帧,释放就意味着将栈指针加大,而具体的做法一般是直接将栈指针指向帧指针,因此会采用类似下面的汇编代码处理。

7恢复调用者的栈帧,恢复其实就是调整栈帧两端,使得当前栈帧的区域又回到了原始的位置。

8弹出返回地址,跳出当前过程,继续执行调用者的代码。

4.过程调用和返回指令

1call指令

2leave指令

3ret指令

14、 MFC消息处理如何封装的?

15、 函数指针

从定义和⽤途两⽅⾯来说⼀下⾃⼰的理解:

⾸先是定义:函数指针是指向函数的指针变量。函数指针本身⾸先是⼀个指针变量,该指针变量指向⼀个具体的函数。这正如⽤指针变量可指向整型变量、字符型、数组⼀样,这⾥是指向函数。

在编译时,每⼀个函数都有⼀个⼊⼝地址,该⼊⼝地址就是函数指针所指向的地址。有了指向函数的指针变量后,可⽤该指针变量调⽤函数,就如同⽤指针变量可引⽤其他类型变量⼀样,在这些概念上是⼤体⼀致的。

其次是⽤途:调⽤函数和做函数的参数,⽐如回调函数。

示例:

char * fun(char * p) {…} // 函数fun
char * (*pf)(char * p); // 函数指针pf
pf = fun; // 函数指针pf指向函数fun,fun就是函数地址 不需要用&fun
pf(p); // 通过函数指针pf调⽤函数fun

16、 回调函数的作用

1.当发生某种事件时,系统或其他函数将会自动调用你定义的一段函数;

2.回调函数就相当于一个中断处理函数,由系统在符合你设定的条件时自动调用。为此,你需要做三件事:1,声明;2,定义;3,设置触发条件,就是在你的函数中把你的回调函数名称转化为地址作为一个参数,以便于系统调用;

3.回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数;

4.因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。

17、 随机数的生成

1.#include<time.h>  srand((unsigned)time(NULL));   cout<<(rand()%(b-a))+a;

2.由于rand()的内部实现是用线性同余法做的,所以生成的并不是真正的随机数,而是在一定范围内可看为随机的伪随机数。

3.种子写为srand(time(0))代表着获取系统时间,电脑右下角的时间,每一秒后系统时间的改变,数字序列的改变得到的数字不同,这才得带不同的数字,形成了真随机数,即使是真随机数,也是有规律可循。

lsy注:这里加一道算法题,用random7()实现random10.

18、 for(;;)和while(true)的区别

总结 for(;;) 比 while(true) 好。

1.编译前  while (1);

编译后

mov eax,1

test eax,eax

je foo+23h

jmp foo+18h

2.编译前for (;;);

编译后

jmp foo+23h

对比之下,for (;;)指令少,不占用寄存器,而且没有判断跳转,比while (1)好。也就是说两者在在宏观上完全一样的逻辑,但是底层完全不一样,for相对于来说更加简洁明了。

19、 数据结构中的常见树结构

1、⼆叉树:任何节点最多只允许有两个⼦节点,称为左⼦节点和右⼦节点,以递归的⽅式定义⼆叉树为,⼀个⼆叉树如果不为空,便是由⼀个根节点和左右两个⼦树构成,左右⼦树都可能为空。

2、⼆叉搜索树(二叉查找树):⼆叉搜索树可以提供对数时间的元素插⼊和访问。节点的放置规则是:任何节点的键值⼀定⼤于其左⼦树的每⼀个节点的键值,并⼩于其右⼦树中的每⼀个节点的键值。因此⼀直向左⾛可以取得最⼩值,⼀直向右⾛可以得到最⼤值。插⼊:从根节点开始,遇键值较⼤则向左,遇键值较⼩则向右,直到尾端,即插⼊点。删除:如果删除点只有⼀个⼦节点,则直接将其⼦节点连⾄⽗节点。如果删除点有两个⼦节点,以右⼦树中的最⼩值代替要删除的位置。

3、平衡⼆叉树:其实对于树的平衡与否没有⼀个绝对的标准, “平衡”的⼤致意 思是:没有任何⼀个节点过深,不同的平衡条件会造就出不同的效率表现。以及不同的实现复杂度。

4、AVL树:高度平衡的平衡⼆叉树(严格的平衡⼆叉树),AVL-tree 是要求任何节点的左右⼦树⾼度相差最多为 1 的平衡⼆叉树。 当插⼊新的节点破坏平衡性的时候,从下往上找到第⼀个不平衡点,需要进⾏单旋转,或者双旋转进⾏调整。

5、红黑树:红黑树就是一种平衡二叉树,说它平衡的意思是它不会出现左子树与右子树的高度之差不会大于1,左子树和右子树保持一种平衡的关系。

6、B树、B+树

20、 什么是平衡二叉树

1.平衡二叉树的性质

在平衡二叉树树中,任一节点对应的两棵子树的最大高度差为1,因此它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下的时间复杂度都是O(log n)。

1可以是空树。

2假如不是空树,任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过1。

2.平衡二叉树的左旋右旋

增加和删除元素的操作则可能需要借由一次或多次树旋转,以实现树的重新平衡。

1左旋

当插入的新节点在节点右子树的右子树位置时。

简称:右右->左旋

(1)原节点的右孩子替代此节点位置

(2)原节点右孩子的左子树变为该节点的右子树

(3)原节点本身变为右孩子新节点的左子树

2右旋

当新插入是节点左子树的左子树时,需要右旋。

简称:左左->右旋

右旋操作与左旋类似,操作流程为:

(1)原节点的左孩子代表此节点

(2)原节点的左孩子的右子树变为节点的左子树

(3)将原节点作为左孩子新节点的右子树。

3.平衡二叉树的插入方式

1插入方式:LL

描述:在 A 的左子树根节点的左子树上插入节点而破坏平衡

旋转方式:右旋转

2插入方式:RR

描述:在 A 的右子树根节点的右子树上插入节点而破坏平衡

旋转方式:左旋转

3插入方式:LR

描述:在A的左子树根节点的右子树上插入节点而破坏平衡

旋转方式:先左旋后右旋

4插入方式:RL

描述:在 A 的右子树根节点的左子树上插入节点而破坏平衡

旋转方式:先右旋后左旋

lsy注:详解平衡二叉树(AVL),红黑树与平衡二叉树的区别_子木呀的博客-CSDN博客

二十万字C/C++、嵌入式软开面试题全集宝典十相关推荐

  1. 二十万字C/C++、嵌入式软开面试题全集宝典七

    目录 121. 怎样判断两个浮点数是否相等? 122. 宏定义一个取两个数中较大值的功能 123. define.const.typedef.inline使用方法? 124. printf实现原理? ...

  2. 二十万字C/C++、嵌入式软开面试题全集宝典十一

    目录 1. 红黑树的性质 2. 红黑树的插入与旋转 3. 红黑树与平衡二叉树 4. 二叉平衡树.红黑树.B树.B+树的区别与联系 5. hello world 程序开始到打印到屏幕上的全过程? 1. ...

  3. 二十万字C/C++、嵌入式软开面试题全集宝典八

    目录 141. 迭代器++it,it++哪个好,为什么 142. C++如何处理多个异常的? 143. 模板和实现可不可以不写在一个文件里面?为什么? 144. 在成员函数中调用delete this ...

  4. 二十万字C/C++、嵌入式软开面试题全集宝典五

    目录 81. vector越界访问下标,map越界访问下标?vector删除元素时会不会释放空间? 82. map[]与find的区别? 83. STL中list与queue之间的区别 84. STL ...

  5. 二十万字C/C++、嵌入式软开面试题全集宝典四

    目录 1. 虚函数的代价? 2. 用C语言实现C++的继承 3. 继承机制中对象之间如何转换?指针和引用之间如何转换? 4. C++四种类型转换 5. 为什么要用static_cast转换而不用c语言 ...

  6. 二十万字C/C++、嵌入式软开面试题全集宝典三

    目录 1. 构造函数析构函数可否抛出异常 2. 类如何实现只能静态分配和只能动态分配 3. 如果想将某个类用作基类,为什么该类必须定义而非声明? 4. 什么情况会自动生成默认构造函数? 5. 构造函数 ...

  7. 二十万字C/C++、嵌入式软开面试题全集宝典二

    目录 1.静态绑定和动态绑定的介绍 2.C语言struct和C++struct区别 3.虚函数可以声明为inline吗? 4.介绍 C++ 所有的构造函数 5. 什么情况下会调用拷贝构造函数 6. 为 ...

  8. 二十万字C/C++、嵌入式软开面试题全集宝典九

    目录 161. 空类 162. 空类会默认添加哪些东西?怎么写? 163. 标准库是什么? 164. const char* 与string之间的关系,传递参数问题? 165. char * 与cha ...

  9. 二十万字C/C++、嵌入式软开面试题全集宝典六

    目录 101. 字节对齐有什么作用? 102. C语言中#pragma用法 103. new和malloc的区别? 104. malloc/calloc/realloc三者之间的区别? 105. de ...

最新文章

  1. 直击2018AWE:智能语言交互大厮杀、老品牌争先搭建平台、第三方平台迅速崛起
  2. Postgis常用函数
  3. NYOJ 594 还是A+B
  4. java实现下功能载插件_javaweb项目插件实现机制
  5. SpringBoot集成Thymeleaf
  6. Visual studio 2012 ultimate 安装遇到 Prerequisites , 错误的函数 incorrect function
  7. 他受他爸影响,他爸受数学家影响,最终造出了自动旋转的房子!
  8. 傲游浏览器怎么创建笔记 傲游浏览器笔记创建方法分享
  9. id vue2路由传参_Vue2.0中 $route 和 $router 的区别
  10. linux 安装rpm qt can't creat,CentOS 6.2部署Qt开发环境
  11. 安卓app测试之Monkey日志分析《转载》
  12. html5炫酷动画及源码,分享8个难忘的HTML5炫酷动画及源码
  13. c语言浮点数输出格式的控制,c语言输出格式控制
  14. java长连接转短连接_HTTP的长连接和短连接转换接口(API)
  15. 芯片代理商哪家专业 品质是否有保障
  16. 山东科技大学2015-2016学年第一学期程序设计基础期末考试第一场 题解
  17. android 视频画面拼接,Android实现视频剪切、视频拼接以及音视频合并
  18. Python的Pexpect详解
  19. “做产品的”,如何自我调节:一封家书,给同学们参考
  20. 吉林大学软件学院期末题答案(10-16级)

热门文章

  1. .net core项目实战之开发环境搭建
  2. 201621123053《Java程序设计》第十三周学习笔记文章
  3. Laravel 的数据库迁移
  4. 韩国IT业是怎么走向国际我们须要学习什么
  5. 网站优化记录-通过命令预编译Asp.net 网站,成功优化到毫秒级别。
  6. ASP.NET 判断客户端是否为手机的函数
  7. 一张图看懂CSS cascade, specific, importance, inheritance
  8. 它们的定义Activity跳转动画
  9. UIImageView 上下和左右翻转 不是旋转
  10. XNA2.0 API --- ViewPort.Unproject出错啦