千家信息网

如何分配C语言编程C++动态内存

发表于:2024-11-27 作者:千家信息网编辑
千家信息网最后更新 2024年11月27日,本篇内容主要讲解"如何分配C语言编程C++动态内存",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何分配C语言编程C++动态内存"吧!目录动态内存管理为什
千家信息网最后更新 2024年11月27日如何分配C语言编程C++动态内存

本篇内容主要讲解"如何分配C语言编程C++动态内存",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何分配C语言编程C++动态内存"吧!

目录
  • 动态内存管理

    • 为什么存在动态内存分配

  • 动态内存函数的介绍

    • malloc申请空间和free释放空间

    • 有借有还free释放内存

  • calloc申请内存

    • realloc调整动态内存的大小

      • realloc使用的注意事项

      • 当然realloc也可以直接开辟空间

    • 常见的动态内存错误

      • 1.对NULL指针的解引用操作

      • 2.对动态开辟空间的越界访问

      • 3.对非动态开辟内存使用free释放

      • 4.使用free释放一块动态内存开辟的一部分

      • 5.对同一块动态内存多次释放

      • 6.动态开辟内存忘记释放(内存泄漏)

    • 几个面试题

      • 题目1

      • 题目2

      • 题目3

      • 题目4

    • C/C++程序的内存开辟

      • C/C++程序内存分配的几个区域:

      动态内存管理

      为什么存在动态内存分配

      我们到现在为止掌握的是什么样的内存开辟方式呢

      //创建一个变量int val = 20;    //局部变量  在栈空间中开辟4个字节int g_val = 10;  //全局变量  在静态区中开辟4个字节//创建一个数组char arr[10] = {0}; //局部区域 在栈空间中开辟10个字节连续的空间char g_arr[5] = {0};//全局区域 在静态区空间中开辟5个字节的连续空间

      但是上述的开辟空间的方式有两个特点:

      1.空间开辟大小是固定的。

      2.数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
      但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。 这时候就只能试试动态内存开辟了。

      c99是支持变长数组的,但现在很多编译器就不支持c99,连vs都不支持,所以就有动态内存的概念

      动态内存函数的介绍

      malloc申请空间和free释放空间

      c语言提供了一个动态内存开辟的函数

      void* malloc(size_t size);

      这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

      1.如果开辟成功,则返回一个指向开辟好空间的指针。

      2.如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。

      3.返回值的类型是 void ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。*

      4.如果参数 size 为0,malloc的行为是标准未定义的,取决于编译器。

      #include#include#include#includeint main(){        //向内存申请10个整形的空间        int* p = (int*)malloc(10 * sizeof(int));        if (p == NULL)        {                //把开辟失败的信息打印出来                printf("%s",strerror(errno));        }        else        {                //正常使用空间                int i = 0;                for (i = 0; i < 10; i++)                {                        *(p + i) = i;//在找下标为i的元素                }                for (i = 0; i < 10; i++)//再把每个元素打印出来                {                        printf("%d ", *(p + i));                }        }        return 0;}

      那我们可不可以看开辟失败的呢

      我们可以用INT_MAX(他是整形最大),一个超级大的数字

      有借有还free释放内存

      free函数用来释放动态开辟的内存。
      1.如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
      2.如果参数 ptr 是NULL指针,则函数什么事都不做。

      注意

      malloc和free是成对使用的,谁开辟谁释放

      calloc申请内存

      在内存中开辟一个数组,把元素都改成零

      函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。

      与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0

      realloc调整动态内存的大小

      当然我们可以申请空间,但会不会遇到申请的空间不够了,想要增加一些些,大了想要去掉一些些

      realloc使用的注意事项

      1.如果p指向的空间之后有足够的内存空间可以追加,则直接追加,后返回p

      2.如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一块新的内存区域,开辟一块满足需求的空间,并且把原来的内存中的数据拷贝回来,释放旧的内存空间,最后返回新开辟的内存空间地址

      3.但也有一个大问题,就是开辟INT_MAX,用新的变量ptr来接收realloc返回值

      当然realloc也可以直接开辟空间

      常见的动态内存错误

      1.对NULL指针的解引用操作

      #include#includeint main(){        int* p = (int*)malloc(40);//没成功就会有大问题        int i = 0;        for (i = 0; i < 10; i++)        {                *(p + i) = i;        }        free(p);        p = NULL;        return 0;}

      所以为了防止没有开辟动态内存成功就需要做个判断

      2.对动态开辟空间的越界访问

      #include#include#include#includeint main(){        int* p = (int*)malloc(5*sizeof(int));        if (p == NULL)//这里我的确判断有没有开辟成功了        {                printf("%s", strerror(errno));        }        else        {                int i = 0;                for (i = 0; i < 10; i++)//但是我这里访问10个整型的空间                {                        *(p + i) = i;                }        }               free(p);        p = NULL;        return 0;}

      3.对非动态开辟内存使用free释放

      int main(){        int a = 0;        int* p = &a;        *p = 20;        free(p);        p = NULL;        return 0;}

      4.使用free释放一块动态内存开辟的一部分

      #include#include#include#includeint main(){        int* p = (int*)malloc(40);        if (p == NULL)        {                return 0;//如果是空指针就直接返回,不干了        }        int i = 0;        for (i = 0; i < 10; i++)        {                *p++ = i;//这个++就是bug的地方        }        //回收空间        free(p);        p = NULL;        return 0;}

      只要p不是指向申请的空间的首地址,其他地方都是错的

      5.对同一块动态内存多次释放

      #include#include#include#includeint main(){        int* p = (int*)malloc(40);        if (p == NULL)        {                return 0;        }        //使用        //释放        free(p);        //...        free(p);        return 0;}

      6.动态开辟内存忘记释放(内存泄漏)

      #include#include#include#includeint main(){        while (1)        {                malloc(100);        }        return 0;}

      几个面试题

      题目1

      void GetMemory(char* p){        p = (char*)malloc(100);}void Test(void){        char* str = NULL;        GetMemory(str);        strcpy(str,"hello world");        printf(str);//这个写法和printf("%s",str);是一样的}int main(){        Test();        return 0;}

      问运行Test函数会有什么样的结果

      修改正确

      #include#include#include#includevoid GetMemory(char* *p){        *p = (char*)malloc(100);}void Test(void){        char* str = NULL;        GetMemory(&str);        strcpy(str,"hello world");               printf(str);//这个写法和printf("%s",str);是一样的        free(str);//用完就释放        str = NULL;}int main(){        Test();        return 0;}

      题目2

      char* GetMemory(void){        char p[] = "hello world";        return p;}void Test(void){        char* str = NULL;        str = GetMemory();        printf(str);}int main(){        Test();        return 0;}

      请问运行Test 函数会有什么样的结果

      输出随机值

      修改正确

      既然是p被销毁了,那我们让他不销毁就可以了延长它的生命周期用static

      char* GetMemory(void){        static char p[] = "hello world";        return p;}void Test(void){        char* str = NULL;        str = GetMemory();        printf(str);}int main(){        Test();        return 0;}

      题目3

      void GetMemory(char **p, int num){*p = (char *)malloc(num);}void Test(void){char *str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);}

      这题基本和第一题一样,不过这题就只有内存泄漏的错误

      修改正确

      #include#includevoid GetMemory(char** p, int num){        *p = (char*)malloc(num);}void Test(void){        char* str = NULL;        GetMemory(&str, 100);        strcpy(str, "hello");        printf(str);        free(str);//用完就释放,防止内存泄漏        str = NULL;}int main(){        Test();        return 0;}

      题目4

      void Test(void){        char* str = (char*)malloc(100);        strcpy(str, "hello");        free(str);        if (str != NULL)        {                strcpy(str, "world");                printf(str);        }}

      问题非常大的打印出结果

      修改正确

      #include#include#includevoid Test(void){        char* str = (char*)malloc(100);        strcpy(str, "hello");        free(str);//这里考查的是free释放后并没有使str为NULL,所以下面if判断就没有作用,如果使他有作用就让str为NULL        str = NULL;        if (str != NULL)        {                strcpy(str, "world");                printf(str);        }}int main(){        Test();        return 0;}

      这道题真正目的就是让你什么都不打印

      C/C++程序的内存开辟

      C/C++程序内存分配的几个区域:

      栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。

      堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似于链表。

      数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。

      代码段:存放函数体(类成员函数和全局函数)的二进制代码。

      到此,相信大家对"如何分配C语言编程C++动态内存"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

      0