面试题总结1

来源:互联网 发布:十面埋伏音乐知乎 编辑:程序博客网 时间:2024/06/13 20:50

malloc和new有什么区别?
1,malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
2,对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
3,因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
4,C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。
5、new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。

define和inline有什么区别?
本质:define只是字符串替换,inline由编译器控制,具体的:
• define只是简单的宏替换,通常会产生二义性;而inline会真正地编译到代码中
• inline函数是否展开由编译器决定,有时候当函数太大时,编译器可能选择不展开相应的函数

const和define有什么区别?
本质:define只是字符串替换,const参与编译运行,具体的:
• define不会做类型检查,const拥有类型,会执行相应的类型检查
• define仅仅是宏替换,不占用内存,而const会占用内存
• const内存效率更高,编译器通常将const变量保存在符号表中,而不会分配存储空间,这使得它成 为一个编译期间的常量,没有存储和读取的操作

引用和指针有什么区别?
本质:引用是别名,指针是地址,具体的:
• 指针可以在运行时改变其所指向的值,引用一旦和某个对象绑定就不再改变
• 从内存上看,指针会分配内存区域,而引用不会,它仅仅是一个别名
• 在参数传递时,引⽤用会做类型检查,而指针不会
• 引用不能为空,指针可以为空

C++中static关键字作用有哪些?
1、隐藏:当同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性。
static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏.
2、static的第二个作用是保持变量内容的持久:存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。
共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,
说到底static还是用来隐藏的。虽然这种用法不常见
3、static的第三个作用是默认初始化为0(static变量)
4、C++中的作用
1)不能将静态成员函数定义为虚函数。
2)静态数据成员是静态存储的,所以必须对它进行初始化。 (程序员手动初始化,否则编译时一般不会报错,但是在Link时会报错误)
3)静态数据成员在<定义或说明>时前面加关键字static。

C++中const关键字作用有哪些??
修饰变量
• 修饰成员函数,表示该成员函数不会修改成员变量

C++中成员函数能够同时用static和const进行修饰?
否,因为static表示该函数为静态成员函数,为类所有;而const是用于修饰成员函数的,两者相矛盾

C++中包含哪几种强制类型转换?他们有什么区别和联系?
• reinterpret_cast: 转换一个指针为其它类型的指针。它也允许从一个指针转换为整数类型,反之亦 然. 这个操作符能够在非相关的类型之间转换. 操作结果只是简单的从一个指针到别的指针的值的 二进制拷贝. 在类型之间指向的内容不做任何类型的检查和转换?

class A{}; class B{}; A* a = new A;B* b = reinterpret_cast(a); 

• static_cast: 允许执行任意的隐式转换和相反转换动作(即使它是不允许隐式的),例如:应用到类 的指针上, 意思是说它允许子类类型的指针转换为父类类型的指针(这是一个有效的隐式转换), 同 时, 也能够执行相反动作: 转换父类为它的子类

class Base {}; class Derive:public Base{}; Base* a = new Base; Derive *b = static_cast(a); 

• dynamic_cast: 只用于对象的指针和引用. 当用于多态类型时,它允许任意的隐式类型转换以及相 反过程. 不过,与static_cast不同,在后一种情况里(注:即隐式转换的相反过程),dynamic_cast 会检查操作是否有效. 也就是说, 它会检查转换是否会返回一个被请求的有效的完整对象。检测在 运行时进行. 如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL. 对于引用 类型,会抛出bad_cast异常
• const_cast: 这个转换类型操纵传递对象的const属性,或者是设置或者是移除,例如:

class C{}; const C* a = new C; C *b = const_cast(a);

简述C++虚函数作用及底层实现原理
要点是要答出虚函数表和虚函数表指针的作用。C++中虚函数使用虚函数表和 虚函数表指针实现,虚函数表是一个类的虚函数的地址表,用于索引类本身以及父类的虚函数的地 址,假如子类的虚函数重写了父类的虚函数,则对应在虚函数表中会把对应的虚函数替换为子类的 虚函数的地址;虚函数表指针存在于每个对象中(通常出于效率考虑,会放在对象的开始地址处), 它指向对象所在类的虚函数表的地址;在多继承环境下,会存在多个虚函数表指针,分别指向对应 不同基类的虚函数表。

一个对象访问普通成员函数和虚函数哪个更快?
访问普通成员函数更快,因为普通成员函数的地址在编译阶段就已确定,因此在访问时直接调 用对应地址的函数,而虚函数在调用时,需要首先在虚函数表中寻找虚函数所在地址,因此相比普 通成员函数速度要慢一些

在什么情况下,析构函数需要是虚函数?
在存在类继承并且析构函数中需要析构某些资源是析构函数需要是虚函数,否则若使用父类指 针指向子类对象,在delete时只会调用父类的析构函数,而不能调用子类的析构函数,造成内存泄露

内联函数、构造函数、静态成员函数可以是虚函数吗?
都不可以。内联函数需要在编译阶段展开,而虚函数是运行时动态绑定的,编译时无法展开; 构造函数在进行调用时还不存在父类和子类的概念,父类只会调用父类的构造函数,子类调用子类 的,因此不存在动态绑定的概念;静态成员函数是以类为单位的函数,与具体对象无关,虚函数是与对象动态绑定的,因此是两个冲突的概念;

