知识点
动态内存分配
3个基本数据区
程序内存布局与变量内存位置
野指针问题
内存泄漏与内存错误
敲黑板先看这里
你觉不觉得C语言基础知识概念在头脑里没有形成知识体系?是否比较模糊比较乱?这就对了?我之前也是,有些知识点时间长了容易忘或者混淆,有些初学者抓不住重点觉得C语言复杂,难!实不相瞒,我也是这样的感受,于是我想是时候整体的把C语言给好好的总结一下了,这样形成一个知识体系,就不容易忘,也不容易混淆,这就是这次总结的意义所在。
分为几个板块总结:数据类型、指针与数组、字符串、多维指针与多维数组、函数、内存分配与操作问题、符号总结、控制语句、以及编译方面的问题。
总结宗旨:绝不专牛角尖!主要围绕常用应用知识为主,突出重点,能够很好的形成知识架构。比如:总结了float一般就不会再总结double,这样做没有多大意义,相反的,把重要的拿出来好好分析一下,是很有意义的,而相似的东西就可以举一反三了。实际上就这些知识点,概念搞明白后,C语言就通透多了
注意:
这个板块内容相对较多,不要怕!建议一个一个的理解,然后再整体归纳一下,最后浓缩后发现
其实内容也就那么几点,初学者关键在于克服内心恐惧,一点一点的突破,5遍下来,其意自现!
动态内存分配
1.C语言中的一切操作都是基于内存的,变量和数组都是内存的别名:内存分配由编译器在编译期间决定 ;定义数组的时候必须指定数组长度;数组长度是在编译期就必须确定的。而在程序运行的过程中,可能 需要使用一些额外的内存空间。
2.malloc和free用于执行动态内存分配和释放;malloc所分配的是一块连续的内存,以字节为单位,并且 不带任何的类型信息;free用于将动态内存归还系统:
void* malloc(size_t size); void free(void* pointer);
3.malloc和free是库函数,而不是系统调用,因此不能依赖于不同平台下的malloc行为;malloc实际分配 的内存可能会比请求的多;当请求的动态内存无法满足时malloc返回NULL;当free的参数为NULL时,函数直接返回。( malloc(0);将返回一个地址,占用一定的空间,只是返回的这个地址不可用)
4.malloc的同胞兄弟:calloc与realloc;
void* calloc(size_t num, size_t size);
void* realloc(void* pointer, size_t new_size);
calloc的参数代表所返回内存的类型信息,会将返回的内存初始化为0;
realloc用于修改一个原先已经分配的内存块大小,在使用realloc之后应该使用其返回值;当pointer的第一个参数为NULL时,等价于malloc。
5.动态内存分配是C语言中的强大功能,程序能够在需要的时候有机会使用更多的内存,malloc单纯的从系统中申请固定字节大小的内存;而calloc能以类型大小为单位申请内存并初始化为0;realloc用于重置内存大小。
3个基本数据区
1.栈、堆和静态存储区是程序中的三个基本数据区:栈区主要用于函数调用的使用;堆区主要用于内存 的动态申请和归还;静态存储区主要用于保存全局变量和静态变量。
2.栈 是现代计算机程序里最为重要的概念之一,在程序中用于维护函数调用上下文,函数的参数和局部变量存储在栈上,栈保存了一个函数调用所需的维护信息:参数、返回地址、局部变量、调用上下文 等。每次函数调用都对应着一个栈上的活动记录,调用函数的活动记录位于栈的中部,被调函数的活 动记录位于栈的顶部;函数调用时,对应的栈空间在函数返回前是专用的,函数调用结束后,栈空间将被释放,数据不再有效(这就解释了为什么不能返回函数中局部变量或者局部数组的地址)。
3.堆 是程序中一块预留的内存空间,可由程序自由使用,堆中被程序申请使用的内存在被主动释放前将 一直有效,栈上的数据在函数返回后就会被释放掉,无法传递到函数外部,如:局部数组。这就是堆存在的意义之一。在C语言中通过库函数的调用获得堆空间(包含头文件:malloc.h;malloc以字节的 方式动态申请堆空间,free将堆空间归还给系统)。系统通过{空闲链表法、位图法、对象池法等}方式来管理堆空间。
4.静态存储区 主要用于保存全局变量和静态局部变量,在程序的编译期存储区的大小就已经确定, 静态存储区的信息最终会保存到可执行程序中,存储在静态存储区的对象随着程序的运行而分配空间,对象的生命周期直到程序运行结束。
程序内存布局与变量内存位置
1.程序和进程不同:程序是静态的概念,表现形式为一个可执行文件;进程是动态的概念,程序由操作 系统加载后得到进程;每个程序对应多个进程,每个进程只能对应一个程序。不同代码在编译后得到的目标文件中的位置不同:
.bss段 存放的是 未初始化 的 全局变量 和 静态变量;
.text段 存放的是程序中的 可执行代码;
.data段 存放的是 已经初始化了 的 全局变量 和 静态变量;
.rodata段 存放程序中的 常量值,如字符串常量;
以上在目标文件中的段运行后一 一映射到程序进程的地址空间!
注意:目标文件中是不存在堆栈段的,只有在程序运行后堆栈段才正式存在;
2.程序术语的对应关系:
静态存储区 通常指程序中的.bss段和.data段;
只读存储区 通常指程序中的.rodata段;
局部变量所占空间为 栈 上的空间;
动态空间为 堆 中的空间;
程序可执行代码存放于.text段;是只读的;
堆栈段是程序运行的基础,只存在于进程空间中;
野指针问题
1.野指针:指针变量中的值是非法的内存地址,是指向不可用内存地址的指针;野指针不是NULL指针,而NULL指针并无危害,很好判断也很好调试;在C语言中无法判断一个指针所 保存的地址是否合法。
2.野指来源何方?
局部指针变量没有被初始化;
指针所指向的变量在指针之前被销毁;
使用已经释放过的指针;
进行了错误的指针运算;
进行了错误的强制类型转换;
3.杜绝野指针的方法:
绝不返回局部变量和局部数组的地址;
任何变量在定义后必须0初始化;
字符数组必须确认0结束符后才能成为字符串;
任何使用与内存操作相关的函数必须指定长度信息;
内存泄漏与内存错误
1.内存错误是实际产品开发中最常见的问题,然而绝大多数的bug都可以通过遵循基本的编程原则和 规范来避免。因此,在学习的时候要牢记和理解内存操作的基本原则、目的和意义。
内存错误 :来源于指针保存的地址为非法值:
1:是指针变量未初始化,保存了随机值;
2:是指针运算导致内存越界;
内存泄漏:来源于malloc和free不匹配:
当malloc次数多于free时,产生内存泄漏;
当malloc次数少于free时,程序可能崩溃!
2.常见的内存错误:
结构体成员指针未初始化;
结构体成员指针未分配足够的内存;
内存分配成功,但并未初始化;
内存操作越界;
3.内存操作的基本规则:
1:动态内存申请之后,应该立即检查指针值是否为NULL,防止使用NULL指针;
2:free指针之后必须立即赋值为NULL;
3:任何与内存操作相关的函数都必须带长度信息;
4:malloc操作和free操作必须匹配,防止内存泄漏和多次释放;
总结
以上总结以C语言知识框架为主线,着重强调实际经常应用!反复浏览体会可牢记,形成自己的知识框架,然后灵活应用,知识点来源于狄泰软件学习总结所得。