c++面试
1、static作用
a)隐藏(对本模块有效,其它文件不可见)
b)持久性(保存在静态存储区)
c)初始值为0
d)类中所有对象所有,节省空间
2、const作用
a)read only
b)节省内存(编译器编译对时候,放到符号表里面,没有分配内存)
c)更少对debug,防止被修改
1、指针
int a[4]
a和&a的区别:&a的作用范围广
int *p[4];指针数组
int (*p)[4];数组指针,p是一个指针,指向的是int [4]的数组,eg;int a[4], p=&a;
int *p(int,int);指针函数,返回是int*
int (*p)(int,int);函数指针,p指向的是函数,eg:p=max,这里的max是一个函数
指针引用:int * & arr , 在函数内部修改形参所指向的地址,调用完成后,实参指向的地址也会改变
1、c++构造函数什么时候调用
a)Box box(2.3) ;构造函数析构函数都调用了
b)Box *box;都没有调用
c)Box *box=new Box(2.3);只调用了构造函数
d) 对象作为函数的参数进行值传递时
2、堆和栈的区别
a)管理方式:
栈:编译器自动管理
堆:程序员
b)空间大小
栈:1M
堆:4G
c)碎片问题
栈:木有碎片(先进后出)
堆:有碎片
d)生长方向
栈:向内存地址减少堆方向
堆:向内存地址增加的方向
e)分配方式
栈:静态和动态
堆:动态
f)分配效率
栈:高
堆:低
3、c++内存结构
栈:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
堆:就是那些由 new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个 delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区:就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
全局/静态存储区:全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。(常量字符串就是放在这里的)
4、python 垃圾回收机制
垃圾回收
a)当内存中有不再使用的部分时,垃圾收集器就会把他们清理掉。它会去检查那些引用计数为0的对象,然后清除其在内存的空间。当然除了引用计数为0的会被清除,还有一种情况也会被垃圾收集器清掉:当两个对象相互引用时,他们本身其他的引用已经为0了。
b)垃圾回收机制还有一个循环垃圾回收器, 确保释放循环引用对象(a引用b, b引用a, 导致其引用计数永远不为0)。
1、malloc/free 和new/delete 的本质区别
new/delete能进行对对象进行构造和析构函数的调用进而对内存进行更加详细的工作,而malloc/free不能
2、虚函数表
虚函数表是全局共享的元素,即全局仅有一个.
虚函数表类似一个数组,类对象中存储vptr指针,指向虚函数表.即虚函数表不是函数,不是程序代码,不肯能存储在代码段.
虚函数表存储虚函数的地址,即虚函数表的元素是指向类成员函数的指针,而类中虚函数的个数在编译时期可以确定,即虚函数表的大小可以确定,即大小是在编译时期确定的,不必动态分配内存空间存储虚函数表,所以不再堆中.
根据以上特征,虚函数表类似于类中静态成员变量.静态成员变量也是全局共享,大小确定.
所以我推测虚函数表和静态成员变量一样,存放在全局数据区.
3、extern c的作用
extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。
这个功能十分有用处,因为在C++出现以前,很多代码都是C语言写的,而且很底层的库也是C语言写的,为了更好的支持原来的C代码和已经写好的C语言库,需要在C++中尽可能的支持C,而extern "C"就是其中的一个策略。
3、构造函数中,哪些成员变量一定要通过初始化列表来初始化
构造函数初始化时必须采用初始化列表一共有三种情况,
- 需要初始化的数据成员是对象(继承时调用基类构造函数)
- 需要初始化const修饰的类成员
- 需要初始化引用成员数据
4、模板
template <class T>
T min(T x,T y)
{ return(x<y)?x:y;}
5、内联函数和宏定义
使用宏和内联函数都可以节省在函数调用方面所带来的时间和空间开销。二者都采用了空间换时间的方式,在其调用处进行展开:
(1) 在预编译时期,宏定义在调用处执行字符串的原样替换。在编译时期,内联函数在调用处展开,同时进行参数类型检查。
(2) 内联函数首先是函数,可以像调用普通函数一样调用内联函数。而宏定义往往需要添加很多括号防止歧义,编写更加复杂。
(3) 内联函数可以作为某个类的成员函数,这样可以使用类的保护成员和私有成员。而当一个表达式涉及到类保护成员或私有成员时,宏就不能实现了(无法将this指针放在合适位置)。
6、内存对齐:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal
adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing
padding)。
内存对齐的主要作用是:
1、 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。具体原因稍后解释。
7、什么是红黑树
红黑树的性质:
1) 红黑树节点要么是红节点、要么是黑节点;
2) 根节点为黑节点;
3) 叶节点(空节点)为黑节点;
4) 每个红节点的两个子节点是黑节点;
5) 对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑节点。
c++ sqrt函数实现
newx=(oldx/2+x/oldx/2)
double mysqrt(float x)
{
if (x <= 0) return 0;
double res, lastres;
res = 0.1; //初始值,可以为任意非0的值
do{
lastres = res;
res = (res + x / res) / 2;
} while (abs(lastres - res) > 0.0001);
return res;
}