构造函数中可以调用虚函数吗?
可以,但是没有动态绑定的效果,父类构造函数中调用的仍然是父类版本的函数,子类中调用的仍然是子类版本的函数

同样可以实现互斥,互斥锁和信号量有什么区别?
信号量是一种同步机制,可以当作锁来用,但也可以当做进程/线程之间通信使用,作为通信使用时不一定有锁的概念;互斥锁是为了锁住一些资源,是为了对临界区做保护

请用普通的互斥锁编程实现一个读写锁

count_mutex = mutex_init();write_mutex = mutex_init();read_count = 0;void read_lock {    lock(count_mutex);    read_count++;    if (read_count == 1) {        lock(write_mutex);    }    unlock(count_mutex);}void read_unlock {    lock(count_mutex);    read_count--;    if (read_count == 0) {        unlock(write_mutex);    }    unlock(count_mutex);}void write_lock {    lock(write_mutex);}void write_unlock {    unlock(write_mutex);}

编程实现三个线程ABC,并让它们顺次打印ABC

#include<stdio.h>#include<sys/types.h>#include<semaphore.h>#include<pthread.h>sem_t sem_id1, sem_id2, sem_id3;void* func1(void*);    //声明void* func2(void*);void* func3(void*);int main(void) {    sem_init(&sem_id1, 0, 1);    //活动    sem_init(&sem_id2, 0, 0);    sem_init(&sem_id3, 0, 0);    pthread_t pthread_id1, pthread_id2, pthread_id3;    pthread_create(&pthread_id1, NULL, func1, NULL);    pthread_create(&pthread_id2, NULL, func2, NULL);    pthread_create(&pthread_id3, NULL, func3, NULL);    pthread_join(phread_id1, NULL);    pthread_join(phread_id1, NULL);    pthread_join(phread_id1, NULL);    return 0;}void *func1 (void*) {    sem_wait(sem_id1);    printf("A\n");    sem_post(sem_id2);}void *func2 (void*) {    sem_wait(sem_id2);    printf("B\n");    sem_post(sem_id3);}void *func3 (void*) {    sem_wait(sem_id3);    printf("C\n");    sem_post(sem_id1);}

简述Linux进程内存空间分为哪几个段?作用分别是什么?
简单可以分为5部分:
1.Text:存放可执行的指令操作,其只读不能写。
2.Bss:存放未初始化的全局变量和静态变量。
3.Data:存放初始化的全局变量和静态变量。
4.Stack:存放临时变量,函数参数等。
5.Heap:存放New/Malloc等动态申请的变量,用户必须手动进行Delete/Free操作。
其中Stack和Heap的内存增长方向是相反的。

简述Linux内存分配–伙伴系统 原理
伙伴系统,其思想是:把内存块分成不同的组(1,2,4,8,16,32….);分配内存时找到能够满足条件 的最小的块;如果找不到,就找大的块,然后一分为2,分配一块,留一块;回收时:如果有相邻的同样大小的块,则合并

简述Malloc实现原理
可以基于伙伴系统实现,也可以使用基于链表的实现
• 将所有空闲内存块连成链表,每个节点记录空闲内存块的地址、大小等信息
• 分配内存时,找到大小合适的块,切成两份,一分给用户,一份放回空闲链表
• free时,直接把内存块返回链表
• 解决外部碎片:将能够合并的内存块进行合并

使用mmap读写文件为什么比普通读写函数要快?
mmap函数:可以将文件映射到内存中的一段区域,普通函数读写文件:用户空间buffer内核空间buffer磁盘;mmap映射之后:用户空间buffer进程内存空间,省掉了拷贝到内核空间的时间?

Linux中如何实现Signal?
基于软中断,不同Signal对应不同中断处理函数

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 彩虹圈被打搅了怎么办 吃中药吃大蒜了怎么办 呕吐蛋黄哥干了怎么办 鹦鹉的脚受伤了怎么办 内痔疮疼得厉害怎么办 孕妇用了痔疮膏怎么办 痔疮犯了特别疼怎么办 有痔疮肛门很痛怎么办 这几天痔疮犯了怎么办 孕初期肛裂出血怎么办 胃疼怎么办怎么缓解胃 脚踝崴了肿了怎么办 脚扭了脚背肿了怎么办 儿童脚扭伤肿了怎么办 脚关节扭伤肿了怎么办 小孩脚扭伤肿了怎么办 抱小孩腰扭伤了怎么办 跳舞把腰拉伤了怎么办 脚不小心扭伤了怎么办 娱乐之太帅了怎么办txt 走路走多了脚痛怎么办 胃疼怎么办简单按摩法 经常胃疼的厉害怎么办 半夜胃疼的厉害怎么办 吃消炎药伤胃了怎么办 吃药伤胃了胃疼怎么办 宝宝吃药伤胃了怎么办 胃胀胃痛怎么办快速解决方法 半夜2点3点胃疼怎么办 晚上吃多了胃疼怎么办 骨折打石膏后痒怎么办 脚脖子崴了肿了怎么办 喝酒喝的吐血了怎么办 感冒后咳嗽有痰怎么办 嗓子里老是有痰怎么办 物业把水停了怎么办 机洗衬衫缩水了怎么办 羊绒大衣洗缩水了怎么办 棉质衣服缩水了怎么办 衣服洗了变小了怎么办 毛衣洗后缩水了怎么办