0%

malloc函数

malloc函数向内存申请一块练习的内存空间

  • 若开辟成功,返回开辟的空间的指针
  • 若开辟失败,返回NULL
  • 返回值是void*,所以malloc并不知道开辟的空间的类型,在使用开辟的空间时需要强转
  • 在开辟完空间后,要记得释放空间
  • 开辟0字节的空间在标准中是未定义的,取决于编译器。

函数声明:

1
void* malloc (size_t size);//返回值类型是void*

函数的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
int *a=(int*)malloc(sizeof(int)*10);//开辟了40字节的空间
if(a==NULL)
{
perrot("malloc");
return 1;
}
free(a);//开辟后要释放
//在free后,要把指针置NULL,因为free后,指针还记得分配的空间的地址,指针还是能找到这块空间,但是此时这块空间已经不属于当前程序了,所以,如果不置NULL,指针就会变成野指针。
a=NULL
return 0;
}

calloc函数

calloc函数与malloc函数的区别:calloc函数在申请空间的时候,会将空间中的值初始化为0

函数的声明:

1
void* calloc (size_t num, size_t size);//返回一个void*的指针

函数使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{

int* a=(int*)calloc(10,sizeof(int));//开辟10个大小为Int的空间
//此时若打印指针变量a指向的空间,会发现里面的值全是0
for(int i=0;i<10;i++)
{
printf("%d ",*(a+i));
}
free(a);
a=NULL;
return 0;
}

realloc函数

函数声明:

1
void* realloc (void* ptr, size_t size);//返回值类型是void*

当我们开辟完一快空间后,假如我们需要对这块空间的大小进行调整,那么此时就用到了realloc函数

我们可以通过realloc函数把空间缩小:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
int main()
{
int *p=(int*)calloc(10,sizeof(int));
assert(p);//判断内存是否开辟成功
//缩小开辟的空间
int*ptr=(int*)realloc(p,5*sizeof(int));
//对于调整后的空间,建议用一个新的指针来接收,因为当遇到空间调整失败的情况时,如果用指针p来接收,容易丢失原数据。
//缩小空间可能存在开辟新空间的情况(不是原来空间的位置处缩小,而是再内存中另外的地址处开辟一块新的空间),所以需要用新的指针来接收
p=NULL;//因为创建了一个新的指针来接收新的地址,所以原指针要置NULL,省的后面因为它而报错
//关于p指向的空间的释放:如果是在原空间的位置处缩小的空间,那么p指向的空间就不会被释放,
//如果是开辟新的空间,那么对于p的释放就由realloc来完成,realloc会把原来p指向的空间释放掉。

free(ptr);
ptr=NULL;
return 0;
}

我们可以通过realloc函数把空间扩大:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//扩大空间也存在:1.在原空间的位置处扩大空间,2.在内存中另外的地址处开辟一块新的空间
//与缩小空间一样
int main()
{
int *p=(int*)calloc(10,sizeof(int));
assert(p);//判断内存是否开辟成功
//缩小开辟的空间
int*ptr=(int*)realloc(p,20*sizeof(int));
//对于调整后的空间,建议用一个新的指针来接收,因为当遇到空间调整失败的情况时,如果用指针p来接收,容易丢失原数据。
p=NULL;

free(ptr);
ptr=NULL;
return 0;
}

free函数

注意:当用指针接收动态开辟的空间,用free释放时,free释放的是指针指向的空间,不是指针

如果ptr指针向的空间不是动态开辟的吗,那么free函数产生的结果是未定义的

如果ptr是空指针,那么free函数什么也不做

1
void free(void*ptr);

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
int n=9;
float *pFloat =(float*)&n;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);

*pFloat=9.0;
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}

思考下这段代码输出的值是什么?

可能你会感到好奇:

我明明&n后强转成了float类型,为什么还会输出0.000000呢?

为什么* pFloat=9.0,以%d的形式输出会得到这么大的一个数呢?

