内存分配函数

时间:2022-05-07 02:22:19

1、函数简介:
1)malloc函数,其原型如下:
void *malloc(size_t size);
malloc所分配的是一块连续的内存,其参数就是需要分配的内存字节数。如果分配成功,则返回指向这块内存的指针;如果分配失败,则返回NULL指针。

2)calloc函数,其原型如下:
void *calloc(size_t num_elements, size_t size_element);
calloc函数也是分配内存的,其参数包含所需元素的个数和每个元素的字节大小,将对分配好的内存进行初始化为0。

3)realloc函数,其原型如下:
void realloc(void *ptr, size_t new_size);
realloc函数用于修改一个原先分配的内存,扩大或缩小内存都是在原先内存块后面进行的,原先数据内容保持不变。如果无法改变原先的内存大小,realloc将申请分配另一块与原先数据内容匹配的内存,并把其内容复制到新的内存块上。因此,在使用realloc之后,就不能再使用指向旧内存的指针,而是应该改用realloc所返回的新指针。

4)free函数,其原型如下:
void free(void *pointer);
free的参数必须是从malloc、calloc和realloc返回的值,以释放动态分配后不再使用的内存,但是不能free两次,采用“一夫一妻制”。如果free的参数是NULL,将不会产生任何效果。

2、malloc函数的使用:
(1)使用malloc函数需要解决的问题:
1)内存分配给谁?
2)分配多大内存?
3)是否还有足够的内存分配?
4)内存将用来存储什么格式的数据?
5)分配好的内存在哪里?
【例】char p = (char )malloc(100);
释:
A、内存分配给char型的指针变量p;
B、分配100字节的内存;
C、有足够的内存分配(堆上剩余的连续内存块);
D、内存将用来存储char型的数据;
E、分配好的内存本身并没有名字,对它的访问时匿名的。

(2)用malloc函数申请0字节内存
申请0字节内存,函数并不会返回NULL,而是返回一个正常的内存地址,但是你却无法使用这块大小为0的内存。这好比尺子上的某个刻度,刻度本身并没有长度,只有某两个刻度有间隔才能量出长度。这时,if(NULL != p)语句校验不起作用。

(3)使用malloc函数之后需要注意的问题:
1)使用free函数释放动态分配的内存,但是不可以对同一块内存释放两次。
2)释放内存后一定要给指针置空,不然该指针就成为了“野指针”,因为使用free函数后指针变量本身保存的地址并没有改变。
【例】

char *p = (char *)malloc(100);
strcpy(p,“hello”);
free(p);//p所指的内存被释放了,但是p所指的地址仍然不变
... //此处应将p置空,即:p = NULL;
if(NULL != p)
{
//没有起防错作用
strcpy(p,“hello”);//出错
}

3、总结
(1)相同点:
1)malloc和calloc函数都能动态分配一块内存,并返回指向这块内存的指针。2)当一块动态分配的内存块不再使用时,应该调用free函数释放内存,而且不能再被访问。
3)如果内配分配失败将返回NULL指针(malloc、calloc和realloc都一样)。
4)malloc和calloc函数的返回值相同,返回“void *”,与realloc函数的返回值不同,返回“void”。

(2)不同点:
1)malloc分配好的内存不初始化,而calloc分配好的内存将被初始化为0。
2)malloc和calloc请求内存的方式不同。
3)realloc函数将改变一块已经动态分配的内存大小。

(3)注意
1)内存泄露指内存被动态分配后,当不再使用时没有被释放。内存泄露会增加程序的体积,有可能导致程序或系统的崩溃。
2)使用malloc和calloc函数分配内存要检查是否成功的情况。
3)不要越过动态分配的区域访问。
4)动态内存被释放后就不要访问它。
5)是malloc、calloc和realloc分配的内存才能用free释放,并且不能只释放一部分,而是整块的释放。
6)使用sizeof计算数据类型的长度,可以提高程序的可移植性。

4、有关内存的思考题
(1)

void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}

请问运行Test函数会有什么样的结果?

答:系统崩溃。因为GetMemory并不能传递动态内存,Test函数中的str一直都是NULL,“strcpy(str, “hello world”);”将使程序崩溃。
(2)

char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}

请问运行Test函数会有什么样的结果?

答:可能是乱码。因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是NULL,但其原有的内存已经被清除了,新内容不可知。

(3)

void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}

请问运行Test函数会有什么样的结果?

答:能够输出“hello”,但是会出现内存泄露。

(4)

void Test(void)
{
char *str = (char *)malloc(100);
strcpy(str, "hello");
free(str);
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}

请问运行Test函数会有什么样的结果?

答:篡改动态内存区的内容,后果难以预测,非常危险。因为free(str)之后,str成为野指针,if (str != NULL)语句不起作用。