目录
  • 一.为什么存在动态内存分配
  • 二.动态内存函数的介绍
    • 1.malloc和free
    • 2.calloc
    • 3.realloc
  • 三.常见的动态内存错误
    • 1.对NULL指针的解引用操作
    • 2.对动态开辟空间的越界访问
    • 3.对非动态开辟的空间使用free释放
    • 4.使用free释放一块动态开辟空间的一部分
    • 5.对同一块开辟的空间多次释放
    • 6.动态内存开辟忘记释放(内存泄漏)
  • 四.几个经典的笔试题

    一.为什么存在动态内存分配

    我们已经掌握的内存开辟方式有:

    int a = 10;//在栈空间开辟4个字节的连续空间
    int b[20] = { 0 };//在栈空间开辟20个字节的连续空间

    这种开辟空间的方式有以下特点:

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

    2.开辟数组时必须指定大小

    初学数组时,我写过下面的错误代码。

    int N;
    scanf("%d",&N);
    int a[N]={ 0 };

    可N是变量,不能用于数组元素个数的初始化。

    如果我们需要的空间大小在程序运行时才能知道,那就只能试试动态内存开辟了。

    二.动态内存函数的介绍

    1.malloc和free

    void* malloc (size_t size); 
    void free (void* ptr);

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

    若开辟成功,返回指向这块空间的指针

    若开辟失败,返回NULL指针,因此malloc的返回值一定要做检查

    使用完malloc函数要用free释放申请的内存空间

    #include<stdio.h>
    #include<stdlib.h>
     
    int main()
    {
    	int* p = (int*)malloc(40);//开辟40个字节的栈空间
    	if (p == NULL)            //检查是否为空指针
    	{
    		perror("malloc");
    		return 1;
    	}
    	for (int i = 0; i < 10; i++)
    	{
    		*(p + i)=i;
    	}
    	free(p);                 //用完后释放空间,注意参数为首地址
    	p = NULL;                //置为空指针
    }    

    2.calloc

    void* calloc (size_t num, size_t size)

    calloc的两个参数分别为申请元素的个数和每个元素的大小,

    使用和malloc差不多,但是申请的空间会被初始化为0,

    #include<stdio.h>
    #include<stdlib.h>
     
    int main()
    {
    	int* p = (int*)calloc(10, sizeof(int));
    	if (p == NULL)
    	{
    		perror("calloc");
    		return 1;
    	}
    	for (int i = 0; i < 10; i++)
    	{
    		printf("%d  ", *(p + i)); //输出为 10个0
    	}
    	free(p);
    	p = NULL;
    }

    3.realloc

    void* realloc (void* ptr, size_t size)

    realloc用于重新设置要开辟内存空间的大小,可以是增大或减小

    指针ptr是指向先前使用 malloc、calloc 或 realloc 分配的内存块的指针。

    size 是新开辟内存空间的大小

    若原空间后面未开辟的空间足够使用,则返回原先的起始地址

    C语言 超详细梳理总结动态内存管理

     若原空间后面未开辟的空间不足以填满新开辟内存空间,

    则会在某个地址开辟所需要的空间,free掉原空间的地址,

    并且返回新的地址的起始地址

    真 ·  一条龙服务

    C语言 超详细梳理总结动态内存管理

     若扩容失败,会返回空指针,因此也要检查是否是空指针

    三.常见的动态内存错误

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

    void test()
    {
        int *p = (int*)malloc(INT_MAX/4);
        *p = 20;
        free(p);
    }

    若p为空指针,则程序错误。

    解决方案:检查是否为空指针

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

    int main()
    {
    	int* p = (int*)calloc(10, sizeof(int));
    	if (p == NULL)
    	{
    		perror("calloc");
    		return 1;
    	}
    	for (int i = 0; i <= 10; i++)  //当i为10时,形成越界访问,程序出错
    	{
    		printf("%d  ", *(p + i));
    	}
    	free(p);
    	p = NULL;
    }

    使用这块空间时要注意是否已经越界访问

    3.对非动态开辟的空间使用free释放

        int a = 10;
    	int* p = &a;
    	free(p);

    一执行,程序崩溃了

    C语言 超详细梳理总结动态内存管理

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

    void test()
    {
    	int* p = (int*)malloc(100);
    	p++;
    	free(p);
    }

    同样会崩溃

    C语言 超详细梳理总结动态内存管理

    5.对同一块开辟的空间多次释放

    void test()
    {
    	int* p = (int*)malloc(100);
    	free(p);
    	free(p);
    }

    没错,又又又崩溃了,就不上图了

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

    如果使用空间后不释放,会导致内存泄漏。

    内存泄漏的堆积,这会最终消耗尽系统所有的内存。

    四.几个经典的笔试题

    第一个

    void GetMemory(char* p)            //对空指针解引用
    {
    	p = (char*)malloc(100);        //内存泄露
    }
    void test()
    {
    	char* str = NULL;
    	GetMemory(str);
    	strcpy(str, "hello world");    
    	printf(str);
    }
     
    int main()
    {
    	test();
     
    }

    p是str的一份临时拷贝,指向malloc申请的起始地址,

    出了函数之后,内存还给系统,str仍为空指针,strcpy把“hello world”放进空指针

    第二个

    char *GetMemory(void)
    {
    	char p[] = "hello world";
    	return p;
    }
    void test()
    {
    	char* str = NULL;
    	str=GetMemory();        //野指针str
    	printf(str);
    }
     
    int main()
    {
    	test();
     
    }

    定义字符串p,并返回p的地址

    但是当出了这个函数,内存还给系统,没有使用权限

    指针变为

    第三个

    void GetMemory(char** p,int num)            //传址调用
    {
    	*p = (char*)malloc(num);        
    }
    void test()
    {
    	char* str = NULL;
    	GetMemory(&str,100);
    	strcpy(str, "hello world");
    	printf(str);                                
                                                //没有free
    }
     
    int main()
    {
    	test();
     
    }

    打印hello world

    没有释放空间

    第四个

    void GetMemory(char** p,int num)
    {
    	*p = (char*)malloc(num);
    }
    void test()
    {
    	char* str = (char*)malloc(100);
    	strcpy(str, "hello world");
    	free(str);                            //还给你,我还要用,哼~
    	if (str != NULL)
    	{
    		strcpy(str, "!!!");
    		printf(str);
    	}
    }
     
    int main()
    {
    	test();
     
    }

    开辟100个字节的空间后,又把这块空间还给操作系统。

    再次把“!!!”放进这块空间,非法修改

    tips:动态内存管理是在堆区上进行的。

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。