• 【0005】堆与栈,四大动态内存分配函数(malloc, calloc, realloc, _recalloc),以及栈内存分配函数alloca


    首先说明一下32位和64位系统下的区别:

    void main001()
    {
        int num = 20;
        int *p = #
    
        printf("%p 
    ", &p);
        printf("%d 
    ", sizeof(p));
    
        
        system("pause");
    }
    
    /*
        Name    Value                        Type
    32bit    &p    0x0135f7ec{0x135f7f8{20}}        int **
        p    0x135f7f8{20}                    int *
    
    64bit    &p    0x0000007A360FF898{0x0000007a360ff874{20}}    int **
        p    0x0000007a360ff874{20}            int *
    */
    32位与64位编译器下地址的表示

        /*
            指针(地址)由编译器决定(64bit/32bit),高位编译器兼容地位编译器
            32bit操作系统的寻址能力:(指针4byte)
                0x00000000-0xFFFFFFFF    2^32=2^2*2^30 = 4G
            64bit操作系统的寻址能力:(指针8byte)
                0x0000000000000000-0xFFFFFFFFFFFFFFFF    16T

           32bitCPU与64bitCPU的本质区别:
                CPU的寻址能力
                64bitCPU能进行32bit的计算和64bit计算,32bitCPU只能进行32bit的计算

           指针的大小的决定因素:
                编译器位数
                操作系统的位数
        */

    多线程中,每一个线程都有自己独立的栈;堆内存则是共享的,32bit堆内存最大为2G,64bit最大为1024G

    栈  auto int num        自动回收,自动释放( 栈是由编译器来维护的,自动回收,自动释放,默认大小为1M,可以手动拓展栈的大小)

    堆  void *p=malloc(1024)    手动分配,手动释放

    void stack(int numA)        // 函数参数属于栈
    {
        int numB = 10;            // 局部变量属于栈
        printf("%p, %p 
    ", &numA, &numB);
    
        numA = 1;
        numB = 2;
    
        printf("
    
    
    ");
    }
    
    void main003()
    {
        //int num[1024 * 1024];    
        /*
            0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x000000F6826C3000).        编译器默认的保留栈大小是1M
    
            可以从属性页查看:Property Pages-->Configuration Properties-->Linker-->System-->Stack Reserve Size(Specifies the total stack allocation size in virtual memory.Default is 1MB.  (/STACK:reserve))
    
            可以改变Stack的默认值
        */
    
    
        stack(1);
    
        printf("
    
    
    ");
    
        stack(1);
    
        printf("
    
    
    ");
    
        system("pause");
    }
    栈中的变量,栈大小的手动修改方法
    void runstack(void *p)
    {
        while (1)
        {
            int num[1024 * 1024];        // 自动回收,自动释放
        }
    }
    
    void main004()
    {
        // 32bit堆内存最大2G
        // void *p=malloc(1024*1024);
    
        for (int i = 0; i < 3; i++)
        {
            _beginthread(runstack, 0, NULL);        // 多线程,每一个线程都有自己独立的栈
                                                    // 堆内存则是共享的,32bit堆内存最大为2G,64bit最大为1024G
        }
    
        system("pause");
    }
    在多线程中演示栈的自动生成和自动回收
    void goheap(void *p)
    {
        while (1)
        {
            malloc(1024 * 1024 * 100);    // 多线程,每一个线程都有自己独立的栈
                                    // 堆内存则是共享的,32bit堆内存最大为2G,64bit最大为1024G
            Sleep(1000);
        }
    }
    void main005()
    {
        for (int i = 0; i < 3; i++)
        {
            _beginthread(goheap, 0, NULL);
        }
    
        system("pause");
    }
    在多线程中演示堆是为多个线程共用的

    内存中的堆、栈与数据结构中的堆、栈的区别:

      内存中的栈的大小是编译器确定的,由编译器生成的代码完成分配和释放(自动分配和释放),每个线程都有一个独立的栈

      内存中的堆,是手动管理的(手动分配、手动释放),同一个进程中的多个线程共用一个堆

      数据结构中的栈——先进后出,先进先出

      数据结构中的堆——堆的本质是一个二叉树,包括二分法查找,朗格朗日差值查找,堆排序查找极值

    通过动态内存分配函数在堆上开辟动态内存

    栈中变量的静态内存分配,静态内存,编译的时候就确定了内存的大小,自动回收,自动释放

    void main024()
    {
        int a[1024 * 1024 * 100];        // 栈默认大小为1M,可以手动设置为较大的栈值
    
        system("pause");
    }
    栈中的静态内存分配

    堆中的动态内存分配

    void main022()
    {
        //int a[10];        // 静态内存,编译的时候就确定了内存的大小
        int n;
        scanf("%d", &n);
    
        int *p = malloc(n*sizeof(int));
    
        for (int i = 0; i < n; i++)
        {
            p[i] = i;
            printf("%d 
    ", p[i]);
        }
    
        system("pause");
    }
    malloc函数

    堆内存的动态分配(malloc)与手动释放(free)

    void main025()        // 动态分配一维数组内存
    {
        // int a[N]
        int N;
        scanf("%d", &N);
    
        int *p = NULL;
    
        p = malloc(N*sizeof(int));
        printf("%p 
    ", p);        // 01583BA8
    
        for (int i = 0; i < N; i++)
        {
            p[i] = i;
            printf("%d 
    ", p[i]);
        }
    
        free(p);        // 释放内存,只能释放一次内存,不能反复释放;分配内存之后一定要通过释放指向该分配内存的指针即释放内存,否则会导致内存泄漏
        printf("%p 
    ", p);        // 01583BA8
        //free(p);        // 20150421.exe has triggered a breakpoint.    当再次释放时,会触发一个断点
        p = NULL;        // 指针被释放,赋值为空
        free(p);        // free释放空指针不会出错
        free(p);
        printf("%p 
    ", p);    // 00000000
        
        system("pause");
    }
    动态分配一维数组内存
    void main026()    // 动态分配二维数组内存
    {
        // int a[3][10]
    
        int(*p)[10] = malloc(sizeof(int) * 30);
        int num = 0;
    
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 10; j++)
            {
                p[i][j] = num++;
                printf("%3d", *(*(p + i) + j));
            }
            printf("
    ");
        }
    
        free(p);
    
        system("pause");
    }
    动态分配二维数组内存
    void main028()
    {
        int(*p)[3][5] = malloc(sizeof(int) * 60);        // 三维数组
        int num = 0;
    
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                for (int k = 0; k < 5; k++)
                {
                    printf("%3d", p[i][j][k] = num++);
                }
                printf("
    ");
            }
            printf("
    
    ");
        }
    
        free(p);
    
        system("pause");
    }
    动态分配三维数组内存

    动态内存分配函数的返回值

    // malloc 函数的返回值
    void main027()
    {
        //int *p = malloc(23454656577889);
        //int *p = malloc(-1);    // 分配失败,-1补码,malloc函数的参数值类型size_t是unsigned int
        //int *p = malloc(0);        // 能分配成功,但是没有实际意义
        int *p = malloc(2345);
        printf("%p 
    ", p);
    
        /*
            动态内存分配函数返回值
                分配成功:返回内存的首地址
                分配失败:返回NULL
        */
    
        system("pause");
    }
    malloc函数的返回值

    void main009()
    {
        int *pm = malloc(100);            // 分配内存(以字节为最小单位),但是不会初始化,参数为内存分配的总大小
        int *pc = calloc(25, sizeof(int));    // 会按照类型大小将所有内存初始化为0,参数1:变量的个数,参数2:变量的大小
    
        int *p = pc;
    
        printf("%p", p);
    
        for (int i = 0; i < 25; i++)
        {
            p[i] = i;
        }
    
        puts("
    ");
        puts("
    ");
    
        system("puase");
    }
    calloc与malloc
    void main010()
    {
        /*
            realloc(parm1,parm2);    
                返回值为地址:
                    拓展成功,后续地址拓展,返回值为这片内存的首地址
                    拓展不成功,重新开辟内存,把原地址的数据拷贝到新地址,返回值为新内存的首地址(原内存空间free掉了,被回收了)
        */
        int *p = malloc(sizeof(int) * 10);        // 有效内存区域
        int *p_p = malloc(100);
    
        for (int i = 0; i < 10; i++)
        {
            p[i] = i;
        }
        printf("%p 
    ", p);                // 0x00e749d0 {0}
    
    
        int *px = realloc(p, 200);        
        printf("%p 
    ", px);    
    
        for (int i = 10; i < 50; i++)
        {
            px[i] = i;
        }
    
        puts("
    ");
        system("pause");
    }
    realloc与malloc
    void main011()
    {
        int *p = calloc(25, sizeof(int));    // 会按照类型大小将所有内存初始化为0,参数1:变量的个数,参数2:变量的大小
        printf("%p", p);
    
        for (int i = 0; i < 25; i++)
        {
            p[i] = i;
        }
    
        int *px = _recalloc(p, 50, sizeof(int));
    
        for (int i = 25; i < 50; i++)
        {
            px[i] = i;
        }
    
        puts("
    ");
    
        system("puase");
    }
    calloc与_recalloc

    堆上开辟连续内存

    void main003()
    {
        int(*p)[4] = malloc(sizeof(int) * 12);                    // 堆上开辟内存,连续分配
    
        int num = 0;
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                printf("%3d,%p", p[i][j] = num++, &p[i][j]);
            }
            putchar('
    ');
        }
        /*
            0,01294B30  1,01294B34  2,01294B38  3,01294B3C
            4,01294B40  5,01294B44  6,01294B48  7,01294B4C
            8,01294B50  9,01294B54 10,01294B58 11,01294B5C
        */
    
        system("pause");
    }
    开辟连续的堆内存_二维数组

    堆上开辟块状的内存

    void main002()
    {
        int **pp = calloc(3, 4);                // 堆上分配指针数组
    
        for (int i = 0; i < 3; i++)
        {
            pp[i] = malloc(sizeof(int) * 4);    // 每个指针分配内存,块状分配
        }
    
        int num = 0;
    
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                printf("%3d,%p", pp[i][j] = num++, &pp[i][j]);    
                /*
                    *(*(pp+i)+j) == pp[i][j]
                    *(pp+i) == pp[i]
                    pp+i == &pp[i]
                    *(pp+i)+j == &(pp[i][j])
                */
            }
            putchar('
    ');
        }
    
        /*
            0,00F64B68  1,00F64B6C  2,00F64B70  3,00F64B74        分块数据模型
            4,00F649E8  5,00F649EC  6,00F649F0  7,00F649F4
            8,00F64A28  9,00F64A2C 10,00F64A30 11,00F64A34
        */
    
        for (int i = 0; i < 3; i++)
        {
            free(pp[i]);                // 先释放块内存
        }
    
        free(pp);                        // 再释放指针
    
        system("pause");
    }
    开辟块状的堆内存_二维数组

    通过栈内存分配函数在堆上开辟静态内存

    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    
    /*
        栈上内存分配函数:
            alloca
        堆上内存分配函数:
            malloc
            calloc
            realloc
            recalloc
    */
    
    
    static void show()
    {
        int *p = alloca(sizeof(int) * 10);            // alloca是栈内分配内存的函数
    
        for (int i = 0; i < 10; i++)
        {
            p[i] = i;
        }
    
    
        //free(p);            栈上内存不能free
    }
    
    
    void main018()
    {
        show();
    
        puts("
    
    
    ");
    
        show();
    
        puts("
    
    
    ");
    
        system("pause");
    }
    alloca函数在栈上分配静态内存

    栈上开辟连续内存

    // 栈上开辟内存
    void main001()
    {
        int *p = (int[]) { 0 };                // 栈上开辟一维数组
        int a[3][4];                    // 栈上开辟二维数组
        int(*px)[4] = (int[][4]) { 0 };        // 栈上开辟二维数组
        int(*py)[3][4] = (int[][3][4]) { 0 };    // 栈上开辟三维数组
    
        system("pause");
    }
    栈上开辟连续内存
    void main004()
    {
        int(*p)[4] = (int[3][4]) { 0 };            // 栈上开辟二维数组,连续分配,自动释放
    
        int num = 0;
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                printf("%3d,%p", p[i][j] = num++, &p[i][j]);
            }
            putchar('
    ');
        }
    
        /*
              0,012FFA48  1,012FFA4C  2,012FFA50  3,012FFA54
              4,012FFA58  5,012FFA5C  6,012FFA60  7,012FFA64
              8,012FFA68  9,012FFA6C 10,012FFA70 11,012FFA74
        */
    
        system("pause");
    }
    开辟连续的栈内存_二维数组
  • 相关阅读:
    【One by one系列】一步步开始使用Redis吧(一)
    Double.valueOf()与Double.parseDouble()两者的区别
    eclipse配置SVN
    java中String.valueOf(obj)、(String)obj与obj.toString()有什么区别
    zookeeper+dubbo【转载】
    jquery中的attr与prop
    window上安装rabbitMQ
    控制 输入框 只能输入数字、小数、负数
    关于JavaScript的事件触发
    JavaScript学习第四天
  • 原文地址:https://www.cnblogs.com/ant-colonies/p/13373808.html
Copyright © 2020-2023  润新知