看着《C++编程思想》, 有点意思, 来欣赏一下其中的CStash程序(有略微的改动):
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
// element: 存储元素
// cell : 存储空间(除了element之外, 可能还有没有利用、但是已经存在的cell空间)
const int increment = 100; // 定义每次膨胀的cell的个数
typedef struct CStashTag
{
int size; //一个cell的字节数
int quantity; //cell的总数
int next; //element的总数(也可以认为是下一个element的位置)
unsigned char* storage; // 指向cell堆空间
}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);
// 初始化后, 就知道每个cell的大小了, 若element为int, 则一个cell的大小为4
void initialize(CStash* s, int sz)
{
s->size = sz;
s->quantity = 0;
s->storage = NULL;
s->next = 0;
}
int add(CStash* s, const void* element)
{
if(s->next >= s->quantity) // cell数目不足以容纳更多的element, 则需要膨胀
{
inflate(s, increment); // 每次膨胀100个cell
}
// 增加一个element, 需要这个element中的值拷贝到下一个cell空间
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++; // element数目自增
return(s->next - 1); //最后一个element的下标
}
void* fetch(CStash* s,int index)
{
if (index >= s->next)
{
return NULL;
}
// 返回index所对应的地址
return &(s->storage[index * s->size]);
}
int count(CStash* s)
{
return s->next; //element的个数(也可以认为是下一个element的位置)
}
void inflate(CStash* s, int increase)
{
int newQuantity = s->quantity + increase; // 膨胀后的cell的总数
int newBytes = newQuantity * s->size; // 原来cell的总空间
int oldBytes = s->quantity * s->size; // 膨胀后cell的总空间
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; // 膨胀后的cell的总数
}
void cleanup(CStash* s)
{
// 我有一点点纳闷, 为什么其他的参数不清零, 而只进行下面的堆空间释放呢?
if(NULL != s->storage)
{
cout << "freeing storage" << endl;
delete []s->storage;
}
}
int main()
{
CStash intStash,stringStash;
int i = 0;
// 初始化int对应的cell
initialize(&intStash, sizeof(int));
// 申请cell, 并将element写入cell
for(i = 0; i < 10; i++)
{
add(&intStash, &i);
}
// 打印cell空间中的element
for(i = 0; i < count(&intStash); i++)
{
cout << *(int*)fetch(&intStash, i) << endl;
}
// 如下代码功能类似上面, 所以我就不注释了
ifstream in;
string line;
const int bufsize = 80;
in.open("main.cpp");
initialize(&stringStash, sizeof(char) * bufsize);
while(getline(in, line))
{
add(&stringStash, line.c_str());
}
i = 0;
char* cp = NULL;
while(NULL != (cp = (char*)fetch(&stringStash, i++)))
{
cout << cp << endl;
}
cleanup(&intStash);
cleanup(&stringStash);
return 0;
}
程序的结果为:
0
1
2
3
4
5
6
7
8
9
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
// element: 存储元素
// cell : 存储空间(除了element之外, 可能还有没有利用、但是已经存在的cell空间
const int increment = 100; // 定义每次膨胀的cell的个数
typedef struct CStashTag
{
int size; //一个cell的字节数
int quantity; //cell的总数
int next; //element的总数(也可以认为是下一个element的位置)
unsigned char* storage; // 指向cell堆空间
}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);
// 初始化后, 就知道每个cell的大小了, 若element为int, 则一个cell的大小为4
void initialize(CStash* s, int sz)
{
s->size = sz;
s->quantity = 0;
s->storage = NULL;
s->next = 0;
}
int add(CStash* s, const void* element)
{
if(s->next >= s->quantity) // cell数目不足以容纳更多的element, 则需要膨胀
{
inflate(s, increment); // 每次膨胀100个cell
}
// 增加一个element, 需要这个element中的值拷贝到下一个cell空间
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++; // element数目自增
return(s->next - 1); //最后一个element的下标
}
void* fetch(CStash* s,int index)
{
if (index >= s->next)
{
return NULL;
}
// 返回index所对应的地址
return &(s->storage[index * s->size]);
}
int count(CStash* s)
{
return s->next; //element的个数(也可以认为是下一个element的位置)
}
void inflate(CStash* s, int increase)
{
int newQuantity = s->quantity + increase; // 膨胀后的cell的总数
int newBytes = newQuantity * s->size; // 原来cell的总空间
int oldBytes = s->quantity * s->size; // 膨胀后cell的总空间
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; // 膨胀后的cell的总数
}
void cleanup(CStash* s)
{
// 我有一点点纳闷, 为什么其他的参数不清零, 而只进行下面的堆空间释放呢?
if(NULL != s->storage)
{
cout << "freeing storage" << endl;
delete []s->storage;
}
}
int main()
{
CStash intStash,stringStash;
int i = 0;
// 初始化int对应的cell
initialize(&intStash, sizeof(int));
// 申请cell, 并将element写入cell
for(i = 0; i < 10; i++)
{
add(&intStash, &i);
}
// 打印cell空间中的element
for(i = 0; i < count(&intStash); i++)
{
cout << *(int*)fetch(&intStash, i) << endl;
}
// 如下代码功能类似上面, 所以我就不注释了
ifstream in;
string line;
const int bufsize = 80;
in.open("main.cpp");
initialize(&stringStash, sizeof(char) * bufsize);
while(getline(in, line))
{
add(&stringStash, line.c_str());
}
i = 0;
char* cp = NULL;
while(NULL != (cp = (char*)fetch(&stringStash, i++)))
{
cout << cp << endl;
}
cleanup(&intStash);
cleanup(&stringStash);
return 0;
}
freeing storage
freeing storage
其实, 从上面可以看到, CStash结构体显得有点多余, 直接用size, quantity, storage, next也是可以的。 之所以还要用结构体, 完全是为了整体性, 让有点关系的size, quantity, storage, next成为一个有机体, 便于理解, 便于编程, 便于维护, 这就是结构体的最大作用吧