十八万字整理C/C++、嵌入式软开 常见面试题汇总20

十八万字吐血整理的C/C++、嵌入式常见面试题!!!!

欢迎订阅,希望能点个赞!!!!

正在持续更新!!!!!欢迎探讨!!!

完整专栏地址:https://blog.nowcoder.net/zhuanlan/gmPWX0


相关知识点都能零星在网上找到,这个文章系列将目前遇到的所有常见面试问题进行一个汇总。

文中很多资料避免不了从网上或是其他复习资料里收集整理,十分感谢前辈的辛勤付出,如果存在侵权请一定联系我进行删除

也有相当一部分是本人在经历提前批以及秋招的过程中遇到和验证过的。


系列文章PDF下载地址:《最全C_C++及嵌入式软开面试题宝典.pdf》



101、字节对齐有什么作用?

字节对齐的作用不仅是便于cpu快速访问,同时合理的利用字节对齐可以有效地节省存储空间。

编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。

102、C语言中#pragma用法

1.#pragma message

#pragma message("消息文本")   当编译器遇到这条指令时,就在编译输出窗口中将消息文本打印出来。

2.#pragma code_seg

#pragma code_seg(["section-name"["section-class"]])

它能够设置程序中函数代码存放的代码段。当我们开发驱动程序时便就会使用到它。

3.#pragma once

只要在头文件的最开始加入这条指令就能够头文件被编译一次。

4.#pragma hdrstop

表示编译头文件到此为止,后面的头文件不进行预编译。

5.#pragma  resouce

#pragma  resouce"*.dfm"表示*.dfm文件中的资源加入工程。*.dfm中包括了外观定义。

6.#pragma warning

#pragma warning (disable:4507  34; once:4385; error:164)  等价于

#pragma warning (disable:4507  34  //不显示450730号警告信息

#pragma warning (once:4385  //4358号警告信息仅报告一次

#pragma warning (error:164 //164号警告信息作为一种错误

7.#pragma  comment

#pragma  comment(...) 该指令将一个注释放入一个对象文件或可执行文件中,常用lib关键字帮我们链入一个库文件。

如:#pragma  commentlib,"user32.lib") 该指令用来将user32.lib库文件加入到本工程中。

8. #pragma  pack

这条指令主要用作改变编译器的默认对齐方式。

103、newmalloc的区别?

1.new/delete是C++关键字,需要编译器支持。malloc/free是库函数,需要头文件支持;

2.使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。

3.new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。

4.new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时返回NULL

5.new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。

104、malloc/calloc/realloc三者之间的区别?

1void *malloc(size_t size);

size表示要分配的字节数,其中要检测空间是否开辟成功,开辟失败时返回0

作用:在内存中分配一个元素被初始化为0的数组。

2)void *calloc(size_t num, size_t size);

num表示元素的个数,size表示每个元素的大小

返回值:返回一个指向所分配空间的void指针。

作用:重新分配内存块

3)void *realloc(void* memblock,size_t size);

memblock指向原先分配的内存块,size表示新的内存块的字节大小。

返回值:返回一个指向重新分配(可能移动了)的内存块的大小。

注意:堆上的内存需要用户自己来管理,动态malloc/calloc/realloc的空间,必须free掉,否则会造成内存泄漏

105、delete p;delete[]pallocator

1.动态数组管理new一个数组时,[]中必须是一个整数,但是不一定是常量整数,普通数组必须是一个常量整数;

2.new动态数组返回的并不是数组类型,而是一个元素类型的指针;

3.delete[]时,数组中的元素按逆序的顺序进行销毁;

4.new在内存分配上面有一些局限性,new的机制是将内存分配和对象构造组合在一起,同样的,delete也是将对象析构和内存释放组合在一起的。allocator将这两部分分开进行,allocator申请一部分内存,不进行初始化对象,只有当需要的时候才进行初始化操作。

106、newdelete的实现原理,delete是如何知道释放内存的大小?

1.new简单类型直接调用operator new分配内存;而对于复杂结构,先调用operator new分配内存,然后在分配的内存上调用构造函数;对于简单类型,new[]计算好大小后调用operator new;对于复杂数据结构,new[]先调用operator new[]分配内存,然后在p的前四个字节写入数组大小n,然后调用n次构造函数,针对复杂类型,new[]会额外存储数组大小;

  • new表达式调用一个名为operator  new(operator new[])函数,分配一块足够大的、原始的、未命名的内存空间;
  • 编译器运行相应的构造函数以构造这些对象,并为其传入初始值;
  • 对象被分配了空间并构造完成,返回一个指向该对象的指针。

