C语言内存管理与程序调试完全指南
2.10 内存管理1. C语言内存分布C语言程序在运行时内存主要分为以下几个区域栈区Stack存放局部变量、函数参数等由编译器自动分配和释放。堆区Heap由程序员手动申请和释放用于存放动态分配的数据。全局/静态区存放全局变量和静态变量。常量区存放字符串常量等。代码区存放程序的二进制代码。2. 堆区堆区是动态内存分配的主要区域通过以下函数进行管理malloc申请指定大小的堆区空间。free释放之前申请的堆区空间。注意如果使用malloc申请的空间在使用完毕后没有及时调用free释放会产生内存泄露。使用场景函数体内的局部数据不想随函数结束被回收可以放入堆区空间。存放比较大的数据如MB级别适合使用堆区空间。3. 位操作技巧在C语言中位操作是高效处理数据的重要手段// 将第n位置1 num | (1 n); // 将第n位置0 num ~(1 n); // 交换两个变量的值不使用临时变量 a a ^ b; b a ^ b; a a ^ b;2.11 程序错误调试方法1. 语法错误Warning告警程序编译成功但存在告警可能运行时会产生问题。Error错误程序编译失败需要找到出错的问题并修改代码。2. 逻辑错误打印方法调试在可能出现逻辑错误的位置加入printf打印运行时查看打印结果与设想结果是否一致从而定位出错的位置。GDB调试方法编译代码时加入-g选项允许进行gdb调试。使用gdb调试代码。输入命令调试代码。3. 段错误Segmentation Fault打印方法程序代码中多加入一些打印前一句能够打印出来后一句打印不出来两句代码中间就产生段错误。通过gdb定位段错误分布调试查看代码是否产生段错误。允许程序段错误时产生core文件core文件中包含段错误产生时的堆栈调用关系根据这个core文件搭配gdb快速找到段错误出现的位置。编译代码时加入-g选项。允许代码段错误时产生core文件。运行代码产生段错误并生成core文件。使用gdb调试core文件快速定位到程序产生段错误的位置。# 编译带调试信息的程序 gcc filename.c -g 启动gdb调试 gdb a.out gdb常用命令 l # 查看代码 b 行号/函数名 # 在行号/函数名对应的位置设置断点 r # 运行代码 n # 单步执行 s # 进入函数体内部运行 p 变量名 # 查看变量的值 c # 继续运行程序到下一处断点# 允许生成core文件 ulimit -c unlimited 调试core文件 gdb a.out core4. 内存越界、内存溢出使用strncpy、strncat、strncmp替代strcpy、strcat、strcmp避免缓冲区溢出。5. 内存泄露申请的堆区空间没有释放会产生内存泄露。使用valgrind工具查看内存是否泄露。valgrind --toolmemcheck --leak-checkfull ./a.out6. 内存碎片由于堆区空间存在一些占用的小空间导致大空间不连续无法被申请使用该现象称为内存碎片。malloc不要申请小空间。小空间尽量使用栈区大空间再使用堆区。如果必须要用堆区将多个小的空间封装成一个大空间结构体再一次性申请堆区空间。Ubuntu环境配置与工具安装1. 让Ubuntu能够上网将虚拟机设置为NAT模式Windows有网、Ubuntu就有网。将Ubuntu的IP地址设置为自动获取IP地址。将ens33网卡设置为自动获取IP地址。重启网络服务。测试网络是否能够与百度连通。# 编辑网络配置文件 sudo vim /etc/network/interfaces 添加以下内容 auto lo iface lo inet loopback auto ens33 iface ens33 inet dhcp 重启网络服务 sudo /etc/init.d/networking restart 测试网络连通性 ping www.baidu.com2. 配置软件源打开Ubuntu Software Center。在终端输入如下命令# 清除旧源 sudo apt-get autoclean 更新软件源 sudo apt-get update 重建软件源依赖关系 sudo apt-get install -f3. 安装软件# 安装valgrind内存检测工具 sudo apt-get install valgrind 安装wireshark网络抓包工具 sudo apt-get install wireshark4. 安装搜狗输入法访问搜狗输入法官网下载安装搜狗输入法linux-安装指导静态库和动态库程序在链接时会将代码与系统中的库文件链接成一个可执行程序。库可以分为静态库和动态库。1. 静态库特点库文件在编译时加载到程序中。文件名lib库名.a优点代码编译完毕后删除静态库对代码没有任何影响。缺点会使代码体积增大多个代码使用自己的静态库。2. 动态库特点库文件是在运行时加载到程序中。文件名lib库名.so优点代码体积不会增大多个代码可以使用同一个动态库。缺点删除了动态库代码无法运行。3. 查看动态库依赖关系ldd a.out多文件编程与Makefile1. Makefile基础用户在工程目录下输入make系统会自动查找当前目录下的makefile或Makefile来调用编译脚本。2. 语法规则# 基本语法 目标文件: 依赖文件 编译规则3. Makefile中的变量默认变量$要生成的文件名目标文件名$^所有依赖的文件名中间以空格隔开$第一个依赖的文件名自定义变量# 定义变量 变量名值 使用变量 $(变量名)4. Makefile中的赋值直接赋值覆盖赋值:覆盖赋值?如果之前没值赋值为新值之前有值不会赋值新值在原来值的基础上加上新值