指针中--【内存申请与释放】变量与空间//内存分配与释放//基本数据类型空间的申请与使用//数组与malloc关系// calloc realloc的使用区别

1.3.4  内存申请与释放

1.3.4.1 变量与空间

1.3.4.1.1 宏观上

  1. 多个程序同时运行是怎么个情况
  2. 所有程序/软件(程序=软件一个面对用户一个面对程序员)的运行,是由操作系统统一调配的。操作系统是程序的运行环境。
  3. 运行中的多个程序之间,内存是不交叉的
  4. 程序结束,操作系统还要释放其使用的资源
  5. 不释放会咋样?资源会被一直占用,别的程序无法使用了。

1.3.4.1.2  微观上

a、程序里定义的变量,申请的空间

申请在哪块内存区域?

由谁申请?

什么时候释放?

由谁释放?

b、什么是栈(堆栈就是栈)区?

内存由五部分组成:为啥分这么多区域?这跟公司差不多,部门分的细致,工作分发的就有针对性,效率就会高。

  1. 栈区

特点:

内存由系统申请,在变量生命周期结束时由系统释放。

生命周期:定义到释放。不是所有的变量在程序结束时(软件关闭时)才释放,服务器例子。

  1. 堆区

特点:

由我们随时申请,由我们自己随时释放比如:int等

  1. 全局区
  2. 字符常量区
  3. 代码区

1.3.4.2 内存分配与释放

1.3.4.2.1  malloc分配函数介绍

a、malloc函数前述

  1. 概念

malloc的全称是memory allocation,中文叫动态内存分配,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存,且分配的大小就是程序要求的大小。

  1. 功能

堆区申请指定大小连续的 一段空间,并返回该空间的首地址。

这个函数的操作类似于数组。

  1. 举例子

int *p = (int*)malloc (4);//malloc先申请一个4字节的空间,可以是float或其他类型,(返回的是一个首地址值),所以用int*标志(也称强制类型转换)然后装到p里面。即:申请的这个空间是一个int型的空间,一次访问4个字节。

或者

int *p ;

p = (int*)malloc (4);

  1. 函数参数

就是要申请的字节数

malloc( )里面是一个整型表达式:5  2*2  sizeof(int)*n 等

size_t:

32编译器环境unsigned int        sizeof size_t  4字节

64编译器环境long unsigned int    sizeof size_t  8字节

  1. 头文件

stdlib.h

malloc.h

b、malloc函数使用

  1. 对三种情况进行讨论

malloc(正常):内存碎片,这个就是正常申请空间

malloc(0):这个一般不会做,因为申请0空间没有意义,但是会返回一个地址,0表示该地址起多少个空间可用

malloc(极限):这个是申请空间过大,超过系统内存大小!申请失败会返回 一个地址,NULL 也就是0,相当于没有空间!没申请到,这个一般是内存不够用了。NULL 就是申请空间的一个返回值,NULL=0.

注意:所以一般,在申请空间这里,使用指针前加个判断,并作一些提示。

if (NULL==p)//也就是判断指针地址是否是0,申请是0的时候就是失败

{

printf(“申请空间失败”);

}

  1. 强制类型转换:

形式:(类型*)//VS()可以不写,最好写上,移植性高

概念:malloc就是返回的void* ,所以可以转换成我们想要的类型,操作。就是申请一个int类型空间,但是可以转换成其他类型空间。

  1. *P的使用

类比:

int a;

int *p1 = &a;

*p1 == a;

对于:int *p2 =(int*) malloc(4);  //malloc申请回来一个地址,相当于&a,malloc的空间没有名字

*p2 == 这个空间 //相当于 a

  1. 内存空间赋值

方式一、内存空间全部赋值0

int *p = (int*)malloc (40);//申请40个字节,相当于10个元素。这个操作和数组一样!!!

int i;

for(i=0;i<10;i++)

{

p[i]=0;//赋值每个元素为0

}

for(i=0;i<10;i++)

{

printf(“%p”,p[i]);//输出结果都是0

}

方式二、内存空间赋值函数memset(效果和上面一样)

这是内存赋值,按字节来赋值,一个字节一个赋值!!!(1字节=8位)

