• C语言 内存操作函数


    内存管理

    进程空间

    程序,是经源码编译后的可执行文件,可执行文件可以多次被执行,比如我们可以
    多次打开 office。
    而进程,是程序加载到内存后开始执行,至执行结束,这样一段时间概念,多次打
    开的 wps,每打开一次都是一个进程,当我们每关闭一个 office,则表示该进程结束。
    程序是静态概念,而进程动态/时间概念。

    进程空间图示

    在这里插入图片描述

    栈内存(Stack)

    栈存储的特点

    栈中存放任意类型的变量,但必须是 auto 类型修饰的,即自动类型的局部变量,
    随用随开,用完即消。
    内存的分配和销毁系统自动完成,不需要人工干预。

    栈大小

    栈的大小并不大,他的意义并不在于存储大数据,而在于数据交换

    [root@localhost ~]# ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size
    (blocks, -f) unlimited
    pending signals                 (-i) 16384
    max locked memory       (kbytes, -l) 32
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 1024
    pipe size            (512 bytes, -p) 8
    POSIX message queues
    (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 10240
    //10M
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 16384
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited
    

    堆内存(Heap)

    堆存储的特点

    堆内存可以存放任意类型的数据,但需要自己申请与释放

    堆大小

    堆的大小受限于系统的内存大小,一般为物理内存的 1/4 到 1/2。

    测试申请大空间

    #include 
    #include 
    #include 
    int main(void)
    {
        int * p = (int*)malloc(1024*1024*1024); //1G 完全无压力
        if(p == NULL)
        {
            printf("malloc error\n");
            return -1;
        }
        int *q = (int*)malloc((unsigned int)-1);
    //无力归天 42 亿个字节 避免整型溢出
        if(q == NULL)
        {
            printf("malloc error\n");
            return -1;
        }
        return 0;
    }
    

    堆内存的申请与释放

    malloc()

    函数声明
    void * malloc(size_t _Size);
    
    函数功能

    申请指定大小的堆内存空间,并返回指向该空间的指针。

    函数参数
    • _Size:要申请的堆内存空间的大小,以字节为单位。
    • 返回值:
    • 成功:返回指向新分配的堆内存空间的指针。
    • 失败:返回 NULL。
    #include 
    #include 
    #include 
    int main(void)
    {
    //申请基本数据类型和数组,栈堆空间作对比。
        int a; int *p = &a;
        a = 100; printf("*p = %d\n",a);
        int *pm = (int*)malloc(sizeof(int));
        if(pm == NULL) return -1;
        *pm = 100;
        printf("*pm = %d\n",*pm);
    //申请基本数据类型和数组,栈堆空间作对比。
        int array[10]; int *pa = array;
        pm = (int*)malloc(10*sizeof(int));
    
        for(int i=0; i<10; i++)
        {
            printf("%d\n",pm[i]);
        }
        free(pm);
        return 0;
    }
    

    calloc()

    函数声明
    void * calloc(size_t _Num, size_t _Size);
    
    函数功能

    申请指定大小的堆内存空间,并返回指向该空间的指针。自动清零。

    函数参数
    • _Num:要申请的堆内存空间的个数。
    • _Size:要申请的堆内存空间的大小,以字节为单位。
    • 返回值:
    • 成功:返回指向新分配的堆内存空间的指针。
    • 失败:返回 NULL。
    #include 
    #include 
    #include 
    int main(void)
    {
        int * array = (int*)calloc(10,sizeof(int));
        for(int i=0; i<10; i++)
        {
            printf("%d\n",array[i]); //己被初始化。
        }
        return 0;
    }
    

    realloc()

    函数声明
    void * realloc(void * ptr, size_t size);
    
    函数功能

    调整指定指针所指向的堆内存空间的大小,并返回调整后的指针。

    函数参数
    • ptr:指向要调整的堆内存空间的指针。
    • size:新的堆内存空间的大小,以字节为单位。
    • 返回值:
    • 成功:返回指向调整后的堆内存空间的指针。
    • 失败:返回 NULL。
      返回的指针,可能与 ptr 的值相同,也有可能不同。
      若相同,则说明在原空间后面申请,否则,则可能后续空
      间不足,重新申请的新的连续空间,原数据拷贝到新空间,
      原有空间自动释放。
    #include 
    #include 
    #include 
    int main(void)
    {
        int * array = (int*)calloc(10,sizeof(int));
        int * newArray = realloc(array,80);
    //array = realloc(array,80);
        if(newArray == NULL)
        {
            printf("realloc 失败\n");
            return -1;
        }
        for(int i=0; i<20; i++)
        {
            printf("%d\n",newArray[i]);
        }
        return 0;
    }
    

    free()

    函数声明
    void free(void * ptr);
    
    函数功能

    释放指定的堆内存空间。

    函数参数
    • ptr:指向要释放的堆内存空间的指针。
    • 返回值:无。
    #include 
    #include 
    #include 
    int main(void)
    {
        int * array = (int*)calloc(10,sizeof(int));
        free(array);
        return 0;
    }
    

    应用

    动态数组

    #include 
    #include 
    
    // 主函数
    int main()
    {
        int len;
        printf("请输入新的长度:");  // 提示用户输入新长度
        scanf("%d", &len);  // 读取用户输入的长度
    
        int *p = (int*)realloc(NULL, sizeof(int) * len);  // 为指针分配内存空间
    
        // 打印初始分配的内存空间中的值
        for(int i = 0; i < len; i++)
        {
            printf("%d\n", p[i]);
        }
    
        // 增加大小
        printf("请输入新的长度:");  // 提示用户输入新长度
        scanf("%d", &len);  // 读取用户输入的长度
        p = (int*)realloc(p, sizeof(int) * len);  // 重新分配内存空间
    
        // 打印重新分配的内存空间中的值
        for(int i = 0; i < len; i++)
        {
            printf("%d\n", p[i]);
        }
    
        // 减小大小
        printf("请输入新的长度:");  // 提示用户输入新长度
        scanf("%d", &len);  // 读取用户输入的长度
        p = (int*)realloc(p, sizeof(int) * len);  // 重新分配内存空间
    
        // 打印重新分配的内存空间中的值
        for(int i = 0; i < len; i++)
        {
            printf("%d\n", p[i]);
        }
    
        free(p);  // 释放内存空间
        return 0;
    }
    
    

    置空与判空

    堆内存使用的逻辑是这样的,申请,判空,使用/释放(配对),置空。常见错误
    之一就是释放以后置未置为 NULL 再次作判空使用 或 释放以后继续非法使用。

    char*p=(char*)malloc(100);
    strcpy(p,"hello");
    free(p);/*p 所指的内存被释放,但是 p 所指的地址仍然不变*/
    //p = NULL;忘了此句,后而又用到了
    .......
    if(NULL!=p)
    {
    /*没有防错*/
    strcpy(p,"hello");
    /*出错*/
    }
    

    重复申请

    while (1)
    {
    char *p = malloc(1000);
    printf("xxxxxx\n");
    printf("xxxxxx\n");
    printf("xxxxxx\n");
    printf("xxxxxx\n");
    p = malloc(1000);
    // 中途可能忘了,重复申请,内存泄漏
    free(p);
    printf("xxxxxx\n");
    Sleep(10);
    }
    

    谁申请谁释放模型(并非绝对)

    如果没有协同的原则,则有可能会造成,重复释放

    void func(char *p)
    {
    strcpy(p, "American");
    printf("%s\n", p);
    free(p);
    //此处违反了,,谁申请谁释放的原则。
    }
    int main()
    {
    char * p = malloc(100);
    func(p);
    free(p);
    return 0;
    }
    

    内存操作函数

    memcpy

    实现两段空间的拷贝,从源地址src开始,拷贝n个字节到目的地址dest。

    void * memcpy(void *dest, const void *src, size_t n);
    
    • dest:目的地址。
    • src:源地址。
    • n:拷贝的字节数。
    #include 
    #include 
    
    int main(void)
    {
        int a[10] = {1,2,3,4,5,0,6,7,8,9}; // 定义整型数组a
        int b[10];  // 定义整型数组b
        memcpy(b, a, 10 * sizeof(a[0]));  // 使用memcpy函数对整型数组进行拷贝
        for(int i = 0; i < 10; i++)
        {
            printf("%d\n", b[i]);  // 输出拷贝后的整型数组b
        }
        printf("***************\n");
    
        char c[10] = {'a','b','c','d','\0','\n','e','f','g','h'};  // 定义字符数组c
        char d[10];  // 定义字符数组d
        memcpy(d, c, 10 * sizeof(a[0]));  // 使用memcpy函数对字符数组进行拷贝
        for(int i = 0; i < 10; i++)
        {
            printf("%c\n", d[i]);  // 输出拷贝后的字符数组d
        }
        printf("***************\n");
    
        puts(d);  // 输出字符数组d
        return 0;
    }
    
    

    输出:

    1
    2
    3
    4
    5
    0
    6
    7
    8
    9
    ***************
    a
    b
    c
    d
    
    
    
    e
    f
    g
    h
    ***************
    abcd
    

    memmove

    实现两段空间的移动,从源地址src开始,移动n个字节到目的地址dest。
    
    void * memmove(void *dest, const void *src, size_t n);
    
    • dest:目的地址。
    • src:源地址。
    • n:移动的字节数。
    #include 
    #include 
    
    //实现删除数组中某一个元素,后序元素依次向前,返回新的元素个数。
    int deleteArrayByIdx(int *array, int idx, int count)
    {
        memmove(array + idx, array + idx + 1, (count - (idx + 1)) * sizeof(*array));
        return count - 1;
    }
    
    int main()
    {
        int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
        int count = sizeof(array) / sizeof(array[0]);
        count = deleteArrayByIdx(array, 2, count);
        for (int i = 0; i < count; i++)
        {
            printf("%d\n", array[i]);
        }
        return 0;
    }
    

    输出:

    1
    2
    4
    5
    6
    7
    8
    9
    0
    

    memcmp

    实现两段内存的比较,从地址src1开始,比较n个字节,如果相同,返回0,如果不同,返回第一个不同的字节的差值。

    int memcmp(const void *src1, const void *src2, size_t n);
    
    • src1:源地址1。
    • src2:源地址2。
    • n:比较的字节数。

    memchr

    查找一段空间中的一个字符,若存在则返回,所查找到字符的指针,若无,返回 NULL。

    void * memchr(const void *s, int c, size_t n);
    
    • s:源地址。
    • c:要查找的字符。
    • n:查找的字节数。

    memset

    将一段空间中的字节设置为指定的值,返回指向修改后的空间的指针。最小单位是字节

    void * memset(void *s, int c, size_t n);
    
    • s:源地址。
    • c:要设置的字符。
    • n:设置的字节数。
    #include 
    #include 
    int main()
    {
        
        char buf[1024];
        //memset(buf,0,1024); //将buf数组中所有元素设置为0
        memset(buf,0,1024*sizeof(char)); //这样作更安全
        //memset(buf,'a',1024); //这样作很危险 因为会将buf数组中所有元素设置为'a'
        printf("buf = %s \n",buf);
        strcpy(buf,"china is great\n");
        printf("buf = %s \n",buf);
        int array[10];
        //memset 函数将整型数组中的每个字节设置为十进制数值 1
        //整型数组 array 的每个元素通常占用4个字节(32位),因此memset函数会将每个4字节的区块都设置为十进制数值 16843009。\
        //十进制数值 16843009 对应的二进制表示是 00000001000000010000000100000001
        memset(array,1,10*sizeof(int));//hex 01010101 -> dec 1684 3009
        for(int i=0; i<10; i++)
        {
            printf("%d\n",array[i]);
        }
        return 0;
    }
    

    输出:

    buf =
    buf = china is great
    
    16843009
    16843009
    16843009
    16843009
    16843009
    16843009
    16843009
    16843009
    16843009
    16843009
    

    y[10];
    //memset 函数将整型数组中的每个字节设置为十进制数值 1
    //整型数组 array 的每个元素通常占用4个字节(32位),因此memset函数会将每个4字节的区块都设置为十进制数值 16843009。
    //十进制数值 16843009 对应的二进制表示是 00000001000000010000000100000001
    memset(array,1,10*sizeof(int));//hex 01010101 -> dec 1684 3009
    for(int i=0; i<10; i++)
    {
    printf(“%d\n”,array[i]);
    }
    return 0;
    }

    输出:
    

    buf =
    buf = china is great

    16843009
    16843009
    16843009
    16843009
    16843009
    16843009
    16843009
    16843009
    16843009
    16843009

  • 相关阅读:
    基于 Iterative 映射和单纯形法的改进灰狼优化算法-附代码
    解决SpringBoot项目war部署到tomcat下无法Nacos中注册服务问题
    应用软件提取出来,打包成.EXE文件在别的电脑上能不能安装?
    Redis:StringRedisTemplate简介
    人工智能学习:CIFAR-10数据分类识别
    [C国演义] 第十七章
    nignx如何部署让前端不用清缓存就可以部署
    Java_汉诺塔
    Allegro设置Cline到Shape按照区域规则避让操作指导
    安卓版微信8.0.31内测版出炉:安装包变小,功能变多!
  • 原文地址:https://blog.csdn.net/gopher9511/article/details/139725878