1、进程和线程的区别
进程是系统资源分配的单位,线程是系统调度的单位。
进程之间不能共享资源,而线程共享所在进程的地址空间和其他资源。同时线程还有自己的堆栈和局部变量,程序计数器等寄存器。
进程拥有自己独立的地址空间,而线程没有,线程必须依赖于进程而存在。
2、C++程序中调用被C编译器编译后的函数,为什么要加extern "C"声明
C++中多了重载,即函数名一样,函数的参数和返回值可以不同。为实现重载,函数在编译时都会重新命名,而C编译器编译的函数没有按该规则重新命名,加上extern,告诉C++编译器,这是C编译器编译的程序,按C的命名方式来识别函数。extern "C"的引入是为了取消C++的名字的改编,实现混合编程。
3、什么是引用?声明和使用引用要注意哪些问题
引用是某个目标变量的别名,对引用的操作与对变量的直接操作效果完全相同。声明一个引用的时候,切记要对其进行初始化。引用声明后,相当于目标变量有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是重新定义了一个变量,它只表示该引用名是目标变量的一个别名,它本身不是一种数据类型,因为该引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。
4、重载和重写的区别
定义区别:重载是指允许存在多个同名函数,而这些函数的参数表不同(参数个数或参数类型不同),重写是指子类重新定义父类虚函数的方法。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定)。
实现原理区别:
重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样)。
重写:当子类重新定义父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。
5、C++是不是类型安全的?
不是。两个不同类型的指针之间可以强制转换(用reinterpret_cast),C#是类型安全的。
6、引用和指针的区别
1)引用必须初始化,指针不必。
2)引用初始化后不能被改变,指针可以改变所指的对象。
3)不存在指向空值的引用,但存在指向空值的指针。
7、C++五大内存分区
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)— 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
写出完整的strcpy函数
char* strcpy(char* dest, const char* src) { assert((dest != NULL) && (src != NULL)); char* p = dest; while ((*p++ = *src++) != '