栈、堆、全局区、字符常量区、代码区
栈区:由操作系统申请,在变量生命周期结束后由操作系统释放。
堆区:由我们申请,由我们自己释放
malloc(size_t __size)
int main(void) {
//申请4字节的空间,类型是int的地址,强制类型转换。
//申请完的地址的首地址就是p
int *p = (int *) malloc(4);
return 0;
}
size_t: unaigned int
- 32位编译器:unaigned int:sizeof =4
- 64位编译器:long unaigned int:sizeof =8
malloc传无符号,(int *) malloc(4)中4默认是int类型的,c语言会转换成无符号的,如果写成(int *) malloc(4u)就直接是无符号的。无符号就是全是整数,跟有符号的取值范围不一样哦。
malloc申请空间
- malloc(不是太大的数):
- malloc(0):malloc得到空间首地址,但是可用地址的长度为0,意思就是地址不能用。
- malloc(超出极限):申请的空间大小超过操作系统所给的内存大小,则返回null,地址为0
malloc空间赋值
int main(void) {
int *p = malloc(40);
//申请的40个字节,能装10个int数据
for (int i = 0; i < 10; ++i) {
//给指针赋值
p[i] = i;
}
//赋值后,读取
for (int j = 0; j < 10; ++j) {
printf("%d,", p[j]);//0,1,2,3,4,5,6,7,8,9,
}
return 0;
}
memset赋值
int main(void) {
int *p = malloc(40);
//内存赋值方法
//第一个参数:起始地址,
//第二个参数:给起始地址设置的值
//第二个参数:一共设置多少个字节
memset(p, 0, 40);
//赋值后,读取
for (int j = 0; j < 10; ++j) {
printf("%d,", p[j]);//0,0,0,0,0,0,0,0,0,0,
}
return 0;
}
memset()是按字节赋值的
是把范围内的所有字节都设置成值1(下面的代码里的),而输出是int类型的,int类型占四个字节,所以输出四个值都是1的字节的值,即16843009
-
16843009是怎么得出来的呢?
image.png
int main(void) {
int *p = malloc(40);
//内存赋值方法
//第一个参数:起始地址,
//第二个参数:给起始地址设置的值
//第二个参数:一共设置多少个字节
memset(p, 1, 40);
//赋值后,读取
for (int j = 0; j < 10; ++j) {
printf("%d,", p[j]);//16843009,16843009,16843009,16843009,16843009,16843009,16843009,16843009,16843009,16843009,
}
return 0;
}
所以如果赋值成0,才能使用memse()
malloc()注意点
1.malloc申请的字节数一定要对应类型,比如申请int型,那么一定要大于4,double的话就要大于8,因为他们类型一次要操作这些个字节,少了不行,多了可以不用。
2.malloc申请内存之后,就不要再malloc了。但是如果malloc的地址记录一下,然后再指向新的地址,就不会丢失空间了。
int main(void) {
int *p = malloc(40);
//p重新指向另一块地址,那么原来的地址就不用了,这样会造成内存泄漏
p = malloc(4);
return 0;
}
int main(void) {
int *p = malloc(40);
int *p1 = p;
//专业就不会丢失空间了.或者原来的空间不使用直接调用free(p)
p = malloc(4);
return 0;
}
free(p)释放指针
- free(p)之后,地址还是那个地址。
- free(p)之后,把p赋值为NULL:p=NULL
int main(void) {
int *p = malloc(40);
*p = 12;
printf("%p,%d\n", p, *p);
free(p);
p = NULL;
if (NULL == p) {
//p是空指针 0==null=空
}
return 0;
}
- 空指针: 0==null=空
- 野指针:指向一个地址,但是不能访问。有两种情况:
1.free(p)之后,没把p设置成null,则指针是野指针。
2.int *p;指针初始化,但是没有赋值,这个也是野指针。 -
不能重复释放一个指针
image.png -
free()不能释放占空间
image.png -
free()一定要释放头指针
image.png - malloc的空间在程序结束的时候,系统会释放所有malloc的内存,那么为什么还有free()呢?
1.服务器不会频繁重启;
2.使用软件也不会短时间频繁重启。
malloc一维数组
-
基本数据类型的空间的申请与使用
image.png - 数组的指针申请
一维数组栈内存:比如int a[5],是申请一个长度为5的内存,每个内存为四字节,这内存是堆内存。
而malloc(n)是:申请一个长度为n字节的内存,然后根据类型的字节数划分存储单位,比如int类型,则以4字节为一个单位存储。malloc申请的内存栈内存。
int main(void) {
//申请的连续的空间
//申请出来的地址就是内存的头地址
int *p = malloc(sizeof(int) * 5);//sizeof(int)*5=20
int a[5];
int *p2 = &a[0];//将指针的首地址指向数组的首地址
return 0;
}
int main(void) {
//申请的连续的空间
int *p = malloc(sizeof(int) * 5);//sizeof(int)*5=20
memset(p, 0, sizeof(int) * 5);//memset只能设置成0
return 0;
}
- *(p+i)==p[i];
malloc的数组与int a[3]这种栈区数组的区别?
1.定义上不同,但是使用上一样。
2.malloc的数组可以这运行过程中指定任意大小,即动态数组,动态分配空间。
int a[3]就不一样了,个数在定义的时候确定,以后就不能改了。
int main(void) {
unsigned int a;
int *p;
scanf("%u", &a);
p = malloc(a);
free(p);
return 0;
}
malloc地址转化成一维数组指针/二维数组指针
malloc一维数组指针
(p+n)=*p[n]
int main(void) {
int a[5];
//栈区一维数组指针的写法
int(*p1)[5] = &a;
//对比上面的写法
//malloc一维数组指针
int (*p)[5] = (int (*)[5]) malloc(sizeof(int) * 5);
*(*p + 0) = 1;
*(*p + 1) = 2;
*(*p + 2) = 3;
*(*p + 3) = 4;
*(*p + 4) = 5;
//遍历malloc的数组数组a的元素
for (int i = 0; i < 5; ++i) {
printf("%d,", (*p)[i]);//1,2,3,4,5,
}
free(p);
return 0;
}
malloc二维数组指针
int main(void) {
int a[2][3];
//栈区二维数组指针的写法
int(*p1)[2][3] = &a;// *p1 == a;
//对比上面的写法
//malloc二维数组指针:
int (*p)[2][3] = (int (*)[2][3]) malloc(sizeof(int) * 2 * 3);
//二维指针数组p赋值
(*p)[0][0] = 1;
(*p)[0][1] = 2;
(*p)[0][2] = 3;
(*p)[1][0] = 5;
(*p)[1][1] = 8;
(*p)[1][2] = 10;
//遍历malloc的数组数组a的元素
for (int i = 0; i < 2; ++i) {
for (int j = 0; j <3 ; ++j) {
printf("%d,", (*p)[i][j]);//1,2,3,5,8,10,
}
}
free(p);
return 0;
}
calloc realloc
- calloc:申请一个数组空间,空间也是连续的
- calloc(5,4);//申请了一个 5个元素每个元素4个字节的空间
- calloc 申请出来地址他给初始化成0了,而malloc不给初始化,字节用memset()初始化
int main(void) {
//1:数组元素个数,2:每个元素的字节数
int *a = calloc(5, 4);//申请了一个 5个元素每个元素4个字节的空间
for (int i = 0; i < 5; ++i) {
printf("%d,", a[i]);//0,0,0,0,0,
//calloc 申请出来地址他给初始化成0了,而malloc不给初始化,字节用memset()初始化。
}
free(a);
return 0;
}
realloc:重新给malloc或者calloc分配空间
int main(void) {
int *p = malloc(12);
//1:分配空间的首地址,2:重新分配空间的大小
int *p1 = realloc(p, 20);//正常情况p1 和p的地址是一样的,不正常的看下面的注意
//如果重新分配的空间,系统分配不足,会返回null
free(p);
return 0;
}
注意:
如果malloc或者calloc原来的空间是10个字节,让realloc重新1000个字节:
- 如果整个内存条上都没有足够1000字节的空间,就返回null。
- 如果其他的内存碎片或者内存上有1000字节的空间,那么指针地址就会变成这个内存地址,然后把原来的值放到对应的地方。
calloc 和malloc的选择
- calloc申请申请数组好用,直接calloc(5,4),calloc申请好数组直接初始化成0,malloc得用memset设置成0。
- 其他的数据结果,比如链表,树,图,一次申请sizeof(节点),这些用malloc更合适
- 效率:calloc会初始化内存,所以申请的内存很多的时候,效率会低一点点,毕竟有时候不需要初始化,malloc这就效率高一些。其实微乎其微啦~~~~
*在C中的四种作用
- 声明的时候有:表示指针变量 intp
- *地址:表示地址操作符 *p
- 数字*数字 :乘法
- 注释:/* */
网友评论