为啥VEX没有malloc啊~~~
问:当没有malloc的情况下,应该怎么办
答:没有枪,没有炮,自己给自己造~~~
动态内存管理原理
事先声明:这次的得到的结论是个人实验得出的结论,如有不对请务必纠正。
首先我们应该了解一下,内存的大致原理。内存可以被形象化为一个大楼,大楼里面有很多个房间。每个房间里都可以住着一个人(数据)。
就和上表一样,内存中的的行,列和单个位都可以用一个名称来访问(其实其中还有更复杂的体系,就不展开了)。在之前那篇文章中,已知C的变量都为静态,那么应该怎么样在没有官方的动态函数的情况下自力更生呢?
- 创建一个特别大的静态内存块(其实就是个数组)
- 创建函数可以申请内存自静态内存块(malloc)(从数组取位置指针)
- 创建函数清空内存块(free)(清空数组元素)
- 创建函数取内存元素(get)(从数组取元素)
- 创建函数向内存元素存数据(set)(清空数组元素)
上代码
内存管理结构分析
创建内存块之前,应该先分析内存的状态,然后在以合理的数据来表示它。首先,根据内存的定义和平时使用的状态可知内存有两种状态(其实是四种,不过这里两种足够了)。第一种状态是内存可用,是处于无人使用的状态。第二种是内存在被其他程序使用。内存里应该有储存数据可空间。而当请求了足够的空间之后,输出的指针也应该记录内存的指向信息。在C语言中,已知数组名是一个指针,对数组名自加会访问数组中元素。
ex:
int array[3]={0,1,2};
for(int i=0;i<3;i++){
printf("%d\n",array[i]);
}
printf("\n");
for(int i=0;i<3;i++){
printf("%d\n",*array);
array++;
}
output:
0
1
2
0
1
2
所以根据以上的想法来设计两个结构体,一个是MemoryUnit内存元素,另一个是MemoryArray内存数组。
//内存元素定义
typedef struct _MemoryUnit {
MovementUnit data;
int state; //0 not be used, 1 is using, 2 ready to free
} MemoryUnit;
//数组元素定义
typedef struct _MemoryArray {
int size;
int location;
} MemoryArray;
在有了空白内存之后,就要对其进行初始化。这里初始化函数void init()
。
void init() {
null.state = 0;
MovementUnit data;
data.motorNumber = preSetFront;
data.countingSetting = distance;
data.difference = 0;
data.stayWhenFinish = 0;
null.data = data;
for (int i = 0; i<MEMORY_SIZE; i++) {
heap[i] = null;
}
coreState.memorySize = MEMORY_SIZE;
coreState.state = 1;
coreState.freeMemoryCount = MEMORY_SIZE;
}
这个函数用null这个结构体初始化了整个内存块,并且初始化了内存监视器的状态。
完成了内存块的初始化之后,接下来要做的是内存申请函数int malloc(MemoryArray* unit, int size)
。这个函数用来从内存里寻找大小相符的内存块并且得到指针。
int malloc(MemoryArray* unit, int size) {
while (coreState.state == 0) {
init();
}
for (int i = 0; i<MEMORY_SIZE; i++) {
int notEnoughSpacce = 0;
if ((i + size)<MEMORY_SIZE) {
for (int j = 0; j<size; j++) {
if (heap[j + i].state != 0)
notEnoughSpacce = 1;
}
if (notEnoughSpacce == 0) {
for (int j = 0; j<size; j++) {
heap[j + i].state = 1;
}
unit->location = i;
unit->size = size;
return notEnoughSpacce;
}
}
}
return 1;
}
返回0代表一切正常,1表示内存不足。
有了可以申请内存的函数,也要有清空内存的函数int free(MemoryArray* unit)
。这个函数会将传入是数组指向的内存完全清空并初始化。
int free(MemoryArray* unit) {// clean memory by replacing data to null
int location = unit->location;
int size = unit->size;
if (location + size<MEMORY_SIZE) {
for (int j = 0; j<size; j++) {
heap[j + location] = null;
}
}
}
但是因为内存数组并没有携带实际的指针,所以还需要额外的MovementUnit get(MemoryArray* unit, int location)
和void set(MemoryArray* units, MovementUnit unit, int location)
来读写数据。
MovementUnit get(MemoryArray* unit, int location) {
int pointer = unit->location + location;
return heap[pointer].data;
}
void set(MemoryArray* units, MovementUnit unit, int location) {
int pointer = units->location + location;
heap[pointer].data = unit;
}
并且还需要一个函数来更新内存监视器的数据void recomputingMemorySize()
。
void recomputingMemorySize() {
int count = 0;
for (int i = 0; i<MEMORY_SIZE; i++) {
if (heap[i].state == 0)count++;
}
coreState.freeMemoryCount = count;
}
至此,一个伪内存管理就做好了。