• 【C语言】动态内存管理


     动态内存管理

    1、动态内存所开辟的空间都是在堆上开辟的;


    malloc函数

    1、可以向内存申请一块连续可用的空间,并返回这块空间的指针;

    2、开辟成功,返回指向空间的指针;

    3、开辟失败,返回NULL;

    4、malloc申请的空间释放:1、free释放(主动);2、程序退出,操作系统回收(被动释放);

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. int main()
    4. {
    5. // 开辟一块malloc空间
    6. int* p = (int*)malloc(10 * (sizeof(int)));
    7. // 判断malloc是否为空
    8. if (p == NULL)
    9. {
    10. // 打印出错误原因
    11. perror("malloc");
    12. return 1;
    13. }
    14. // 使用malloc开辟的空间
    15. for (int i = 0; i < 10; i++)
    16. {
    17. printf("%d ", *(p + i)); // 未初始化
    18. }
    19. return 0;
    20. }

    free函数

    1、用来释放动态开辟的内存;

    2、free的参数的空间不是动态开辟的空间,那free的行为是未定义的;

    3、free的参数是NULL指针,函数什么都都不做;

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. int main()
    4. {
    5. // 开辟一块malloc空间
    6. int* p = (int*)malloc(10 * (sizeof(int)));
    7. // 判断malloc是否为空
    8. if (p == NULL)
    9. {
    10. // 打印出错误原因
    11. perror("malloc");
    12. return 1;
    13. }
    14. // 使用malloc开辟的空间
    15. for (int i = 0; i < 10; i++)
    16. {
    17. *(p + i) = i;
    18. printf("%d ", *(p + i));
    19. }
    20. // free释放空间
    21. free(p);
    22. p = NULL; // 最后将指针制为空指针
    23. return 0;
    24. }

    calloc函数

    1、calloc也是开辟空间的;

    2、calloc会将开辟好的空间全部初始化为0;

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. int main()
    4. {
    5. // 开辟一块calloc空间
    6. int* q = (int*)calloc(10, sizeof(int));
    7. if (q == NULL)
    8. {
    9. perror("calloc");
    10. return 1;
    11. }
    12. for (int i = 0; i < 10; i++)
    13. {
    14. printf("%d ", *(q + i)); // 全都初始化为了0
    15. }
    16. free(q);
    17. q = NULL;
    18. return 0;
    19. }

     realloc函数

    1、realloc函数使用来追加空间的;

    2、realloc的返回值不能用追加到指定空间接收;(因为如果追加空间失败,则会导致以前开辟的空间也置为空);

    3、如果后续空间被占用,不能直接使用;realloc则会找一块新的空,一次性开辟够;并将就空间中的数据拷贝到新空间中,还会将就得空间释放掉,返回新空间的地址;

    4、realloc追加的空间内存放的是随机值;

    5、realloc函数的第一个参数如果是一个空指针,那么就等价于malloc函数;

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. int main()
    4. {
    5. // 开辟一块calloc空间
    6. int* q = (int*)calloc(10, sizeof(int));
    7. if (q == NULL)
    8. {
    9. perror("calloc");
    10. return 1;
    11. }
    12. // 使用realloc追加空间
    13. // q = (int*)realloc(q, 10 * sizeof(int));
    14. // 这样写是会出问题的,最好不用自己接收;
    15. int* q1 = (int*)realloc(q, 10 * (sizeof(int)));
    16. if (q1 == NULL)
    17. {
    18. perror("realloc");
    19. return 1;
    20. }
    21. for (int i = 0; i < 20; i++)
    22. {
    23. printf("%d ", *(q + i)); // realloc追加的空间值是随机值
    24. }
    25. free(q);
    26. free(q1);
    27. q = NULL;
    28. q1 = NULL;
    29. return 0;
    30. }

     动态内存常见错误

    1、对NULL指针的解引用操作;

    • 不对动态内存开辟空间的返回值进行判断,就对该指针进行解引用操作,就会出现错误;

    2、对动态内存的越界访问;

    3、对非动态的内存free释放;

    4、使用free释放动态内存的一部分;

    • 使用动态内存保证指针的起始位置不变;

    5、对同一块动态内存空间多次释放;

    • 所以要保证在free完之后将指针置为空指针,这样多次释放就不会报错了;

    6、忘记释放动态内存空间(内存泄漏);


     笔试题

    题目1:未free、解引用NULL指针

    源代码:

    1. #include
    2. #include
    3. #include
    4. void GetMemory(char* p)
    5. {
    6. p = (char*)malloc(100); // 没有内存释放,并且形参不会改变实参;
    7. }
    8. void Test(void)
    9. {
    10. char* str = NULL;
    11. GetMemory(str);
    12. strcpy(str, "hello world"); // 对NULL指针解引用;
    13. printf(str);
    14. }
    15. int main()
    16. {
    17. Test();
    18. return 0;
    19. }

    修改后的代码1:

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. void GetMemory(char** p)
    5. {
    6. *p = (char*)malloc(100); // 没有内存释放,并且形参不会改变实参;
    7. // 这里通过解引用找到首元素地址
    8. }
    9. void Test(void)
    10. {
    11. char* str = NULL;
    12. GetMemory(&str); // 所以这里传地址过去,通过形参改变实参;
    13. strcpy(str, "hello world"); //NULL指针解引用;
    14. printf(str);
    15. // 使用完后,对动态内存空间进行释放
    16. free(str);
    17. str = NULL;
    18. }
    19. int main()
    20. {
    21. Test();
    22. return 0;
    23. }

    修改后的代码2:

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. void* GetMemory()
    5. {
    6. char* p;
    7. return p = (char*)malloc(100); // 没有内存释放,并且形参不会改变实参;
    8. // 将地址传回去
    9. }
    10. void Test(void)
    11. {
    12. char* str = NULL;
    13. str = GetMemory();
    14. strcpy(str, "hello world"); //NULL指针解引用;
    15. printf(str);
    16. // 最后释放
    17. free(str);
    18. str = NULL;
    19. }
    20. int main()
    21. {
    22. Test();
    23. return 0;
    24. }

     题目2:野指针

    注意:

    局部变量出了当前函数就会销毁,千万千万不能返回变量地址,也就是不能返回栈空间地址,那么所接收的指针就成为了野指针;地址是带回来了,但是空间却销毁了;

    1. char* GetMemory(void)
    2. {
    3. char p[] = "hello world";
    4. return p;
    5. }
    6. void Test(void)
    7. {
    8. char* str = NULL;
    9. str = GetMemory(); // str成了野指针了
    10. printf(str);
    11. }


     题目3:未free(存在内存泄漏)

    这个代码和题目1改造后的代码很像, 只是少了释放动态内存空间,存在内存泄漏;

    1. #include
    2. void GetMemory(char** p, int num)
    3. {
    4. *p = (char*)malloc(num);
    5. }
    6. void Test(void)
    7. {
    8. char* str = NULL;
    9. GetMemory(&str, 100);
    10. strcpy(str, "hello");
    11. printf(str);
    12. }
    13. int main()
    14. {
    15. Test();
    16. return 0;
    17. }

     题目4:free后未置为NULL

    1. #include
    2. void Test(void)
    3. {
    4. char* str = (char*)malloc(100);
    5. strcpy(str, "hello");
    6. free(str);
    7. if (str != NULL)
    8. {
    9. strcpy(str, "world");
    10. printf(str);
    11. }
    12. }
    13. int main()
    14. {
    15. Test();
    16. return 0;
    17. }

    代码错误注释:

    1. #include <stdio.h>
    2. void Test(void)
    3. {
    4. char* str = (char*)malloc(100);
    5. // 未判断NULL
    6. strcpy(str, "hello");
    7. free(str);
    8. // 应该在后面将str置为NULL
    9. if (str != NULL)
    10. {
    11. strcpy(str, "world"); // 先释放了空间,所以这里的str成了野指针
    12. printf(str);
    13. }
    14. }
    15. int main()
    16. {
    17. Test();
    18. return 0;
    19. }

    C/C++的内存开辟

    还未写完

  • 相关阅读:
    Caffe在Linux下的安装,编译,实验
    信息熵,交叉熵,KL散度,互信息一网打尽
    HTML-form表单
    【python】OpenCV—Image Pyramid(8)
    RESTful API,以及如何使用它构建 web 应用程序
    GBase 8c V3.0.0数据类型——文本检索函数
    Cholesterol-PEG-DBCO,CLS-PEG-DBCO,胆固醇-聚乙二醇-二苯基环辛炔科研试剂
    Install pydot and install graphviz
    C/C++内存管理
    打卡系统有什么用?如何通过日常管理系统提高企业员工的效率?
  • 原文地址:https://blog.csdn.net/2201_75406088/article/details/133843776