//直接上代码 C语言写数据库 #include#include #include #include //断言函数的库 #include //错误机制库 #define MAX_DATA 512 #define MAX_ROWS 100 struct Adress{ int id; int set; char name[MAX_DATA]; char email[MAX_ROWS]; }; struct Database{ struct Adress rows[MAX_ROWS]; }; struct Connection{ FILE* file; struct Database* db; }; void die(const char* message){ if(errno){ //发生错误时该error的变量值为1,可通过perror打印出错信息 perror(message); //和printf的作用差不多,只是它使用在错误的时候打印 }else{ printf("ERROR:%sn",message); } exit(1); //不正常程序退出 } void Adress_print(struct Adress* addr){ printf("%d %s %sn",addr->id,addr->name,addr->email); } void Database_load(struct Connection* conn){ //fread函数:将file指针指向的内容读取1个数据块,大小为sizeof那么大的数据块,给db指针; 返回数据块指定个数表示成功;反之读取失败。 int rc=fread(conn->db,sizeof(struct Database),1,conn->file); if(rc != 1) die("Failed to load database."); } struct Connection* Database_open(const char* filename,char mode){ struct Connection* conn=malloc(sizeof(struct Connection)); if(!conn) //NULL的宏定义本质是0 die("Memory error"); conn->db=malloc(sizeof(struct Database)); if(!conn) die("Memory error"); if(mode == 'c'){ conn->file =fopen(filename,"w"); }else{ conn->file =fopen(filename,"r+"); //读取已存在的文件,光标到开头 if(conn->file){ Database_load(conn); } } if(!conn->file) die("Failed to open the file"); return conn; } //释放资源的时候,应该先放“子资源”,再放“父资源”;防止出现野地址(野内存,无法认领或访问的内存) void Database_close(struct Connection* conn){ if(conn){ if(conn->file) fclose(conn->file); if(conn->db) free(conn->db); free(conn); } } void Database_write(struct Connection* conn){ rewind(conn->file); //rewind函数:文件I/O流的指针回归文件开头 //将若干数据块写入指定文件,写入file文件指针 int rc=fwrite(conn->db,sizeof(struct Database),1,conn->file); if(rc != 1) die("Failed to write database."); rc=fflush(conn->file); //清除缓存I/O流 if(rc == -1) die("Cannot flush database."); } void Database_create(struct Connection* conn){ int i=0; for(i=0;i struct Adress addr={.id=i,.set=0}; conn->db->rows[i]=addr; } } void Database_set(struct Connection* conn,int id,const char* name,const char* email){ struct Adress* addr=&conn->db->rows[id]; if(addr->set) die("Already set,delete it first"); addr->set=1; char* res=strncpy(addr->name,name,MAX_DATA); if(!res) die("Name copy failed"); } void Database_get(struct Connection* conn,int id){ struct Adress* addr=&conn->db->rows[id]; if(addr->set){ Adress_print(addr); }else{ die("ID is not set"); } } void Database_delete(struct Connection* conn,int id){ struct Adress addr={.id=id,.set=0}; //结构体的默认赋值方法,可以省略结构体名 conn->db->rows[id]=addr; //当结构体嵌套时候,应该搞清对应关系,避免指向再指向的问题 } void Database_list(struct Connection* conn){ int i=0; struct Database* db=conn->db; for(i=0;i struct Adress* cur=&db->rows[i]; if(cur->set) Adress_print(cur); } } int main(int argc,char* argv[]){ if(argc<3) die("USAGE:ex17 [action params]"); char* filename=argv[1]; char action=argv[2][0]; struct Connection* conn=Database_open(filename,action); int id=0; if(argc>3) id=atoi(argv[3]); //将字符转换成int型 if(id>MAX_ROWS) die("There`s not that many records."); switch(action){ case 'c': Database_create(conn); Database_write(conn); break; case 'g': if(argc!=4) die("Need an id to get"); Database_get(conn,id); break; case 's': if(argc!=6) die("Need an id ,name,email to set"); Database_set(conn,id,argv[4],argv[5]); Database_write(conn); break; case 'd': if(argc!=4) die("Need an id to delete"); Database_delete(conn,id); Database_write(conn); break; case 'l': Database_list(conn); break; default:die("Invalid action: c=create,g=get,s=set,d=del,l=list"); } Database_close(conn); return 0; }



