简单学习一下C语言中的动态内存管理

目录

1.malloc 和 free

1.1 malloc函数

1.2 free函数

2. calloc函数

3. realloc函数

3.1realloc函数使用的注意事项:

4. 动态内存开辟的常见错误

4.1 对NULL进行解引用操作

4.2 对动态内存开辟的越界访问

4.3 对非动态内存开辟空间使用free函数

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

4.5 对同一块动态开辟内存进行多次释放

4.6 对动态开辟内存的忘记释放


1.malloc 和 free

1.1 malloc函数

malloc函数的头文件为stdlib.h

函数原型:

void* malloc(size_t size)  //开辟内存块,size为要几个字节大小;

示例:

int main()
{
    //向内存申请10个整形空间;
    int* p=(int*)malloc(10*sizeof(int));  //返回值为申请的空间的地址,需要强制类型转换;
    if(p==NULL)
    {
        printf("%s\n",strerror(errno));  //会报出对应的错误信息,即为什么内存开辟失败;
    }
    else
    {
        //正常使用空间;
        int i=0;
        for(i=0;i<10;i++)
        {
            *(p+i)=i;
        }
        for(i=0;i<10;i++)
        {
            printf("%d\n",*(p+i));
        }
    }
    //当申请的空间不再使用的时候
    //应该还给操作系统
    return 0;
}

1.2 free函数

free函数是专门用来做动态内存的回收和释放的;

函数原型为:

void free(void* ptr);

free函数用于释放动态内存开辟的内存。

·如果参数ptr指向的空间不是动态开辟的,free的行为就是未定义的;

·如果ptr是NULL指针,则函数什么事都不做;

示例:

int main()
{
    //向内存申请10个整形空间;
    int* p=(int*)malloc(10*sizeof(int));  //返回值为申请的空间的地址,需要强制类型转换;
    if(p==NULL)
    {
        printf("%s\n",strerror(errno));  //会报出对应的错误信息,即为什么内存开辟失败;
    }
    else
    {
        //正常使用空间;
        int i=0;
        for(i=0;i<10;i++)
        {
            *(p+i)=i;
        }
        for(i=0;i<10;i++)
        {
            printf("%d\n",*(p+i));
        }
    }
    //当申请的空间不再使用的时候
    //应该还给操作系统
    free(p);   //当程序结束时,动态内存开辟的空间也会还回去,free就是主动还回去
    p=NULL;  //free过后p并没有发生变化,还是指向开辟的那块空间,为了防止那块空间被再次利用,就将p赋值为空指针;
    //malloc 和 free 函数要成对使用;
    return 0;
}

2. calloc函数

开辟一个数组在内存中,元素初始化为0;

函数原型:

void* calloc(size_t num,size_t size)

示例:

int main()
{
    // malloc(10*sizeof(int));
    int* p=(int*)calloc(10,sizeof(int));//几个元素,每个元素多少个字节;
//开辟失败时,同样返回空指针
    if(p==NULL)
    {
        printf("%s\n",strerror(errno));
    }
    else
    {
        int i=0;
        for(i=0;i<10;i++)
        {
            printf("%d",*(p+i));  //打印结果都是0;
        }
    }
    //释放空间
    free(p);
}

malloc和calloc函数的区别在于,malloc效率高,但不初始化;calloc效率低,但初始化;

3. realloc函数

函数原型:

void* realloc(void* ptr,size_t size); 

realloc函数的出现,让动态内存管理更加灵活

realloc可以对动态开辟内存的大小进行调整

ptr是要调整的内存地址,size是调整之后的新大小,返回值为调整好之后的内存起始地址,这个函数在调整原内存空间的基础上,还会将原来内存中的数据移动到新的空间。

示例:

int main()
{
    int* p=(int*)malloc(20);
    if(p==NULL)
    {
        printf("%s",strerror(errno));
    }
    else
    {
        int i=0;
        for(i=0;i<5;i++)
        {
            *(p+i)=i;
        }
    }
    //此时在使用malloc开辟的20个字节的空间;
    //假设这里,20个字节不能满足我们的需求
    //希望有40个字节空间
    //此时可以使用realloc来调整内存;
    int* ptr=(int*)realloc(p,40);
    if(ptr!=NULL)
    {
        ps=ptr;
         int i=0;
    for(i=0;i<10;i++)
    {
        printf("%d ",*(ps+i));
    }
    }
    free(ps);
    ps=NULL;
    return 0;
}

3.1realloc函数使用的注意事项:

 1.如果p指向空间之后有足够的内存空间可以追加,则直接追加,后返回p;
 2.如果p指向空间之后没有足够的内存空间可以追加,则realloc会重新找一个新的内存区域开辟一块满足需求的空间,并把原来内存中的数据拷贝过来,释放原来的内存空间,最后返回新开辟的内存空间地址;
 3.得用一个新的变量来接受realloc的返回值

4. 动态内存开辟的常见错误

4.1 对NULL进行解引用操作

示例:

int* p=(int*)malloc(40);
//这里是有可能会开辟失败的,这个时候p就是空指针,下面就是对空指针进行解引用;
int i=0;
for(i=0;i<10;i++)
{
    *(p+i)=i;
}

4.2 对动态内存开辟的越界访问

示例:

int *p=(int*)malloc(5*sizeof(int));
if(p==NULL)
{
    return 0;
}
else
{
    int i=0;
    for(i=0;i<10;i++)  //造成越界访问了,5个元素放了10个元素;
    {
        *(p+i)=i;
    }
}
free(p);
p=NULL;

4.3 对非动态内存开辟空间使用free函数

示例:

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

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

示例:

int main()
{
    int *p=(int*)malloc(40);
    if(p=NULL)
    {
        return 0;
    }
    int i=0;
    for(i=0;i<10;i++)
    {
        *p++=i;
    }
    free(p);
    p=NULL;  //错误原因就是p指向的变成后面的空间了,++使得p指向地址以及发生改变;
}

4.5 对同一块动态开辟内存进行多次释放

int main()
{
    int* p=(int*)malloc(40);
    if(p=NULL)
    {
        return 0;
    }
    free(p);  //用完后将p置为空指针,可以防止多次释放;
    //·····
    free(p);
    return 0;
}

4.6 对动态开辟内存的忘记释放

//内存泄漏
int main()
{
    while(1)
    {
        malloc(1);
    }
}

猜你喜欢

转载自blog.csdn.net/yss233333/article/details/124073044