为了能到远方,脚下的每一步都不能少.|

Yasuo_Hasaki

园龄:1年1个月粉丝:2关注:0

2024-02-18-物联网C语言(6-动态内存申请)

6.动态内存申请

6.1 动态分配概述

​ 在数组一章中,介绍过数组的长度是预先定义好的,在整个程序中固定不变,但是在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定

​ 为了解决上述问题,C语言提供了-些内存管理函数,这些内存管理函数可以按需要动态的分配内存空间,也可把不再使用的空间回收再次利用。

**动态分配内存就是在堆区分配空间**

6.2 静态分配、动态分配

静态分配
1、在程序编译或运行过程中,按事先规定大小分配内存空间的分配方式。int a[10]
2、必须事先知道所需空间的大小
3、分配在栈区或全局变量区,一般以数组的形式
4、按计划分配

动态分配
1、在程序运行过程中,根据需要大小自由分配所需空间
2、按需分配
3、分配在堆区,一般使用特定的函数进行分配

6.3 动态分配函数

  1. malloc函数

    #include <stdlib.h>
    void *malloc(unsigned int size);
    // 功能:在堆区开辟指定长度的空间
    // 参数:
    // size:要开辟的空间的大小返回值:
    // 成功:开辟好的空间的首地址
    // 失败:NULL

    注意
    1. 在调用 malloc之后,一定要判断一下,是否申请内存成功
    2. 如果多次 malloc,申请的内存,第1次和第2次申请的内存不一定是连续的
    3. 使用malloc开辟空间需要保存开辟好的空间首地址,但是不确定空间的用途,所以本身的返回值是void *,使用的时候需要根据实际情况进行强制类型转换

    #include <stdio.h>
    #include <stdlib.h>
    char *func(){
    //char ch[100]= "hello world";
    //静态全局区的空间只要开辟好,除非程序结束,否则不会释放,所以//如果是临时使用,不建议使用静态全局区的空间
    //static char ch[100]= "hello world";
    //堆区开辟空间,手动申请手动释放,更加灵活
    char *str =malloc(100 *sizeof(char));
    str[0] = 'h';
    str[1] = '\0';
    return str;
    }
    int main(int argc, char const *argv[])
    {
    char *p;
    p = func();
    printf("p = %s\n",p);
    return 0;
    }

    输出结果

    p = h
  2. free函数(释放内存函数)

    头文件:#include <stdlib.h>
    函数定义:void free(void *ptr)
    功能:只能释放堆区的空间
    参数:ptr ,开辟后使用完毕的堆区空间首地址
    返回值:无
    #include <stdio.h>
    #include <stdlib.h>
    char *func(){
    //char ch[100]= "hello world";
    //静态全局区的空间只要开辟好,除非程序结束,否则不会释放,所以//如果是临时使用,不建议使用静态全局区的空间
    //static char ch[100]= "hello world";
    //堆区开辟空间,手动申请手动释放,更加灵活
    char *str =malloc(100 *sizeof(char));
    str[0] = 'h';
    str[1] = '\0';
    return str;
    }
    int main()
    {
    char *p;
    p = func();
    printf("p = %s\n",p);
    // 使用free释放空间
    free(p);
    // 防止野指针
    p = NULL;
    return 0;
    }

    注意:

    1. free函数只能释放堆区的空间,其他区域的空间无法使用free
    2. free释放空间必须释放malloc或者calloc或者reloc的返回值对应的空间,不能说只释放一部分free(p)
    3. 当free后,因为没有给p赋值,所以p还是指向原先动态申请的内存。但是内存已经不能再用了,p变成野指针了,所以一般为了放置野指针,会free完毕之后对p赋为NULL
    4. 一块动态申请的内存只能free一次,不能多次free
  3. calloc函数

    头文件:#include <stdlib.h>
    函数定义:void *calloc(size_t nmemb,size_t size)
    功能:在堆区申请制定大小的空间
    参数:
    nmemb:要申请的空间块数
    size:每块的字节数
    返回值:
    成功:申请空间的首地址
    失败:NULL

    注意:
    malloc 和 calloc函数都是用来申请内存的。
    区别:

    1. 函数的名字不一样
    2. 参数的个数不一样
    3. malloc 申请的内存,内存中存放的内容是随机的,不确定的,而 *calloc函数申请的内存中的内容为0
    // 在堆中申请了3块,每块大小为 100个字节,即 300个字节连续的区域
    char *p=(char *)calloc(3,100);
  4. realloc函数(重新申请内存)

    在调用 malloccalloc函数单次申请的内存是连续的,两次申请的两块内存不一定连续。

    有些时候有这种需求:先用 malloc 或者 calloc,申请了一块内存,还想在原先内存的基础上挨着申请内存。或者开始时候使用 malloc 或 callo 申请了一块内存,再释放后边的一部分内存。

​ 为了解决这个问题,就发明了realloc这个函数。

头文件 #include<stdlib.h>
函数的定义: void* realloc(void *s,unsigned int newsize);
参数:
s - 原本开辟好的空间首地址
newsize - 重新开辟空间的大小
返回值:
新的空间的首地址
函数的功能: 在原先s指向的内存基础上重新申请内存,新的内存的大小为 new size 个字节
1. 如果原先内存后面有足够大的空间,就追加;
2. 如果后边的内存不够用,则relloc函数会在堆区找一个 newsize个字节大小的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新内存的地址。
char *p;
p = (char *)malloc(100);
// 在100个字节后面追加50个字节
p = (char *)realloc(p,150);
// 将100个字节减少到50个字节
p = (char *)realloc(p,50);

注意:malloc calloc relloc 动态申请的内存,只有在fee或程序结束的时候才释放。

6.4 内存泄露

​ 内存泄露的概念: 申请的内存,首地址丢了,找不了,再也没法使用了,也没法释放了,这块内存就被泄露了。

案例1

int main(){
char *p;
p=(char *)malloc(100);
//接下来,可以用p指向的内存了
p="hello world";//p指向别的地方了
//从此以后,再也找不到你申请的100个字节了,则动态申请的100个字节就被泄露了
return 0;
}

案例2

void fun(){
char *p;
p=(char *)malloc(100);//接下来,可以用p指向的内存了
}
// 不断地申请空间,导致内存炸裂
int main() {
fun();
// 后面每次调用一次fun泄露100个字节
fun();
fun();
...
return 0
}

解决方式:

  1. 申请的空间使用完毕后,使用free释放空间,指针指向NULL
  2. 可以将内存空间地址返回,然后释放,指针指向NULL
posted @   Yasuo_Hasaki  阅读(10)  评论(0编辑  收藏  举报
//雪花飘落效果
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起