头文件:memory.h

memset(p,0,40);//效果和上面一样,输出是0

memset(p,1,40);//这个输出就不是1了,因为是按字节赋值,赋值1就是四个字节即:1111(4字节),换成8位,1111就是00000001  00000001 00000001  00000001八位,按十进制:16843009

  1. 注意点:

1、千万别越界:比如你要申请四字节当作int使用,千万别申请三个

不会像数组报错,malloc不会报错!

2、一个指针指向了一块堆区空间,千万不要再指向另一块

会导致内存丢失,(因为已经申请过了,但是指针名字被覆盖了)造成内存泄漏,也就是一块空间没有用,丢失了。

当用一个新的指针记录这个地址后,原来的指针就可以解放。(因为有名字了,可以释放)

 

1.3.4.2.2 free释放函数介绍

b)free函数使用

  1. 形式:free(p);//这样就完事了没有返回值
  2. 参数p:p就是malloc申请的返回值,要释放的空间的指针
  3. 释放:释放只是释放堆中的数据,但是栈中仍然存在指针变量

例子:

int *p = (int*)malloc(4);

*p = 12;

printf("%p  %d\n",p ,*p);// 00E58FC8  12

free(p);

p=NULL;//指针复位

printf("%p  %d\n", p, *p); //00E58FC8  17891602

  1. 注意点:

在free之后,p地址在,但是数据不在额

所以在实际项目中,一般指针释放后,赋值一个NULL; 一个指针赋值NULL了,就叫空指针=0=NULL(指针复位),不赋值0语法没错,只是存在隐患。

所指向的空间访问受限,叫野指针,这个东西不能直接使用不能操作。

不能重复释放同一块空间//free(p); free(p);

不能释放栈区空间//比如释放int a这个应该是操作系统自己释放,不能人为

一定要释放头指针//释放从前到后(一个空间:头地址+字节数),必须是这个空间的头地址

  1. 崩溃情况:

malloc运行中的崩溃,一定是某一行具体的代码引起的,大家一定要找到。

运行结束的崩溃,基本就是内存越界操作了。非常难找,所以大家一定要小心,细心的使用指针,

 

1.3.4.3 基本数据类型空间的申请与使用

int *p = (int*)malloc(4);

short *p1 = (short*)malloc(sizeof(short));

float *p2 = (float*)malloc(4);

double *p3 = (double*)malloc (8);

long *p4 = (long*)malloc(sizeof(long));

1.3.4.4 数组与malloc关系

1.3.4.4.1  申请一维数组和malloc

特点

  1. 栈区数组:

一段连续的空间,数组名字是首元素的首地址,类型不变,定义什么就是什么!

  1. 堆区数组

那我们malloc一段空间(这时是没有类型的,即:可以任意定义类型),然后记住首地址,malloc回的空间时灵活的,类型可以变。

定义

  1. 形式:

int* p =(int*)malloc(sizeof(int)*5);//  4*5这个不能初始化

p就装着首地址,p+1就是第二个元素,......

这个不能初始化(可以用memset赋值成0或者用循环赋值任意值)

  1. 访问:

*(p+0)==*p   *(p+1)  *(p+2)   *(p+3)   *(p+4)

公式  *(p+n) = p[n]  

  1. malloc的数组与int a[3]这种栈区数组的区别:

定义有点儿不一样,使用一模一样,  malloc需要free

1、malloc的数组可任意指定长度

int a;

int* p;

scanf("%d", &a); //可以在运行过程中指定任意大小

p =(int*)malloc(a);//动态数组,动态分配空间

2、int a[2];就不一样了,个数在定义时候确定,以后就不能修改了

1.3.4.4.2一维数组指针接这个空间

#include<stdio.h>

#include<stdlib.h>

#include<malloc.h>

int  main(void)

