首页 > 系统相关 >C语言进阶——动态内存管理

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

时间:2024-03-23 17:32:35浏览次数:33  
标签:进阶 str int free C语言 内存 动态内存 NULL ptr

目录

一、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;
}

标签:进阶,str,int,free,C语言,内存,动态内存,NULL,ptr
From: https://blog.csdn.net/paradiso989/article/details/136951903

相关文章

  • C语言——函数练习程序
    1.从终端接收一个数,封装一个函数判断该数是否为素数#include<stdio.h>intpri(intnum){inti=0;for(i=2;i<num;i++){if(num%i==0){return0;break;}}if(i==num-1)......
  • 【C语言】整数和浮点数在内存中的存储
    点这里是个人主页~这次的内容是比较底层的奥,对于理解编程很重要~整数浮点数在内存中的存储一、整数在内存中的存储二、大小端字节序和字节序判断大小端的概念一道简单关于大小端排序的百度面试题三、简单理解数据类型存储范围例一例二例三例四例五例六四、浮点......
  • C语言的算符优先级
    C语言中提供许多算符,比如算术运算、逻辑运算、关系运算等,必须规定它们的优先级,否则将它们放到一起运算肯定要出乱子,正如算术中有先乘除后加减的规则,C语言同样要有确定的运算规则。C语言定义了15个算符优先级,其优先级规则如下:规则1:优先级高的先运算规则2:同一个优先级则需要按照结......
  • C语言 03 原码 反码 补码
    原码计算机中所有的数字都是使用0和1这样的二进制数来进行表示的。这时如果要存储一个数据,比如十进制的3,那么就需要使用2个二进制位来保存,二进制格式为11,占用两个位置,称为2bit位。一般占用8个bit位表示一个字节(B),2个字节等于1个字,所以一个字表示16个bit位......
  • C语言字符函数和字符串函数及内存函数详解(干货小知识:常用函数的模拟实现)
    文章目录1.字符函数1.1字符分类函数1.2字符转换函数2.字符串函数2.1strlen函数2.1.1strlen函数的使用:2.1.2strlen函数的模拟实现2.2strcpy函数2.2.1strcpy函数的使用2.2.2strcpy函数的模拟实现2.3strcat函数2.3.1strcat函数的使用2.3.2strcat函数的模拟实......
  • PAT乙级 1062 最简分数 C语言
    最简分数一个分数一般写成两个整数相除的形式:N/M,其中M不为0。最简分数是指分子和分母没有公约数的分数表示形式。现给定两个不相等的正分数N1​/M1​和N2​/M2​,要求你按从小到大的顺序列出它们之间分母为K的最简分数。输入格式:输入在一行中按N/M的格式给出两个......
  • PAT乙级 1055 集体照 C语言
    集体照拍集体照时队形很重要,这里对给定的N个人K排的队形设计排队规则如下:每排人数为N/K(向下取整),多出来的人全部站在最后一排;后排所有人的个子都不比前排任何人矮;每排中最高者站中间(中间位置为m/2+1,其中m为该排人数,除法向下取整);每排其他人以中间人为轴,按身高......
  • PAT乙级 1054 求平均值 C语言
    本题的基本要求非常简单:给定N个实数,计算它们的平均值。但复杂的是有些输入数据可能是非法的。一个“合法”的输入是[−1000,1000]区间内的实数,并且最多精确到小数点后2位。当你计算平均值的时候,不能把那些非法的数据算在内。输入格式:输入第一行给出正整数N(≤100)。随......
  • 摸爬滚打半年,我是如何从小白进阶到渗透测试工程师
    前言工作也好几年了,在这摸爬滚打中,遇到了服务器被黑,网站被人DDOS攻击,数据库被篡改等等。服务器也不是你说不让人上就不让人上的,所以IT安全这个话题还是比较沉重的,涉及的东西很多,只有你了解得更多,你才会知道你所了解的安全其实是那么少。【点此开始渗透学习】梦想的开始......
  • 0基础学习C语言第一章:常量与变量详解
    一、常量定义:在程序运行过程中,其值不能被改变的量称为常量。常用常量有以下几类:1.整型常量十进制整数形式例如:234,-1232.实型(浮点型)常量十进制小数形式:由数字、小数点组成例如:2.345、-23.345指数形式:如:1.23e2(相当于1.23x10²)由于在计算机输入输出时,无法表示上角......