2.delete简单数据类型默认只是调用free函数;复杂数据类型先调用析构函数再调用operator delete;针对简单类型,delete和delete[]等同。假设指针p指向new[]分配的内存。因为要4字节存储数组大小,实际分配的内存地址为[p-4],系统记录的也是这个地址。delete[]实际释放的就是p-4指向的内存。而delete会直接释放p指向的内存,这个内存根本没有被系统记录,所以会崩溃。

3.需要在 new [] 一个对象数组时,需要保存数组的维度,C++ 的做法是在分配数组空间时多分配了 4 个字节的大小,专门保存数组的大小,在 delete [] 时就可以取出这个保存的数,就知道了需要调用析构函数多少次了。

107、malloc申请的存储空间能用delete释放吗

不能,malloc /free主要为了兼容C,new和delete 完全可以取代malloc /free的。malloc /free的操作对象都是必须明确大小的。而且不能用在动态类上。new 和delete会自动进行类型检查和大小,malloc/free不能执行构造函数与析构函数,所以动态对象它是不行的。当然从理论上说使用malloc申请的内存是可以通过delete释放的。不过一般不这样写的。而且也不能保证每个C++的运行时都能正常。

108、函数参数入栈的顺序

  • 大多数编译器中,参数是从右向左⼊栈(原因在于采⽤这种顺序,是为了让程序员在使⽤C/C++的“函数参数⻓度可变”这个特性时更⽅便。如果是从左向右压栈,第⼀个参数(即描述可变参数表各变量类型的那个参数)将被放在栈底,由于可变参的函数第⼀步就需要解析可变参数表的各参数类型,即第⼀步就需要得到上述参数,因此,将它放在栈底是很不方便的。)
  • 本次函数调用结束时,局部变量先出栈,然后是参数,最后是栈顶指针最开始存放的地址,程序由该点继续运⾏,不会产生碎⽚。

109、堆和栈区别

1.管理方式

  • 栈由操作系统自动分配释放,无需我们手动控制,无需我们手工控制,⼀般保存的是局部变量和函数参数等。
  • 堆由程序员管理,需要⼿动 new malloc delete free 进⾏分配和回收,如果不进⾏回收的话,会造成内存泄漏的问题。

2.空间大小一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改: 打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。 注意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。 

3.碎片问题对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。

4.生长方向

  • 对于栈来讲,是连续的内存空间,它的生长方向是向下的,是向着内存地址减小的方向增长。比如在函数调⽤的时候,首先⼊栈的主函数的下⼀条可执⾏指令的地址,然后是函数的各个参数。
  • 对于堆来讲,不连续的空间,实际上系统中有⼀个空闲链表,生长方向是向上的,也就是向着内存地址增加的方向,空间交⼤,较为灵活。

;当有程序申请的时候,系统遍历空闲链表找到第⼀个⼤于等于申请⼤⼩的空间分配给程序,⼀般在分配程序的时候,也会空间头部写⼊内存⼤⼩,⽅便 delete 回收空间⼤⼩。当然如果有剩余的,也会将剩余的插⼊到空闲链表中,这也是产⽣内存碎⽚的原因。

5.分配方式堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器进行释放,无需我们手工实现。 

6.分配效率栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

110、堆与栈的优点和缺点

1.堆的优缺点:堆得优点就是可以动态分配内存大小,生存期也不必告诉编译器,因为它是在运行中动态分配内存的;缺点就是由于是在运行时动态分配内存的,所以读取速度较慢。

2.栈的优缺点:栈的优点就是读取速度快,而且数据可以共享;缺点就是存在于栈中的数据大小及周期必须是确定的,缺乏灵活性。


目前已整理十万字的C/C++、嵌入式常见面试题!!!!还在持续更新中!!! 这个专栏写完了,再po上自己亲手敲的笔试编程题整理。

全部评论

相关推荐

兄弟们,绩效自评一定得给自己打A啊!千万别谦虚给低分,不然领导正愁给谁高分,你这不就“主动请缨”了嘛,而且多数领导不会给你更高分。我几年前试用期绩效自评打了B,领导就给了同等级,还好是试用期。真别等领导主动给高评价!
准备进厂的劳伦斯很迷人:小学时候有个册子 自评 小组 老师 我谦虚打了个b 小组别人给我打b 老师来句我觉得能给他打a 但是小组长说他自评是b怎么能打高呢 那时候我才明白的道理
点赞 评论 收藏
分享
01-24 12:50
门头沟学院 C++
投票
菜狗二号:还有啥想的 指定国有行啊,去了就开始幸福美满的生活了,选华子不是折腾自己么,最终财富积累度是差不多的,但是幸福指数是相差甚远的
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客企业服务