{

int i;

int(*p)[5] = (int(*)[5])malloc(sizeof(int) * 5);//不加p:(*)[ ]就表示数组指针的类型,加p就是指针的变量

//利用栈区数组对比学习:

(int(*)[5])malloc(sizeof(int)* 5); 这意义和 &a一样就是数组的地址

//int a[5];

//int (*p1)[5] = &a;//数组的指针

*(*p + 0) = 1;//*p==a 就是首元素的地址

*(*p + 1) =2;// *p+1=a+1就是加一个元素的地址  所以加*(*p+1)

*(*p + 2) = 3;

*(*p + 3) = 4;

*(*p + 4) = 5;

//记住三句话:

//1、数组名字是数组的首元素的首地址

//2、*(p+n)==p[n]

//3、一个指针指向一个变量或者空间  *这个指针就是这个变量或者空间

for (i = 0; i < 5; i++)

{

printf("%d\n",(*p)[i]);

}

free(p );//这个和malloc是一套的

system("pause");

return 0;

}

1.3.4.4.3二维数组指针接这个空间

int (*p)[2][3] = (int (*)[2][3])malloc(2*3*4);

类比栈区二位数组:int  a[2][3];

int (*p)[2][3] = &a;

访问:*(*(*p+1) + 2)== (*p)[1][2] *(*p+2)  套用公式:*(p+n)==p[n]

 

 

//二维数组:

int i, j;

int(*p)[1][2] = (int(*)[1][2])malloc(sizeof(int)* 2*3);//(*)[]表示数组指针的类型

//类比二维数组:(int(*)[5])malloc(sizeof(int)* 5); 这意义和 &a一样就是数组的地址

//int a[2][3];

//int (*p1)[2][3] = &a;二维数组的指针

(*p)[0][0] = 1;//*p==a 就是首元素的地址

(*p)[0][1] = 2;// *p+1=a+1就是加一个元素

(*p)[0][2] = 3; //一定加()/对于*p[][]表示p先与*结合表示指针类型,不然p[][]结合就是先表示为数组

(*p)[1][0] = 4;

(*p)[1][1] = 5;

(*p)[1][2] = 6;

//记住三句话:

//1、数组名字是数组的首元素的首地址

//2*(p+n)==p[n]

//3、一个指针指向一个变量或者空间  *这个指针就是这个变量或者空间

for (i = 0; i < 2; i++)

{

for (j = 0; j < 3; j++)

{

printf("%d\n", (*p)[i][j]);

}

}

free(p);//这个和malloc是一套的*/

1.3.4.5 calloc  realloc

1.3.4.5.1 calloc

功能:申请一段空间数组

形式举例:int* p = (int*)calloc(5, 4); //五个元素,一个元素占四字节

头文件:<stdlib.h> and <malloc.h>

特点:每个元素会被初始化成0

1.3.4.5.2 realloc

功能:重新分配内存的大小(在原来的空间后面连续操作),原来8字节,重新分配成100字节或者5字节

如果该内存地址起有足够的内存,那么内存首地址p1 == p;

如果该内存地址起没有足够的内存,那么内存首地址p1 != p;  即p1有新的地址了,前面所有的数据复制进新空间

参数1是内存块的起始地址,参数二是重新分配的大小空间值。

int *p1;//定义一个指针变量

int* p = (int*)malloc(20);//五个元素,一个元素占四字节

size_t a = _msize(p);//_msize()就是输出malloc申请空间的大小

printf("%d",a );

 p1 =(int*) realloc(p, 1000);//重新给malloc分配空间大小,这个地址p1和p一样,只不过realloc也返回一个值p1(地址)

 size_t a1 = _msize(p1);//_msize()就是输出malloc申请空间的大小

printf("%d", a1);

注意点: 和 malloc一样, 最重要的就是别越界,都是操作指针的!

 

1.3.4.5.3 msize函数

就是输出malloc空间的大小

查看 malloc申请的空间的字节数

1.3.4.5.3 calloc与malloc怎么选择

  1. 使用场景

calloc申请数组挺好用

其他的数据结构,比如链表,树,图,一次申请sizeof(节点),这些用malloc更合适。

  1. 初始化

calloc清零方便省事儿malloc不清零

  1. 效率问题

calloc会初始化内存,所以申请的内存数很多的时候,效率会低一点点。毕竟有时候内存不需要初始化,malloc这就效率高一些,也属于强行解释,效率问题也是微乎其微。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值