c语言内存分区详细介绍

目录

一 c语言内存分区

1. 代码区(Code Segment 或 Text Segment)

2. 数据段(Data Segment)

3. BSS段(Block Started by Symbol)

4. 栈区(Stack)

5. 堆区(Heap)

二 内存使用注意事项

1. 内存泄漏:

2. 重复释放:

3. 野指针:

4. 数组越界:

5. 未初始化的内存:

6. 缓冲区溢出:



一 c语言内存分区

1. 代码区(Code Segment 或 Text Segment)


   - **作用**:存储程序的机器指令。在程序加载到内存时,操作系统会将可执行文件中的二进制代码复制到代码区,CPU执行的就是这部分内存里的指令。
   - **特点**:代码区一般是只读的,以防止程序意外修改指令流,增强系统的安全性。

   **实例**:

 int main() {
    int x = 5; // 这一行对应的机器指令就存储在代码区
    return 0;
 }

2. 数据段(Data Segment)

   - **作用**:存储程序中已初始化的全局变量和静态变量的值。
   - **特点**:数据段中的内容在程序运行开始时就固定下来,除非程序明确改变了这些变量的值。

   **实例**:

   int initializedGlobalVar = 10; // 存储在数据段
   static int initializedStaticLocalVar = 20; // 局部静态变量,同样存储在数据段

3. BSS段(Block Started by Symbol)

  - **作用**:存储未初始化或者初始化为0的全局变量和静态变量。BSS段并不在可执行文件中存储这些变量的值(都为0),而是在程序加载到内存时自动为这些变量分配内存并清零。
   - **特点**:BSS段有助于减少可执行文件的大小。

   **实例**:

   int uninitializedGlobalVar; // 存储在BSS段,默认值为0
   static int uninitializedStaticLocalVar; // 局部静态变量,默认值也为0,存储在BSS段

4. 栈区(Stack)

 - **作用**:用于存储函数调用时的局部变量、函数参数和返回地址等临时数据。栈是从高地址向低地址增长的,采用“后进先出”(LIFO)的原则。
   - **特点**:栈空间由编译器自动分配和释放,栈内存分配速度快,但大小有限。   **实例**:

   void foo(int arg) {
       int localVar = 30; // 存储在栈区
       // ...
   }

   int main() {
       foo(20); // 参数20和局部变量localVar都在栈区内分配
       return 0;
   }

5. 堆区(Heap)

- **作用**:用于动态内存分配,即程序员在程序运行过程中通过系统调用(如C语言中的`malloc`、`calloc`、`realloc`等函数)分配的内存区域。
   - **特点**:堆内存由程序员手动申请和释放,如果不释放可能会导致内存泄漏。堆内存的大小没有固定的上限,但分配和释放的速度相比栈内存较慢。   **实例**:

   #include <stdlib.h>

   int main() {
       int *dynamicVar = (int*)malloc(sizeof(int) * 5); // 在堆区分配内存
       if (dynamicVar != NULL) {
           // 使用动态分配的内存...
           free(dynamicVar); // 用完后必须手动释放
       }
       return 0;
   }

二 内存使用注意事项

内存使用注意事项涵盖了多个方面,包括避免内存泄漏、防止野指针引用、正确处理数组边界、适当地分配和释放内存等。以下是一些常见的内存使用错误实例及其对应的注意事项:

1. 内存泄漏:

 错误实例:

   int *array = (int*)malloc(sizeof(int)*10);
   // 使用array...
   // 忘记释放内存

  注意事项:每次使用`malloc`、`calloc`等函数分配的内存,在不再需要时必须通过`free`函数释放,否则会造成内存泄漏。

2. 重复释放:

 错误实例:

   int *ptr = (int*)malloc(sizeof(int));
   free(ptr);
   // ...一段时间后
   free(ptr);  // 重复释放内存

 注意事项:释放内存后,不应该再次释放同一指针。重复释放内存可能导致未定义行为,甚至程序崩溃。

3. 野指针:

错误实例:

   int *ptr = (int*)malloc(sizeof(int));
   free(ptr);
   *ptr = 42;  // 释放后仍使用指针,形成野指针

 注意事项:在释放内存后,应立即将指向该内存的指针设为NULL,防止后续代码误用成为野指针。使用野指针会导致未定义行为。

4. 数组越界:

错误实例:

   int array[10];
   for (int i = 0; i <= 10; ++i) {
       array[i] = i;  // 数组越界写入
   }

  注意事项:访问数组时要注意索引范围,数组的最后一个有效元素的索引是数组长度减一,超出这个范围就是数组越界。

5. 未初始化的内存:

 错误实例:

   int *uninitPtr = (int*)malloc(sizeof(int));
   printf("%d\n", *uninitPtr);  // 使用未初始化的内存

  注意事项:分配内存后应及时初始化,否则内存中可能是随机值,直接读取未初始化的内存可能导致不可预测的结果。

6. 缓冲区溢出:

错误实例:

   char buffer[10];
   strcpy(buffer, "This is a very long string");  // 字符串拷贝超过buffer大小

  注意事项:在复制字符串或填充缓冲区时,务必检查目标缓冲区的大小,防止数据溢出覆盖相邻内存区域。

以上示例展示了在C语言中容易犯的内存使用错误,避免这些问题需要程序员在编程时谨慎处理内存分配和释放,并始终关注内存边界的合法性。对于现代编程语言如C++,可以使用智能指针、容器类等特性来降低内存错误的发生概率。

  • 60
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值