别再搞混堆和栈!C 语言内存管理与位运算完整学习笔记
·
内存管理、位运算
1.操作系统内存管理
内存分区(4G虚拟地址空间)
| 分区 | 说明 |
|---|---|
| 内核空间 | 操作系统内核使用,应用程序不能直接访问 |
| 栈区 | 保存局部变量、函数形参、返回值、函数调用保护现场;操作系统自动管理;默认大小8M,空间小,访问效率高,函数执行结束自动回收空间 |
| 堆区 | 开发者手动申请、手动释放;空间大,访问效率低于栈;如果申请后不释放会产生内存泄漏 |
| 数据区 | .data段:存放已初始化全局变量、static静态变量.bss段:存放未初始化全局变量、static静态变量,系统自动默认清0字符常量区:存放字符串常量,只读 |
| 文本区 | 存放程序代码指令,只读 |
堆区与栈区对比
- 栈区:系统自动分配回收;空间小(默认8M);效率高;函数结束自动释放;不能手动控制生命周期。
- 堆区:程序员手动malloc/calloc申请、free释放;空间大;效率略低;函数结束不会自动释放,忘记释放造成内存泄漏。
堆区动态内存分配函数
头文件:#include <stdlib.h>
- malloc
void *malloc(size_t size);
- 功能:向堆内存申请
size字节大小的空间 - 参数:size 需要申请的字节数
- 返回值:成功返回堆空间首地址;申请失败返回
NULL
⚠️申请完必须判断返回值是否为NULL,防止空指针访问。
- free
void free(void *ptr);
- 功能:释放堆上申请的内存
- 参数:malloc/calloc得到的堆空间首地址
注意:不要重复free、不要free栈上变量地址;释放之后建议把指针置NULL,避免野指针。
- calloc
void *calloc( size_t nmemb , size_t size );
- 功能:申请nmemb个元素,每个元素占size字节;申请后内存自动初始化为0
- 参数:nmemb元素个数;size单个元素字节大小
- 返回值:成功返回首地址,失败返回NULL
内存泄漏:堆区申请的内存,使用完毕没有调用free释放;程序运行时间越长内存占用越高。
动态数组示例
int *pa = malloc(ARRAY_LEN*sizeof(int));
if (NULL == pa)
{
printf("malloc error\n");
return 0;
}
for(int i = 0; i < ARRAY_LEN; i++)
{
pa[i] = i;
}
free(pa);
pa = NULL;
什么时候使用堆内存:
①函数内开辟的空间,希望函数结束之后内存仍然有效;
②需要开辟很大内存,栈空间不足。
2.位运算
位运算直接操作二进制bit位,运算效率很高;操作数只能是整型(char/short/int/long),浮点不能做位运算。
| 运算符 | 名称 | 运算规则 |
|---|---|---|
& |
按位与 | 全1为1,有0则0 |
| ` | ` | 按位或 |
^ |
按位异或 | 相同为0,相异为1 |
~ |
按位取反 | 1变0,0变1(单目运算符) |
<< |
按位左移 | 整体向左移动n位,低位补0;num << n等价 num∗2nnum * 2^nnum∗2n |
>> |
按位右移 | 整体向右移动n位;有符号数高位补符号位,无符号数高位补0;num >> n等价 num/2nnum / 2^nnum/2n |
常用位运算场景
- 将指定第n位置1:
num |= (1 << n); - 将指定第n位清0:
num &= ~(1 << n); - 判断第n位是否为1:
if(num & (1 << n)) - 不使用中间变量交换两个数(异或特性)
a ^= b;
b ^= a;
a ^= b;
补充小知识点
- 左移不要移动负数位、不要超过数据本身总bit位数,结果未定义。
- 有符号数右移是算术右移,高位补符号;无符号数是逻辑右移,高位补0。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)