桂林论坛网站有哪些,优化手机流畅度的软件,wordpress文章首行缩进,深圳百度推广关键词推广#x1f308;欢迎来到C基础专栏 #x1f64b;#x1f3fe;♀️作者介绍#xff1a;前PLA队员 目前是一名普通本科大三的软件工程专业学生 #x1f30f;IP坐标#xff1a;湖北武汉 #x1f349; 目前技术栈#xff1a;C/C、Linux系统编程、计算机网络、数据结构、Mysq… 欢迎来到C基础专栏 ♀️作者介绍前PLA队员 目前是一名普通本科大三的软件工程专业学生 IP坐标湖北武汉 目前技术栈C/C、Linux系统编程、计算机网络、数据结构、Mysql、Python目前在学 博客介绍通过分享学习过程加深知识点的掌握也希望通过平台能认识更多同僚如果觉得文章有帮助请您动动发财手点点赞本人水平有限有不足之处欢迎大家扶正~ 最后送大家一句话共勉知不足而奋进望远山而前行。 ———————————————— C内存 1. 简述一下堆和栈的区别2.简述C的内存管理1. 内存分配方式2. 常见的内存错误及其对策 3. 内存泄露及解决办法什么是内存泄露怎么检测 4. malloc和局部变量分配在堆还是栈一个程序有哪些section初始化为0的全局变量在bss还是data 5.简述C中内存对齐的使用场景1. 什么是内存对齐 1. 简述一下堆和栈的区别
参考回答 区别
堆栈空间分配不同。栈由操作系统自动分配释放 存放函数的参数值局部变量的值等堆一般 由程序员分配释放。堆栈缓存方式不同。栈使用的是一级缓存 它们通常都是被调用时处于存储空间中调用完毕立 即释放堆则是存放在二级缓存中速度要慢些。堆栈数据结构不同。堆类似数组结构栈类似栈结构先进后出。
2.简述C的内存管理
参考回答
1. 内存分配方式
在C中内存分成5个区他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 栈在执行函数时函数内局部变量的存储单元都可以在栈上创建函数执行结束时这些存储单元自动被释放。 堆就是那些由new分配的内存块一般一个new就要对应一个delete。 自由存储区就是那些由malloc等分配的内存块和堆是十分相似的不过是用free来结束自己的生命。 全局/静态存储区全局变量和静态变量被分配到同一块内存中 常量存储区这是一块比较特殊的存储区里面存放的是常量不允许修改。
2. 常见的内存错误及其对策
1内存分配未成功却使用了它。 2内存分配虽然成功但是尚未初始化就引用它。 3内存分配成功并且已经初始化但操作越过了内存的边界。 4忘记了释放内存造成内存泄露。 5释放了内存却继续使用它。 对策 1定义指针时先初始化为NULL。 2用malloc或new申请内存之后应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。 //const* 是常量指针*const 是指针常量 int const *a; //a指针所指向的内存里的值不变即*a不变 int *const a; //a指针所指向的内存地址不变即a不变 3不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。 4避免数字或指针的下标越界特别要当心发生“多1”或者“少1”操作 5动态内存的申请与释放必须配对防止内存泄漏 6用free或delete释放了内存之后立即将指针设置为NULL防止“野指针” 7使用智能指针。
3. 内存泄露及解决办法
什么是内存泄露
简单地说就是申请了一块内存空间使用完毕后没有释放掉。 1new和malloc申请资源使用后没有用delete和free释放 2子类继承父类时父类析构函数不是虚函数 3Windows句柄资源使用后没有释放。
怎么检测
第一良好的编码习惯使用了内存分配的函数一旦使用完毕,要记得使用其相应的函数释放掉。 第二将分配的内存的指针以链表的形式自行管理使用完毕之后从链表中删除程序结束时可检查改链表。 第三使用智能指针。 第四一些常见的工具插件如ccmalloc、Dmalloc、Leaky、Valgrind等等。 4. malloc和局部变量分配在堆还是栈
参考回答 malloc是在堆上分配内存需要程序员自己回收内存局部变量是在栈中分配内存超过作用域就 自动回收。 1.2.4 程序有哪些section分别的作用程序启动的过程怎么判断数据分配在栈 上还是堆上
一个程序有哪些section
如上图从低地址到高地址一个程序由代码段、数据段、BSS段、堆、共享区、栈等组成。
数据段存放程序中已初始化的全局变量和静态变量的一块内存区域。代码段存放程序执行代码的一块内存区域。只读代码段的头部还会包含一些只读的常数变量。BSS 段存放程序中未初始化的全局变量和静态变量的一块内存区域。可执行程序在运行时又会多出两个区域堆区和栈区。 堆区动态申请内存用。堆从低地址向高地址增长。 栈区存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。最后还有一个共享区位于堆和栈之间。 程序启动的过程操作系统首先创建相应的进程并分配私有的进程空间然后操作系统的加载器负责把可执行文件的数据段和代码段映射到进程的虚拟内存空间中。加载器读入可执行程序的导入符号表根据这些符号表可以查找出该可执行程序的所有依赖的动态 链接库。加载器针对该程序的每一个动态链接库调用LoadLibrary 1查找对应的动态库文件加载器为该动态链接库确定一个合适的基地址。 2加载器读取该动态链接库的导入符号表和导出符号表比较应用程序要求的导入符号是否匹配该库的导出符号。 3针对该库的导入符号表查找对应的依赖的动态链接库如有跳转则跳到3 4调用该动态链接库的初始化函数初始化应用程序的全局变量对于全局对象自动调用构造函数。进入应用程序入口点函数开始执行。 怎么判断数据分配在栈上还是堆上首先局部变量分配在栈上而通过malloc和new申请的空间是在堆上
初始化为0的全局变量在bss还是data
参考回答 BSS段通常是指用来存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域。特点是可读写的在程序执行之前BSS段会自动清0。
5.简述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只有一个成员真正存储于该地址。 答案解析
1. 什么是内存对齐
那么什么是字节对齐在C语言中结构体是一种复合数据类型其构成元素既可以是基本数据类型如int、long、float等的变量也可以是一些复合数据类型如数组、结构体、联合体等的数据单元。在结构体中编译器为结构体的每个成员按其自然边界alignment分配空间。 各个成员按照它们被声明的顺序在内存中顺序存储第一个成员的地址和整个结构体的地址相同。 为了使CPU能够对变量进行快速的访问变量的起始地址应该具有某些特性即所谓的“对齐”比如4字节的int型其起始地址应该位于4字节的边界上即起始地址能够被4整除也即“对齐”跟数 据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍他就被称做自然对 齐。 比如在32位cpu下假设一个整型变量的地址为0x00000004(为4的倍数)那它就是自然对齐的而如果其地址为0x00000002非4的倍数则是非对齐的。现代计算机中内存空间都是按照byte 划分的从理论上讲似乎对任何类型的变量的访问可以从任何地址开始但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问这就需要各种类型数据按照一定的规则在空间上排 列而不是顺序的一个接一个的排放这就是对齐。 2. 为什么要字节对齐 需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐比如为0x00000002则CPU如果取它的值的话需要访问两次内存第一次取从0x00000002- 0x00000003的一个short第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据如果变量在0x00000003地址上的话则要访问三次内存第一次为char第二次为 short第三次为char然后组合得到整型数据。 而如果变量在自然对齐位置上则只要一次就可以取出数据。一些系统对对齐要求非常严格比如sparc系统如果取未对齐的数据会发生错误而在x86上就不会出现错误只是效率下降。 各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些平台每次读都是从偶地址开始如果一个int型假设为32位系统如果存放在偶地址开始的地方那么一个读周期就可以读出这32bit而如果存放在奇地址开始的地方就需要2个读周期并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。 3. 字节对齐实例
union example {
int a[5];
char b;
double c;
};
int result sizeof(example);
如果以最长20字节为准内部double占8字节这段内存的地址0x00000020并不是double的整数
倍只有当最小为0x00000024时可以满足整除double8Byte同时又可以容纳int a[5]的大小
所以正确的结果应该是result24
*/
struct example {
int a[5];
char b;
double c;
}test_struct;
int result sizeof(test_struct);
/*
如果我们不考虑字节对齐那么内存地址0x0021不是double8Byte的整数倍所以需要字节对
齐那么此时满足是double8Byte的整数倍的最小整数是0x0024说明此时char b对齐int扩充
了三个字节。所以最后的结果是result32
*/
struct example {
char b;
double c;
int a;
}test_struct;
int result sizeof(test_struct);
/*
字节对齐除了内存起始地址要是数据类型的整数倍以外还要满足一个条件那就是占用的内存空间大
小需要是结构体中占用最大内存空间的类型的整数倍所以20不是double8Byte的整数倍我们还
要扩充四个字节最后的结果是result24
*/
/*