【C实现简易内存数据库】4、create实现

来源:互联网 发布:sharpdesk软件 编辑:程序博客网 时间:2024/04/30 09:44

需要在C盘根目录下有create.txt和create2.txt方可运行。

如:create1.txt

create table Student     (       id float(4) NOT NULL;       name char(100) NULL;       grade float(4) NULL;     )     
create2.txt

create table Student2 (       id2 float(4) NOT NULL;       name2 char(100) NULL;       grade2 float(4) NULL;     )     


代码很大一部分是直接照搬了老师的博客:http://orangegao-gmail-com.iteye.com/
完整源码:

#include <stdio.h>  #include <stdlib.h>  #include <string.h> enum DataType {floatType, stringType};   struct Row {void** data;Row* next;};struct Column {DataType type;int length;bool allowNull;char name[256];Column* next;};struct Table{char name[256];Row* rowHead;Column* columnHead;int columnCount;Table* next;};Table* tableHead;int createTable(char*,Table*);int getLength(char*);int getColumnTypeLength(char* , DataType* , int*);int main(){Table* t = (Table *)malloc(sizeof(Table));memset(t, 0, sizeof(Table)); char* path;path = "C://create.txt";createTable(path,t);t = (Table *)malloc(sizeof(Table));memset(t, 0, sizeof(Table)); path = "C://create2.txt";createTable(path,t);//testprintf("%s\n",tableHead->name);//Studentprintf("%s\n",tableHead->columnHead->name);//idprintf("%s\n",tableHead->columnHead->next->name);//nameprintf("%s\n",tableHead->next->name);//Student2printf("%s\n",tableHead->next->columnHead->name);//id2printf("%s\n",tableHead->next->columnHead->next->name);//name2getchar();return 1;}/*  * 描述:根据给定文件,在内存里填充数据库格式  * 参数:已经打开的文件  * 返回:返回0说明创建失败。返回1则创建成功  */ int createTable(char* path,Table* t){FILE *fp = fopen(path,"r"); t->columnHead = NULL;t->columnCount = 0;    char buffer[100];      //第一次读应该读到create      fscanf(fp,"%s",buffer);      if (stricmp(buffer,"create")) return 0;         //第二次读应该读到table      fscanf(fp,"%s",buffer);      if (stricmp(buffer,"table")) return 0;         //第三次读应该读到表名     fscanf(fp,"%s",buffer);     strcpy(t->name, buffer);       //第四次读应该读到(      fscanf(fp,"%s",buffer);      if (strcmp(buffer,"(")) return 0;         //接下去开始读column内容   Column * current = NULL;  fscanf(fp,"%s",buffer);  while (!feof(fp) && strcmp(buffer,")")){  //每次循环先创建一个column对象  Column * column = (Column *)malloc(sizeof(Column));  //清空column  memset(column, 0, sizeof(Column));      //第一次读应该读到 column name  strcpy(column->name, buffer);    //第二次读应该读到 column type(column length)  fscanf(fp,"%s",buffer);  getColumnTypeLength(buffer, &column->type, &column->length)==0;     //第三次可能读到NULL; 可能读到; 这两种都代表着可以为空  fscanf(fp,"%s",buffer);  if (strcmp(buffer,";")==0 || strcmp(strupr(buffer),"null;")==0)  column->allowNull = 1;  //第三次读也可能读到NOT,代表着不能为空  else if (stricmp(buffer,"not")==0){  //第四次读应该读到null;  fscanf(fp,"%s",buffer);  if (!stricmp(buffer,"NULL;")) return 0;   column->allowNull = 0;  }  //因为column是链表结构,所以必有一下几句 1)保留住链表头 2)把链表连起来 3)当前的指针往后移一个  if (t->columnHead == NULL){t->columnHead = column; current = column;}else{current->next = column;  current = current->next;}//每创建一个Column,columnCount+1t->columnCount++;//继续读应该读到下一行内容了  fscanf(fp,"%s",buffer);  }  //将当前Table加到Table链表尾if(tableHead == NULL)tableHead = t;else{Table* last_t = tableHead;while(last_t->next != NULL)last_t = last_t->next;last_t->next = t;}return 1;}/*  * 描述:float(4)或者char(100)把括号前后的内容分别保存  * 参数:string -- 整体字符串  * 参数:type -- 解析后返回的type(float/char)(返回)  * 参数:length -- 解析后返回的长度(返回)  * 返回:返回0说明创建失败。返回1则创建成功  */  int getColumnTypeLength(char * string, DataType * type, int * length){      char * floatHead = "float(";      char * charHead = "char(";      //如果是float打头的      if (strncmp(string,floatHead,strlen(floatHead))==0){          *type = floatType;          string = string+strlen(floatHead);          *length = getLength(string);          return 1;      }      else if (strncmp(string,charHead,strlen(charHead))==0){          *type = stringType;          string = string+strlen(charHead);          *length = getLength(string);          return 1;      }      else{          printf("文件格式有误\n");          return 0;      }  }  /*  * 描述:4)或者100)把括号前的数字返回  * 参数:string -- 整体字符串  * 返回:返回解析后的数字  */  int getLength(char * string){      //找到')'的位置      char * end=string;      while( *end !=')' ) end++;      //把')赋值成'\0'      *end='\0';      //把字符串转成数字      return atoi(string);  }  

常见问题:

#include <stdio.h>  #include <string.h> struct Table{char name[256];};Table* tableHead = NULL;int createTable(){Table t;strcpy(t.name,"Student");tableHead = &t;return 0;}int main(){createTable();printf(tableHead->name);getchar();return 0;}

在这段代码中,我们在createTable函数中声明了Table t,将t.name赋值Student,然后将变量t的地址交给全局变量tableHead保存。在main函数中,我们打印tableHead的name,希望得到Student但却发现错误。

原因在于t是声明在createTable函数中的,在函数执行完后,变量t即被释放。虽然我们存下了t的地址,但这个地址上的数据实际上已经被释放了,现在这个地址上存储的数据已经不是我们可以预知的了。

在这种情况下,我们很容易想到在main函数中声明t后再作为参数传给createTable函数。

#include <stdio.h>  #include <string.h> struct Table{char name[256];};Table* tableHead = NULL;int createTable(Table t){strcpy(t.name,"Student");tableHead = &t;return 0;}int main(){Table t = {};createTable(t);printf(tableHead->name);getchar();return 0;}
但是这样的写法仍是错误的。

原因在于在createTable中的t实际上已经不是main函数中的那个t了,在函数调用时拷贝了一个t的副本传给createTable函数,所以所有的操作都是对这个t的副本操作的,原始的t并没有改变。

解决方法是不要传递t本身,而是传递t的地址,即t的指针。

#include <stdio.h>  #include <stdlib.h>#include <string.h> struct Table{char name[256];};Table* tableHead = NULL;int createTable(Table* t){strcpy(t->name,"Student");tableHead = t;return 0;}int main(){Table* t = (Table *)malloc(sizeof(Table));  createTable(t);printf(tableHead->name);getchar();return 0;}
这样的写法传递了t的地址,那么createTable函数中的操作都是对这个地址上的变量(即main中的t)进行的。这样我们就可以在main函数中打印出我们想要的“Student”了。

新址:http://www.limisky.com/114.html

0 0