C语言进阶——动态内存管理

目录

一、C语言底层内存知识补充

二、动态内存函数

1.1free

1.2malloc

1.3calloc

1.4realloc

三、使用常见错误

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

3.2空指针未判断造成的错误

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

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

3.5动态开辟内存没有释放而造成内存泄露

3.6已开辟空间的越界访问

四、典型习题练习


一、C语言底层内存知识补充

  1. 栈区:栈区主要存放函数运行中分配的局部变量函数参数、返回数据、返回地址等。
  2. 堆区:⼀般由程序员分配释放(比如本讲的动态内存管理), 若程序员不释放,程序结束时可能由操作系统回收。
  3. 静态区:存放全局变量静态数据。程序结束后由系统释放。
  4. 代码段:存放函数体的⼆进制代码。

二、动态内存函数

1.1free

void free (void* ptr);
  1. 功能:⽤来做动态内存的释放和回收。
  2. 注意事项:
    1.如果参数 ptr 指向的空间不是动态开辟的,那free函数使用错误。
    2.如果参数 ptr 是NULL,则函数无效。
  3. 代码示例:会在其他函数示例时使用

1.2malloc

void* malloc (size_t size)
  1. 功能:向内存申请⼀块连续可⽤的空间 
  2. 返回值:若开辟成功-返回所开辟空间的指针;若开辟失败-返回NULL
  3. 注意事项:函数返回值为void*意味着不能直接进行解引用等操作。建议使用前进行强制类型转换
  4. 示例代码:

int main()
{
	int* p = (int*)malloc(20);
	//确保空间开辟成功后使用
    if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//使用空间
	for (int i = 0; i < 5; i++)
	{
		*(p + i) = i + 1;
	}
	//释放内存
	free(p);
	p = NULL;
}

1.3calloc

void* calloc (size_t num, size_t size);
  1. 功能:为 num 个⼤⼩为 size 的元素开辟⼀块空间,并把空间的每个字节初始化为0。
  2. 返回值: 若开辟成功-返回所开辟空间的指针;若开辟失败-返回NULL
  3. 注意事项:函数返回值为void*意味着不能直接进行解引用等操作。建议使用前进行强制类型转换
  4. 代码示例
int main()
{
    int* p = (int*)calloc(5, sizeof(int));
    if (p == NULL)
    {
	    perror("calloc");
	    return 1;
    }
    //使用空间
    for (int i = 0; i < 5; i++)
    {
	    printf("%d", *(p + i));
    }
    //释放内存
    free(p);
    p = NULL;
}

1.4realloc

void* realloc (void* ptr, size_t size);
  1. 功能:用来调整动态开辟内存的大小。
  2. 返回值:若成功-调整之后的内存空间首地址;若失败-返回NULL
  3. 细节解释:
    1.若原有空间之后有⾜够⼤的空间:直接在原有内存之后扩展空间,原来空间的数据不发⽣变化。函数返回传入的原地址即可。
    2.若原有空间之后没有⾜够⼤的空间:在堆空间上另找⼀个合适⼤⼩ 的连续空间来使⽤。函数返回⼀个新的内存地址
  4.  代码示例:
int main()
{
    int* ptr = (int*)realloc(p, 40);
    if (ptr != NULL)
    {
	    p = ptr;
	    //使用空间
        for (int i = 5; i < 10; i++)
	    {
		*(p + i) = i + 1;
	    }
    }
    else
    {
	    perror("realloc");
	    return 1;
    }
    //释放空间
    free(p);
    p = NULL;
}

三、使用常见错误

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

int main()
{
    int a = 10;
    int *p = &a;
    free(p);
}

3.2空指针未判断造成的错误

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

应该效仿前文的代码,加上对空指针的判断 

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

int main()
{
    int *ptr = (int *)malloc(100);
    ptr++;
    free(ptr);    //ptr不再指向动态内存的起始位置
}

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

int main()
{
    int *ptr = (int *)malloc(50);
    free(ptr);
    free(ptr);    //重复释放
}

3.5动态开辟内存没有释放而造成内存泄露

动态开辟内存后必须用free释放,定义的指针必须置为空指针

3.6已开辟空间的越界访问

int main()
{
    int i = 0;
    int *p = (int *)malloc(10*sizeof(int));
    if(NULL == p)
    {
       exit(EXIT_FAILURE);
    }
    for(i=0; i<=10; i++)
    {
        *(p+i) = i;
    }
    free(p);
}

四、典型习题练习

  • 调用函数后返回的指针指向的空间被系统销毁,无法接收到数据。
    char *test(void)
    {
        char p[] = "hello world";
        return p;
    }
    void Test(void)
    {
     char *ptr = NULL;
     ptr = test();
     printf(ptr);
    }
    
  • free函数不会将指针置为空指针,只会将开辟的空间还给操作系统
    int main
    {
        char *str = (char *) malloc(100);
        strcpy(str, "hello");
        free(str);
        if(str != NULL)              //str不为空指针进入函数
        {
            strcpy(str, "world");    //非法访问
            printf(str);
        }
    }

错误程序修改(使用二级指针)

void test(char** p , int num)
{
    *p = (char*)malloc(num);
}
int main()
{
    char* str = NULL;
    test(&str,100);
    strcpy(str,"hello world");
    printf(str);
    free(str);
    str = NULL;
}

  • 43
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值