Hi everybody:
I'm trying to do the practices on the top of forum. I started from
beginner's level. This time I will show you my solution to implement
a simple database in C++. If you could give some advice on the
following aspects or other, it would be so nice of you:)
1. base datastructure. I used a 2D array to store a number of
pointers to string data. However, it's not easy to resize. I find it's not
easy to add a column.
2. design pattern. My solution really looks like a hardcoded solution
only to this question. How to find a better a design pattern than could
be reused easily?
3.algothirms.
4. multithreads and process protection
5....
I hope my post is not too long to make you boring.
my codes:
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "io.h"
const char *filename = "d:/database.txt";
const int ROWS = 10;
const int COLOUMS = 3;
class Data
{
public:
Data() :
m_nTotalColumns(COLOUMS),
m_nTotalRows(ROWS),
m_nCurCol(0),
m_nCurRow(0),
m_ppcData(NULL),
m_fp(NULL)
{
}
virtual ~Data() {}
//create a dynamic 2 dimension char * array which points to a single data string
bool Init() {
m_ppcData = (char **)new char *[ROWS][COLOUMS];
if(NULL == m_ppcData) {
return false;
}
memset((void *)m_ppcData, NULL, ROWS * COLOUMS * sizeof(char *));
return ReadFile();
}
//insert a record with all values of fields
void Insert(const char *name, const char *Gender, const char *old) {
if (NULL == name || NULL == Gender || NULL == old) {
return;
}
//array is full
if(++m_nCurRow >= m_nTotalRows) {
return;
}
StrCpy(m_ppcData[m_nCurRow * m_nTotalColumns], name);
StrCpy(m_ppcData[m_nCurRow * m_nTotalColumns + 1], Gender);
StrCpy(m_ppcData[m_nCurRow * m_nTotalColumns + 2], old);
}
//updata a special data
void Update(const unsigned int row, const unsigned int column, const char *data) {
if(row > m_nCurRow || column >= m_nTotalColumns || NULL == data) {
return;
}
StrCpy(m_ppcData[row * m_nTotalColumns + column], data);
}
//select a special data
char *Select(const unsigned int row, const unsigned int column) {
if(row > m_nCurRow || column >= m_nTotalColumns) {
return NULL;
}
return m_ppcData[row * m_nTotalColumns + column];
}
//delete a row
void DeleteRecord(const unsigned int row) {
if(row > m_nCurRow) {
return;
}
unsigned int i;
unsigned int j;
for(i = 0; i < m_nTotalColumns; i++) {
delete [] m_ppcData[row * m_nTotalColumns + i];
m_ppcData[row * m_nTotalColumns + i] = NULL;
}
//if the deleted row is not the last, i will fflush the data to the top
if(row < m_nCurRow) {
for(i = row; i < m_nCurRow; i++) {
for(j = 0; j < m_nTotalColumns; j++) {
m_ppcData[i * m_nTotalColumns + j] = m_ppcData[(i + 1) * m_nTotalColumns + j];
}
}
}
memset((void *)(m_ppcData + m_nCurRow * m_nTotalColumns), NULL, COLOUMS * sizeof(char *));
m_nCurRow--;
}
void display() {
printf("**************\n");
for(int i = 0; i < ROWS * COLOUMS; ++i) {
if (NULL != m_ppcData && NULL != m_ppcData[i]) {
printf("%s\n ", m_ppcData[i]);
}
}
}
void Save() {
WriteFile();
}
protected:
const char* StrCpy(char *&dest, const char *src) {
if(NULL == src) {
return NULL;
}
//avoid copy self
if(src == dest) {
return dest;
}
//release original memory
if(NULL != dest) {
delete [ ]dest;
dest = NULL;
}
int len = strlen(src);
dest = new char[len + 1];
if(NULL == dest) {
return NULL;
}
return strcpy(dest, src);
}
//write data into file
bool WriteFile() {
m_fp = fopen(filename, "w+");
if(NULL == m_fp) {
return false;
}
for(int i = 0; i < ROWS * COLOUMS; ++i) {
if (NULL != m_ppcData && NULL != m_ppcData[i]) {
fputs(m_ppcData[i], m_fp);
fputs(" ", m_fp);
}
}
fclose(m_fp);
return true;
}
//Read data From file
//load all the data from the disk, do I need to do so?
bool ReadFile() {
m_fp = fopen(filename, "r+");
if(NULL == m_fp) {
return false;
}
long length = _filelength(_fileno(m_fp)) + 1;
char *tmp = new char[length];
if(NULL == tmp) {
return false;
}
fgets(tmp, length, m_fp);
int i = 0;
char *pre = tmp;
char *t = tmp;
unsigned int pos;
bool bIsEOF = false;
for(i = 0, pos = 0; (i < length) && (pos < m_nTotalRows * m_nTotalColumns); ++i) {
if(*t == '\0' || *t == ' ') {
//if we come to the end of the data, break
if(*t == '\0') {
StrCpy(m_ppcData[pos], pre);
break;
}
else {
*t = '\0';
StrCpy(m_ppcData[pos], pre);
//deal with multi spaces
while (*++t == ' ') {
}
pre = t;
pos++;
}
}
&nref="http://bbs.fdc.com.cn/boardlist.asp?boardid=376" target=_blank> </DIV> <DIV class=tabcontent id=tcontent5> p; delete [] tmp;
fclose(m_fp);
return true;
}
private:
const unsigned int m_nTotalColumns;
const unsigned int m_nTotalRows;
unsigned int m_nCurCol;
unsigned int m_nCurRow;
FILE *m_fp;
char **m_ppcData;
};
int main(int argc, char* argv[])
{
Data d;
if (d.Init()) {
d.Update(2, 2, "100");
d.Insert("Rock", "male", "24");
d.display();
char * p = d.Select(3, 2);
printf("p = %s\n", p);
d.DeleteRecord(1);
d.display();
d.Save();
}
return 0;
}
You have to create a file called "d:/database.txt" on your disk, the contens look like this"name Gender old Rock male 100".
Thankyou very much for watching.