内存布局与分配

部分转载自
https://blog.csdn.net/qq_29924041/article/details/54897204
和小甲鱼数据结构课程
内存布局规律:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
malloc 申请动态内存空间
void *malloc(size_t size);
malloc函数向系统申请分配size个字节的内存空间,并返回一个指向这空间的指针

void *,表示未确定类型的指针。
C,C++规定,void *类型可以强转为任何其他类型的的指针。

如果分配成功:则返回指向被分配内存空间的指针
不然,返回空指针NULL。
同时,当内存不再使用的时候,应使用free()函数将内存块释放掉。

void malloc1()
{
    int *ptr;
    ptr = (int *)malloc(sizeof(int));
    if (ptr == NULL)
    {
        printf("失败\n");
        exit(1);
    }
    printf("输入一个整数\n");
   scanf("%d",ptr);
   printf("%d\n",*ptr);


}//malloc申请的内存在堆上,不使用后要释放
//malloc还可以申请一块任意尺寸的内存空间
void malloc2()
{
    int *ptr=NULL;
    int i,num;
    printf("请输入待录入整数个数: \n");
    scanf("%d",&num);
    ptr=(int *)malloc(num*sizeof(int));
    for(i=0;i<num;i++)
    {
        printf("请录入第%d个整数:",i+1);
        scanf("%d",&ptr[i]);
    }
    printf("你录入的整数是:");
    for(i=0;i<num;i++)
    {
        printf("%d",ptr[i]);
    }
    putchar('\n');
    free(ptr);
}

free 释放动态内存空间
void free(void *ptr);

free() 可以释放由 malloc()、calloc()、realloc() 分配的内存空间,以便其他程序再次使用。
【参数说明】ptr 为将要释放的内存空间的地址。
free() 只能释放动态分配的内存空间,并不能释放任意的内存。
如果 ptr 所指向的内存空间不是由上面的三个函数所分配的,或者已被释放,那么调用 free() 会有无法预知的情况发生。
如果 ptr 为 NULL,那么 free() 不会有任何作用。
注意:free() 不会改变 ptr 变量本身的值,调用 free() 后它仍然会指向相同的内存空间,但是此时该内存已无效,不能被使用。所以建议将 ptr 的值设置为 NULL

void malloc1()
{
    int *ptr;
    ptr = (int *)malloc(sizeof(int));
    if (ptr == NULL)
    {
        printf("失败\n");
        exit(1);
    }
    printf("输入一个整数\n");
   scanf("%d",ptr);
   printf("%d\n",*ptr);
  free(ptr);
  printf("%d\n",*ptr);

}

内存泄露:
导致内存泄漏主要有两种情况:
隐式内存泄漏(即用完内存块没有及时使用free函数释放)
丢失内存块地址
用了内存后要释放,malloc和free要像大括号一样,有左就有右

初始化内存空间
由于 malloc 并不会帮你初始化申请的内存空间,所以你需要自己进行初始化。
当然你可以写一个循环来做这件事儿,但我不建议你这么做,因为标准库提供了更加高效的函数:memset。
以mem开头的函数被编入字符串标准库,函数的声明包含在string.h这个头文件中:
-memset --使用一个常量字节填充内存空间,初始化函数

#define N 10
int memset1(void)
{
     int *ptr=NULL;
     int i;
     ptr = (int*)malloc(sizeof(int));
     if(ptr == NULL)
        exit(1);
     memset(ptr,0,N*sizeof(int))//初始化,指向要初始化的内存块,初始化常量,内存块连续尺寸
    for(i=0;i<N;i++)
    {
        printf("%d ",ptr[i]);
    }
  free(ptr);
}

-memcpy --拷贝内存空间
-memmove–拷贝内存空间
-memcmp --比较内存空间
-memchr --在内存空间中搜索一个字符
处理字符串用str开头,处理内存空间用mem开头

calloc 申请并初始化一系列内存空间
void *calloc(size_t nmemb, size_t size);
比malloc多个初始化,此函数申请完空间后会把内存空间全部初始化为0

//如果想扩大空间可用memcpy
void memcpy1()
{
    int *ptr1=NULL;
    int *ptr2=NULL;

    //第一次申请的内存空间
    ptr1=(int *)malloc(sizeof(int));
    //ptr1空间不够用
    //第二次申请内存空间
    ptr2= (int *)malloc(sizeof(int));
    //将ptr1的数据拷贝到ptr2
    memcpy(ptr2,ptr1,10);//目标,源,拷贝数量
    free(ptr1);
    //ptr2操作后
    free(ptr2);
}

