void指针
void用在函数定义中可以表示函数没有返回值或者没有形参,用在这里表示指针指向的数据的类型是未知的。
void*
表示一个有效指针,它确实指向实实在在的数据,只是数据的类型尚未确定,在后续使用过程中一般要进行强制类型转换。
malloc()函数:动态分配内存空间
原型:
void* malloc(size_t size);
作用:malloc()在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。如果希望在分配内存的同时进行初始化,请使用calloc()函数。
返回值:分配成功返回指向该内存的地址,失败则返回NULL
初始化:使用
memset(str, 0, 20);
初始化
#include<stdio.h>
#include<iostream>
int main(){
//分配可以保存30个字符的内存,并把返回的指针转换为char*
char *str = (char *)malloc(sizeof(char) * 30);
str = "leetcode" ;
cout << str << endl;
return 0;
}
malloc背后的实现原理---内存池
malloc()和free()的分配算法:
内存池:
不管具体的分配算法是怎样的,为了减少系统调用,减少物理内存碎片,malloc()的整体思想是先向操作系统申请一块大小适当的内存,然后自己管理,这就是内存池(Memory Pool)。
调用malloc()发生了什么?
内存控制块数据结构,用于管理所有的内存块:is_available标志该块是否可用 + size标志该块的大小
实现malloc时要用到linux下的全局变量:指向进程堆底的指针,也就是指向堆中的第一个内存块 + 指向进程堆顶的指针,也就是指向堆中最后一个内存块的末地址。
1.对堆中的内存块进行遍历,找合适的内存块:判断该块是否可用;大小是否满足要求。
2.没有找到满足条件的内存块时:向操作系统申请新的内存块,返回内存块的首地址。
calloc()函数:分配内存空间并初始化
原型:
void* calloc(size_t num, size_t size);
作用:calloc()在内存中动态分配num个长度为size的连续空间,并将每一个字节都初始化为0。所以它的结果是分配了num * size个字节长度的内存空间,并且每个字节的值都是0。
返回值:分配成功返回值指向该内存的地址,失败则返回NULL。
#include<iostream>
#include<stdio.h>
using namespace std;
int main(){
//分配可以保存30个字符的内存,并把返回的指针转换为char*
char *str = (char *)calloc(sizeof(char), 30);
cout << str << endl;
str = "leetcode" ;
cout << str << endl;
return 0;
}
realloc()函数:重新分配内存空间
原型:
void* realloc(void* ptr, size_t size)
作用:realloc()对ptr指向的内存重新分配size大小的空间。如果size的值为0,那么ptr指向的内存空间就会被释放,但是由于没有开辟新的内存空间,所以会返回空指针;类似于调用free()
free()函数:
原型:
void free(void* ptr);
作用:free()只能释放动态分配的内存,并不能释放任意的内存
注意:free()不会改变ptr变量本身的值,调用free()后它仍然会指向相同的内存空间,但是此刻内存已无效,不能被使用,所以建议将ptr的值设置为NULL。