C风格库文件笔记
今天学习《Thinking in C++》数据抽象。看到袖珍C库的程序。作为一个C++初学者,感到理解有些困难。因此整理笔记,以便理清思路,并得以更加深入地理解库文件。
源程序如下:
//:Clib.h
//一个可以在运行过程中创建的类似数组的结构
typedef struct CStashTag{
int size; //每个空间的大小
int quantity; //存储空间总数
int next; //下一个空的空间
//动态分配数组字节
unsigned char* storage;
}CStash;
void initiallize(CStash* s, int size); //初始化
void cleanup(CStash* s);
int add(CStash* s, const void* element);
void* fetch(CStash* s, int index);
int count(CStash* s);
void inflate(CStash* s, int increase); //扩充存储空间
///:~
//CLib.cpp
//C风格库的实现
//声明结构和函数:
#include"CLib.h"
#include<iostream>
#include<cassert>
using namespace std;
//这是在增加存储时要添加的元素的总数
const int increment = 100;
void initialize(CStash* s, int sz){
s->size = sz;
s->quantity = 0;
s->storage = 0;
s->next = 0;
}
int add(CStash* s, const void* element){
if(s->next >= s->quantity)//是否有足够的空间?
inflate(s, increment);
//将element复制到storage中
//从下一个空的空间开始:
int startBytes = s->next * s->size;
unsigned char* e = (unsigned char*)element;
for(int i = 0; i < s->size; i++)
s->storage[startBytes + i] = e[i];
s->next++;
return(s->next - 1); //下标数字
}
void* fecth(CStash* s,int index){
//检查下标界线(Check index boundaries):
assert(0 <= index);
if (index >= s->next)
return 0; //To indicate the end
//为需要的元素创立一个指针
return &(s->storage[index * s->size]);
}
int count(CStash* s){
return s->next; //CStash中的元素
}
void inflate(CStash* s, int increase){
assert(increase > 0);
int newQuantity = s->quantity + increase;
int newBytes = newQuantity * s->size;
int oldBytes = s->quantity * s->size;
unsigned char* b = new unsigned char[newBytes];
for(int i = 0; i < oldBytes; i++)
b[i] = s->storage[i]; //将旧内容复制到新的空间中
delete [](s->storage);//删除旧的存储空间
s->storage = b; //指向新的内存
s->quantity = newQuantity;
}
void cleanup(CStash* s) {
if(s->storage != 0) {
cout << "freeing storage" << endl;
delete []s->storage;
}
}///:~
CStash结构意义:
size为整型,表示一块CStash有几个元素。
quantity为整型,表示一块CStash占几个字节。
next为整型,表示当前位于第几个元素。
storage为指向无符号字符的指针,为CStash的首地址。
const int increment 为CStash需要增加时默认的增加的元素个数(它只在add函数中出现过)。
initialize()对指定的CStash变量作初始化。其中storage为0表示它为空指针,不分配初始内存。
add()函数在下一个位置插入一个元素。此处next以及size的用处得到淋漓尽致的体现。而且可以看出其设置的巧妙。next用于记录位置。存储指定成员是用到size变量。此变量在初始化时有用户指定。所以使得CStash结构可以存储各种类型的数据。该函数一开始检查CStash变量是否已满,若是,则用inflate函数进行扩充。add()函数最后返回下标号。
现在,就可以比较轻松的理解书上的解释了。原话如下:
因为编译器并不知道存放的特定变量的类型(函数返回的都是void*),所以不能只做赋值,虽然这的确是很方便的事情。我们必须一个字节一个字节地拷贝这个变量,完成这项拷贝任务最简单的方法是使用数组下标。典型的情况是,在storage中已经存放有数据字节,有next的值指明。为了从正确的字节偏移开始,next必须乘上每个元素的长度(按字节),产生startBytes,然后,参数element转换为一个unsigned char*,所以这就能一个字节接着一个字节地寻址,拷贝进可用的storage存储空间中。增加后的next指向下一个可用的存储块,fetch()能用指向这个数值存放点的“下标数”重新得到这个值。
――此段引自《Thinking in C++》