realloc 重新分配内存空间,与上有相同功能
void *realloc(void *ptr, size_t size);
函数概要:

  1. realloc 函数修改 ptr 指向的内存空间大小为 size 字节。
  2. 如果新分配的内存空间比原来的大,则旧内存块的数据不会发生改变;如果新的内存空间大小小于旧的内存空间,可能会导致数据丢失,慎用!
  3. 该函数将移动内存空间的数据并返回新的指针。
  4. 如果 ptr 参数为 NULL,那么调用该函数就相当于调用 malloc(size)。
  5. 如果 size 参数为 0,并且 ptr 参数不为 NULL,那么调用该函数就相当于调用 free(ptr)。
  6. 除非 ptr 参数为 NULL,否则 ptr 的值必须由先前调用 malloc、calloc 或 realloc 函数返回。

参数解析:

参数 含义
ptr 1. 指向由先前调用 malloc、calloc 或 realloc 函数返回的内存空间
2. 如果该参数为 NULL,相当于调用 malloc(size) 函数
size 指定新的内存块空间大小,以字节为单位

返回值:

  1. 如果函数调用成功,返回值是指向新的内存空间的指针,由于返回类型是 void 指针(void *),所以它可以被转换成任何类型的数据。
  2. 如果函数调用失败,返回值是 NULL。
  3. 如果 size 参数设置为 0,返回值也可能是 NULL,也可能返回一个指针值,稍后可以传递给 free 函数。
  4. 如果 realloc 函数调用失败,那么原始内存空间的数据并不会修改,也不会被释放或移动。
//根据用户输入需求不断拓宽内存空间
void realloc1()
{
    int i,num;
    int count = 0;
    int *ptr = NULL;//必须初始化为NULL,调用realloc第一个为NULL相当于调用malloc
    do
    {
        printf("请输入一个整数(输入-1表示结束):");
        scanf("%d",&num);
        count++;
        ptr=(int *)realloc(ptr,count*sizeof(int));
        if(ptr==NULL)
            exit(1);
        ptr[count-1]=num;//把数存放进去
    }
    while(num !=-1);
   printf("输入的整数为:");
   for(i=0;i<count;i++)
   {
       printf("%d",ptr[i]);
   }
   free(ptr);
}

int *func2()
{
    int *ptr=NULL;
    ptr=(int*)malloc(sizeof(int));//从堆里申请内存空间,把堆的地址返回,则打印出来的则是520,可在main函数内释放
    if(ptr==NULL)
    {
        exit(1);
    }
    *ptr=520;
    return ptr;
}

/堆与栈比较 与数据结构中的堆和栈不同/
//发展方向
/**• 堆和其它区段一样,都是从低地址向高地址发展
• 栈则相反,是由高地址向低地址发展
**/

void fazhan()
{
    int *ptr1 = NULL;//局部变量存在栈中
    int *ptr2 = NULL;

    ptr1 = (int *)malloc(sizeof(int));
    ptr2 = (int *)malloc(sizeof(int));

    printf("stack: %p -> %p\n",&ptr1,&ptr2);//栈
    printf("heap: %p -> %p\n",ptr1,ptr2);   //堆


} //可行

/**结果为:
stack:0060FF28->0060FF2C
heap:00652F90->00652FA0
**/
常见的内存错误:
1:段错误
使用未分配成功的内存
避免方式:在使用内存之前检查指针是否为NULL;
引用分配成功但尚未初始化的内存
避免方式:赋予初值,即便是赋予零值也不可省略
内存分配成功并且已经初始化,但操作越过了内存的边界
避免:注意下表的使用不能超出边界
忘记释放内存,造成内存泄露
避免方式:申请内存的方式和释放内存的方式需要成双成对
释放内存之后却继续去使用这一块内存
避免方式:使用free内存之后,把指针置为NULL;

内存错误的注意点:
指针消亡了,并不表示它所指向的内存会被自动释放,(在free之前,直接将指针设为NULL);
内存释放了,并不代表指针会消亡或者成了NULL指针;(在free之后,指针并没有进行NULL设置)

野指针:
野指针的形成是指针变量没有被初始化,任何指针变量刚被创建的时候不会自动成为NULL指针,它的缺省值是最忌的,它会乱指一气

指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法内存

free内存块之后,需要将指针设置为NULL,如果没有设置为NULL,也会出现“野指针”,它是指向“垃圾”内存的指针;

多次free内存块,是会导致程序崩溃的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值