1、
malloc:分配内存块
calloc:分配内存块,并且全部初始化为0
realloc:调用之前申请的内存块的大小,缩小内存块的时候,开头地址不变,其他不要的数据也不变,只是右边界线
正常使用两个参数,第一个参数:之前开辟的内存块的开始地址, 第二个参数:新开辟的内存块的大小
注意:第一个参数,必须是开辟前的内存块的开始地址,不不能移动;
如果将第一个参数传0,相当于一个malloc函数;
如果将第二个参数传0,相当于一个free函数;
2、动态开辟空间:
(1)int *p6 = (int*)realloc(0, 10 * sizeof(int) * 4)=/int *p6 = (int*)malloc(10 * sizeof(int) * 4);相当于malloc,重新找了一块空间,并没有释放之前的空间。
(2)p = (int*)realloc(p, 10 * sizeof(int) * 4);//有可能在其后边续,也有可能重新开辟一块空间。
(3)一般用malloc加for循环代替calloc。
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<assert.h>
int main()
int main()
{
//动态开辟 10个空间 int
int* p1 = (int*)malloc(10 * sizeof(int));
assert(p1 != NULL);//断言
if (p1 == NULL)
{
return 0;
}
//动态开辟 20个空间 short
short* p2 = (short*)malloc(20 * sizeof(short));
assert(p2 != NULL);//断言
if (p2 == NULL)
{
return 0;
}
//动态开辟 100个空间 double
double* p3 = (double*)malloc(100 * sizeof(double));
assert(p3 != NULL);//断言
if (p3 == NULL)
{
return 0;
}
//动态开辟 30个空间 int 初始化为0
int* p4 = (int*)calloc(30, sizeof(int));
assert(p4 != NULL);//断言
if (p4 == NULL)
{
return 0;
}
//动态开辟 50个空间 char 初始化为'A'
char* p5 = (char*)calloc(50, sizeof(char));
assert(p5 != NULL);//断言
if (p5 == NULL)
{
return 0;
}
for (int i = 0; i < 50; i++)
{
p5[i] = 'A';
}
//对p进行扩容,扩容为40个空间
p1 = (int*)realloc(p1, 10 * sizeof(int) * 4);//有可能在其后边续,也有可能重新开辟一块空间
//int *p1 = (int*)realloc(0, 10 * sizeof(int) * 4)=/int *p1 = (int*)malloc(10 * sizeof(int) * 4);//相当于malloc,重新找了一块空间,并没有释放之前的空间
assert(p1 != NULL);//断言
if (p1 == NULL)
{
return 0;
}
//对p1进行缩小,缩小为5个
p1 = (int*)realloc(p1, 5 * sizeof(int));
assert(p1 != NULL);//断言
if (p1 == NULL)
{
return 0;
}
return 0;
}
3、free函数
(1)C语言中有两个危险的东西:
(a)数组越界
(b)内存泄漏
内存泄漏或内存碎片怎么处理:可以进行重启
(2) void free(void *p),释放指针变量p所指向的动态内存;
(3)free函数的必要性:如果动态内存开辟,使用结束后没有释放,会导致申请的这块内存没有人可以使用,一般将这块没有人能使用的内存叫做垃圾,留着垃圾的函数会导致内存泄漏。
(4)使用malloc时,一个malloc搭配一个free
int main()
{
/*
int* p = (int*)malloc(10 * sizeof(int));//申请p
int* q = (int*)malloc(10 * sizeof(int));//申请q
p = q;//让其相等,p指向q,p原先的内存空间没有释放,其他人都不能访问,p也不能访问,造成内存泄漏
*/
//改正
int* p = (int*)malloc(10 * sizeof(int));//申请p
int* q = (int*)malloc(10 * sizeof(int));//申请q
free(p);
p = q;//让其相等,p指向q,p原先的内存空间没有释放,其他人都不能访问,p也不能访问,造成内存泄漏
free(q);
}
(5)free函数报错的原因:
(a)同一块内存连续释放;
(b)free释放内存块A,但其参数并不是A的开始地址
int main()
{
/* 报错,free释放内存块p,但其参数并不是p的开始地址
int* p = (int*)malloc(10 * sizeof(int));//申请p
printf("%p\n", p);
p++;
printf("%p\n", p);//p指向第二个地址
free(p);
*/
//改正
int* p = (int*)malloc(10 * sizeof(int));//申请p
int* q =p;//备份,防止释放的不是p的开始地址
printf("%p\n", p);
p++;
printf("%p\n", p);//p指向第二个地址
free(q);
free(p);
}
(c)free释放后,会造成一个悬空指针
悬空指针:野指针,会造成不可知的错误,一般来说
空指针:指向0地址的指针,非NULL即真
一般来说,free函数执行结束后会将其执行为NULL
int main()
{
/*报错,连续释放p
int* p = (int*)malloc(10 * sizeof(int));//申请p
free(p);
free(p);
*/
//改正
int* p = (int*)malloc(10 * sizeof(int));//申请p
free(p);
p = NULL;//修改为空
free(p);//free传入空指针直接退出
}
4、函数指针:本质是一个指针,只是指针指向一个函数,编译器在编译期间对函数开辟了一块空间,而这块空间的开始地址就是函数开始地址。
C标准规定,函数名是其开始地址,所以用指针p获取函数地址 p = &Max 或 p = Max
函数指针p怎么调用:int tmp = (*p)(10, 20);//(*p)需要提高优先级
tmp=p(10,20)也可以
int Max(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int(*p)(int, int);
p = &Max;//p = Max取地址和不去地址一样
int tmp = (*p)(10, 20);//(*p)需要提高优先级
//tmp=p(10,20)也可以
printf("%d\n", tmp);
}
5、编写简单计算器利用函数指针
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a-b;
}
int Mul(int a, int b)
{
return a* b;
}
int Div(int a, int b)
{
if (b == 0)
{
return -1;
}
else
{
return a / b;
}
}
int Computer(int a, int b, int(*p)(int, int))
{
return p(a, b);
}
int main()
{
printf("a+b=%d\n", Computer(10, 20, Add));
printf("a-b=%d\n", Computer(10, 20, Sub));
printf("a*b=%d\n", Computer(10, 20, Mul));
printf("a/b=%d\n", Computer(10, 20,Div));
}