别急,我慢慢解释。

首先我们需要知道浮点型的数据在内存中是如何存储的。

浮点型的数据是根据国际标准“IEEE 754”来存储的,标准规定:每个浮点数V=(-1)^S* M*2^E

当S=0时,浮点数为正数

当S=1时,浮点数为负数

那么M与E又代表什么意思呢?

假设我们有一个浮点数“5.5”,把它转换成二进制的形式就是:101.1,此时它的S=0,M=1.01,E=2。

(就好比科学计数法,5500=5.5*10^3,只不过浮点型V=(-1)^S * M * 2^E是把科学计数法的10换成了2。)

回到正题,M就是将浮点数转换成二进制再转换成类似于科学计数法的形式时,5.5的部分,E就是小数点的位移量,

同时,计算机又根据32为浮点型(float)与64位浮点型(double)将存储方式分类两类:

32位浮点型:第一位位符号位(s),往后8 bit表示E,剩下23 Bit表示M

64位浮点型:第一位表示符号位,往后11 bit表示E,剩下52 bit表示M。

关于M:

M,的取值范围:M大于等于1,小于2。

也就是说,M是默认存在一个1的,所以,为了节省一位有效数字,我们在把M存储到内存中时,只会存储小数部分,当要使用该浮点型的数时,提取M,只需要在前面加上一个1就行。假设是一个32位的浮点数,以这样的方式存储,原本只能存放23位有效数字,现在就能存放24位有效数字了(存放到内存中的小数部分(23位)与默认的1,一共24位)

关于E:

上面我们说到,V的公式类似于科学计数法,但是在科学计数法里,E的值可以为负数;但是在V公式中,E是一个无符号整型,它只能为正数,所以,为了防止出现负数的情况,在计算机把E存入到内存中时,会让E加上一个中间值。

32位的浮点型中间值为127

64位的浮点型中间值为1023

比如上面提到的V=5.5=101.1=(-1)^0* M *2^2;

E=2,加上中间值=129,再转换成二进制形式:1000 0001。

如果要取出来,也很简单,让E减去中间值就行了。

但是在提取E时,会出现三种情况:

  • E全为0的情况
  • E全为1的情况
  • E不是全为1也不是全为0的情况(正常情况)

E全为0的情况:(假设是32位浮点数)

1
s: 0  E: 00000000  M: 00000000000000000000000

此时E是存储在内存中的,E=0,我们知道E存储到内存中时要加上中间值,前面已经知道了32位浮点数的中间值是127,当E为多少时,加上中间值会等于0?答案是:-127

所以 : v=(-1)^S* M*2^E,此时不管S与M等于多少,最终V都是一个接近于0的数。

E全为1的情况

1
s: 0  E: 11111111  M: 00000000000000000000000

此时E是存储在内存中的,E转换成十进制是255,我们知道E存储到内存中时要加上中间值,前面已经知道了32位浮点数的中间值是127,当E为多少时,加上中间值会等于255?,答案是:128。

所以 : v=(-1)^S* M*2^E,此时不管S与M等于多少,最终V都是一个非常大的数。

E不是全为1也不是全为0的情况(正常情况)

正常情况就不赘述了。当你看完了前面的内容,这种情况也就能自己去推算了。

现在我们在回到前面的问题:

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
int n=9;
float *pFloat =(float*)&n;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);

*pFloat=9.0;
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}思考下这段代码输出的值是什么?

当面把&强转成浮点型时,9=(-1)^S* M *2^E;

S=0、E=00000000、M=00000000000000000001001。

所以最后输出:

1
printf("*pFloat的值为:%f\n",*pFloat);

值为:0.000000

在当我们给*pFlota赋值9.0时;

9.0=(-1)^S* M* 2^E;

S=0、M=001、E=3,

转换成二进制:0 10000010 00100000000000000000000,再转换成十进制就等于:1091567616

文件指针:

文件函数:

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment