1.定义一个全局变量放在.cpp文件还是.h文件,原因是什么
在cpp文件中定义变量,h文件用来声明变量的作用域,使用extern声明的变量可以在本编译单元或其他编译单元中使用。
举例如下:
a.h文件
extern int a;
a.cpp文件
int i=1;
其他cpp文件如果需要用到全局变量,加入#include<a.h>
即B编译单元要引用A编译单元中定义的全局变量或函数时,B编译单元只要包含A编译单元的头文件即可,在编译阶段,B编译单元虽然找不到该函数或变量,但它不会报错,它会在链接时从A编译单元生成的目标代码中找到此函数。
2.new和malloc的区别
1.申请内存的位置不同。new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存,是操作系统所维护的一块特殊内存,用于程序的内存动态分配
2.返回类型的安全性。new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。
3.内存分配失败的返回值
new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。
4.是否需要指定内存大小。使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。
class A{...}
A * ptr = new A;
A * ptr = (A *)malloc(sizeof(A)); //需要显式指定所需内存大小sizeof(A);
5.对数组的处理。
C++提供了new[]与delete[]来专门处理数组类型:
A * ptr = new A[10];//分配10个A对象
使用new[]分配的内存必须使用delete[]进行释放:
delete [] ptr;
New创建数组时会调用构造函数初始化数组元素,删除数组后会调用每个对象的析构函数。
malloc需要用户计算数组的大小后进行内存分配,int * ptr = (int *) malloc( 10*sizeof(int) );//分配一个10个int元素的数组
3.生日攻击
生日问题:在n个人中随机选取k个人,当k为多大时能保证k个人中有两个人的生日是相同的?根据鸽笼原理(pigeon hole principle),如果有366个人,那么其中两个人必定会在同一天过生日。用统计学的方法来考虑生日问题,只要k=70,随机选取70个人,这其中两个人有相同生日的可能性就是99.9%
解法:假设至少有两个人同一天生日的概率为P,那么1-P就是没有任何两个人在同一天过生日的概率。
1-p=365/365+364/365+...+(365-k+1)/365
生日攻击:hash函数的好坏,就在于它是否能够使输出的值尽量分散,减少输出值的碰撞
在安全性方面,hash 函数必须做到够复杂,让人不能够通过简单的几组输入输出结果猜出来这个hash函数用的是什么样的算法。把hash函数的每个输入值想成是k个人中的一个,再把输出值想成是每个人的生日,那么生日问题就告诉我们,只需要很少的输入值,就会有很大的可能性有至少两个输出值完全相同。
4.指针和引用
1.指针是一个变量,存储的是地址,指向内存的一个存储单元;引用和原来的变量是同一个东西,是原变量的别名,与原变量占用同一个存储单元。
2.指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;
3.指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。
5.重载和虚函数
1.函数重载可以用于非成员函数和类的成员函数,而虚函数只能用于类的成员函数
2.函数重载可用于构造函数,而虚函数不能用于构造函数
3.如果对成员函数进行重载,重载的函数与被重载的函数应该是用一个类中的成员函数,不能分属于两个不同继承层次的类,函数重载处理的是横向的重载。虚函数是对同一类族中的基类和派生类的同名函数的处理,即允许在派生类中对基类的成员函数重新定义。虚函数处理的是纵向的同名函数。
4.重载的函数必须具有相同的函数名,函数类型可以相同也可以不同,但函数的参数个数和参数类型二者中至少有一个不同,否则在编译时无法区分。而虚函数则要求同一类族中的所有虚函数的函数名,函数类型,函数的参数个数和参数类型都全部相同,否则就不是重定义了,也就不是虚函数了
5.函数重载是在程序编译阶段确定操作的对象的,属于静态关联。虚函数是在程序运行阶段确定操作对象的,属于动态关联。