C语言写数据库
代码】C语言写数据库。fread函数、fwrite函数、fflush函数、C语言的错误机制、atoi函数、结构体嵌套等。
·
//直接上代码 \
C语言写数据库
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h> //断言函数的库
#include<errno.h> //错误机制库
#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:%s\n",message);
}
exit(1); //不正常程序退出
}
void Adress_print(struct Adress* addr){
printf("%d %s %s\n",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<MAX_ROWS;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<MAX_ROWS;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 <dbfile><action> [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;
}
更多推荐
已为社区贡献1条内容
所有评论(0)