建设网站网站首页,购物网站开发代码,网站博客程序,商城手机网站开发文章目录 17、说说new和malloc的区别#xff0c;各自底层实现原理。18、 说说const和define的区别。19、 说说C中函数指针和指针函数的区别#xff1f;20、 说说const int *a, int const *a, const int a, int *const a, const int *const a分别是什么#xff0c;有什么特点… 文章目录 17、说说new和malloc的区别各自底层实现原理。18、 说说const和define的区别。19、 说说C中函数指针和指针函数的区别20、 说说const int *a, int const *a, const int a, int *const a, const int *const a分别是什么有什么特点。21、说说使用指针需要注意什么22、说说内联函数和函数的区别内联函数的作用23、 简述C有几种传值方式之间的区别是什么24、简述const星号和星号const的区别25、简述堆和栈的区别26、简述C的内存管理?27、常见的内存错误及其对策28、内存泄露及解决办法29、 malloc和局部变量分配在堆还是栈30、程序有哪些section分别的作用程序启动的过程怎么判断数据分配在栈上还是堆上31、 初始化为0的全局变量在bss还是data32、简述C中内存对齐的使用场景 17、说说new和malloc的区别各自底层实现原理。
new是操作符而malloc是函数。new在调用的时候先分配内存在调用构造函数释放的时候调用析构函数而malloc没有构造函数和析构函数。malloc需要给定申请内存的大小返回的指针需要强转new会调用构造函数不用指定内存的大 小返回指针不用强转。new可以被重载malloc不行new分配内存更直接和安全。new发生错误抛出异常malloc返回null。
malloc底层实现当开辟的空间小于 128K 时调用 brk函数当开辟的空间大于 128K 时调用mmap。malloc采用的是内存池的管理方式以减少内存碎片。先申请大块内存作为堆区然后将堆区分为多个内存块。当用户申请内存时直接从堆区分配一块合适的空闲快。采用隐式链表将所有空闲块每一个空闲块记录了一个未分配的、连续的内存地址。
new底层实现关键字new在调用构造函数的时候实际上进行了如下的几个步骤
创建一个新的对象将构造函数的作用域赋值给这个新的对象因此this指向了这个新的对象执行构造函数中的代码为这个新对象添加属性返回新对象
18、 说说const和define的区别。
const用于定义常量而define用于定义宏而宏也可以用于定义常量。都用于常量定义时它们的区别 有
const生效于编译的阶段define生效于预处理阶段。const定义的常量在C语言中是存储在内存中、需要额外的内存空间的define定义的常量运行时是直接的操作数并不会存放在内存中。const定义的常量是带类型的define定义的常量不带类型。因此define定义的常量不利于类型检查。
19、 说说C中函数指针和指针函数的区别
定义不同 指针函数本质是一个函数其返回值为指针。 函数指针本质是一个指针其指向一个函数。写法不同
指针函数int *fun(int x,int y);
函数指针int (*fun)(int x,int y);20、 说说const int *a, int const *a, const int a, int *const a, const int *const a分别是什么有什么特点。
1. const int a; //指的是a是一个常量不允许修改。
2. const int *a; //a指针所指向的内存里的值不变即*a不变
3. int const *a; //同const int *a;
4. int *const a; //a指针所指向的内存地址不变即a不变
5. const int *const a; //都不变即*a不变a也不变21、说说使用指针需要注意什么
定义指针时先初始化为NULL。用malloc或new申请内存之后应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。避免数字或指针的下标越界特别要当心发生“多1”或者“少1”操作动态内存的申请与释放必须配对防止内存泄漏用free或delete释放了内存之后立即将指针设置为NULL防止“野指针”。
22、说说内联函数和函数的区别内联函数的作用
内联函数比普通函数多了关键字inline。内联函数避免了函数调用的开销普通函数有调用的开销。普通函数在被调用的时候需要寻址函数入口地址内联函数不需要寻址。内联函数有一定的限制内联函数体要求代码简单不能包含复杂的结构控制语句普通函数没有这个要求。 内联函数的作用内联函数在调用时是将调用表达式用内联函数体来替换。避免函数调用的开销。
23、 简述C有几种传值方式之间的区别是什么
传参方式有这三种值传递、引用传递、指针传递
值传递形参即使在函数体内值发生变化也不会影响实参的值引用传递形参在函数体内值发生变化会影响实参的值指针传递在指针指向没有发生改变的前提下形参在函数体内值发生变化会影响实参的值 值传递用于对象时整个对象会拷贝一个副本这样效率低而引用传递用于对象时不发生拷贝行为只是绑定对象更高效指针传递同理但不如引用传递安全。
24、简述const星号和星号const的区别
//const* 是指针常量*const 是常量指针
int const *a; //a指针所指向的内存里的值不变即*a不变指针可变
int *const a; //a指针所指向的内存地址不变即a不变其所指内存值可变。25、简述堆和栈的区别
区别
堆栈空间分配不同。栈由操作系统自动分配释放 存放函数的参数值局部变量的值等堆一般由程序员分配释放。堆栈缓存方式不同。栈使用的是一级缓存 它们通常都是被调用时处于存储空间中调用完毕立即释放** **堆栈数据结构不同。堆类似数组结构栈类似栈结构先进后出。
26、简述C的内存管理?
内存分配方式 在C中内存分成5个区他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈在执行函数时函数内局部变量的存储单元都可以在栈上创建函数执行结束时这些存储单元自动被释放。堆就是那些由new分配的内存块一般一个new就要对应一个delete。自由存储区就是那些由malloc等分配的内存块和堆是十分相似的不是用free来结束自己的生命。全局/静态存储区全局变量和静态变量被分配到同一块内存中常量存储区这是一块比较特殊的存储区里面存放的是常量不允许修改。
27、常见的内存错误及其对策
错误 1内存分配未成功却使用了它。 2内存分配虽然成功但是尚未初始化就引用它。 3内存分配成功并且已经初始化但操作越过了内存的边界。 4忘记了释放内存造成内存泄露。 5释放了内存却继续使用它。 对策 1定义指针时先初始化为NULL。 2用malloc或new申请内存之后应该立即检查指针值是否为NULL。防止使用指针值为NULL 的内存。 3不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。 4避免数字或指针的下标越界特别要当心发生“多1”或者“少1”操作 5动态内存的申请与释放必须配对防止内存泄漏 6用free或delete释放了内存之后立即将指针设置为NULL防止“野指针”。 7使用智能指针
28、内存泄露及解决办法
什么是内存泄露
简单地说就是申请了一块内存空间使用完毕后没有释放掉。 1new和malloc申请资源使用后没有用delete和free释放 2子类继承父类时父类析构函数不是虚函数。 3Windows句柄资源使用后没有释放。
怎么检测 第一良好的编码习惯使用了内存分配的函数一旦使用完毕,要记得使用其相应的函数释放掉。 第二将分配的内存的指针以链表的形式自行管理使用完毕之后从链表中删除程序结束时可检查改链表。 第三使用智能指针。 第四一些常见的工具插件如ccmalloc、Dmalloc、Leaky、Valgrind等等。
29、 malloc和局部变量分配在堆还是栈
malloc是在堆上分配内存需要程序员自己回收内存 局部变量是在栈中分配内存超过作用域就自动回收。
30、程序有哪些section分别的作用程序启动的过程怎么判断数据分配在栈上还是堆上 一个程序有哪些section 如上图从低地址到高地址一个程序由代码段、数据段、 BSS 段组成。
数据段存放程序中已初始化的全局变量和静态变量的一块内存区域。代码段存放程序执行代码的一块内存区域。只读代码段的头部还会包含一些只读的常数变量。BSS 段存放程序中未初始化的全局变量和静态变量的一块内存区域。可执行程序在运行时又会多出两个区域堆区和栈区。 堆区动态申请内存用。堆从低地址向高地址增长。 栈区存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。最后还有一个文件映射区位于堆和栈之间。堆 heap 由new分配的内存块其释放由程序员控制一个new对应一个delete栈 stack 是那些编译器在需要时分配在不需要时自动清除的存储区。存放局部变量、函数参数。常量存储区 存放常量不允许修改。
程序启动的过程
操作系统首先创建相应的进程并分配私有的进程空间然后操作系统的加载器负责把可执行文件的数据段和代码段映射到进程的虚拟内存空间中。加载器读入可执行程序的导入符号表根据这些符号表可以查找出该可执行程序的所有依赖的动态链接库。加载器针对该程序的每一个动态链接库调用LoadLibrary 1查找对应的动态库文件加载器为该动态链接库确定一个合适的基地址。 2加载器读取该动态链接库的导入符号表和导出符号表比较应用程序要求的导入符号是否匹配该库的导出符号。 3针对该库的导入符号表查找对应的依赖的动态链接库如有跳转则跳到3 4调用该动态链接库的初始化函数。初始化应用程序的全局变量对于全局对象自动调用构造函数。进入应用程序入口点函数开始执行。
怎么判断数据分配在栈上还是堆上首先局部变量分配在栈上而通过malloc和new申请的空间是在堆上。
31、 初始化为0的全局变量在bss还是data
BSS段通常是指用来存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域。特点是可读写的在程序执行之前BSS段会自动清0。
32、简述C中内存对齐的使用场景
内存对齐应用于三种数据类型中struct/class/union。
struct/class/union内存对齐原则有四个
数据成员对齐规则结构(struct)或联合(union)的数据成员第一个数据成员放在offset为0的地方以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小的整数倍开始。结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最宽基本类型成员的整数倍地址开始存储。(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储)。收尾工作:结构体的总大小也就是sizeof的结果必须是其内部最大成员的最宽基本类型成员的整数倍。不足的要补齐。(基本类型不包括struct/class/uinon)。sizeof(union)以结构里面size最大元素为union的size因为在某一时刻union只有一个成员真正存储于该地址。
什么是内存对齐那么什么是字节对齐在C语言中结构体是一种复合数据类型其构成元素既可以是基本数据类型如int、long、float等的变量也可以是一些复合数据类型如数组、结构体、联合体等的数据单元。在结构体中编译器为结构体的每个成员按其自然边界alignment分配空间。各个成员按照它们被声明的顺序在内存中顺序存储第一个成员的地址和整个结构体的地址相同。为了使CPU能够对变量进行快速的访问变量的起始地址应该具有某些特性即所谓的“对齐”比如4字节的int型其起始地址应该位于4字节的边界上即起始地址能够被4整除也即“对齐”跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍他就被称做自然对齐。为什么要字节对齐 为了快速准确的访问若没有字节对齐则会出现多次访问浪费时间。 举例说明定义一个char 和 int型数据不按照字节对齐存储的情况需要多次访问