c - 如何用C语言调试一个简单的数据库?

标签 c database debugging struct

这是一个 C 语言程序,它将所有数据库(结构)放入文件并随后读取,但是当我通过以下方式执行它时:(编译后)

a ab.txt w 1 abc abc@me.com

程序崩溃并停止工作 <windows>

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>

struct Rows{
int id;
int state;
char* name;
char* email;
};


struct database{
struct Rows rows[200];
};

struct connection{
FILE* fil;
struct database *db;
};
size_t dbsize = sizeof(struct database*);

void die(char* err){
if(errno)perror(err);
else fprintf(stderr,err);
exit(0);
}


struct connection fileopener(char* filename,char mode){
struct connection conn;
if(mode=='w')conn.fil=fopen(filename,"a+");
else conn.fil=fopen(filename,"r+");
return conn;
}

void writetof(struct connection conn){
int rc =fwrite(conn.db,dbsize,1,conn.fil);
if(rc!=1)die("cannot write");
rc = fflush(conn.fil);
if(rc==-1) die("cannot flush");
} 

void writetodb(struct connection conn,int id ,char*name,char* email){
if(conn.db->rows[id].state = =1)die("already written");
conn.db->rows[id].state=1;
conn.db->rows[id].id=id;
conn.db->rows[id].name = strdup(name);
conn.db->rows[id].email = strdup(email);
}

void delete(struct connection conn,int id){
conn.db->rows[id].state=0;
}

void readfrom(struct connection conn,int id){
if(conn.db->rows[id].state==0)die(" no record sorry");
else {
printf("id\tname\temail\n");
printf("%d\t%s\t%s\n", conn.db->rows[id].id,conn.db->rows[id].name,conn.db->rows[id].email);
}
}

void printall(struct connection conn){
int i =0;
printf("id\tname\\temail\n");
for(;i<200;i++){
if(conn.db->rows[i].state==1){
printf("%d\t%s\t%s\t",conn.db->rows[i].id,conn.db->rows[i].name,conn.db->rows[i].email);
}
}
if(i==0)die("no records");
}

void init(struct connection conn){
int i ;
for(i=0;i<200;i++){
conn.db->rows[i].id=i;
conn.db->rows[i].state=0;
}
} 

int main(int argc,char* argv[]){
if(argc<3)die("need filename and mode");
char* filename = argv[1];
char mode = argv[2];
struct connection conn = fileopener(filename,mode);
init(conn);
int mid;
fread(conn.db,dbsize,1,conn.fil);
if(argc>3)mid = atoi(argv[3]);
switch(mode){
case 'w':
if(argc<6)die("need data to be written <id> <name> <email>");
writetodb(conn,mid,argv[4],argv[5]);
writetof(conn);
break;
case 'r':
if(argc<3)die("need id");
readfrom(conn,mid);
break;
case 'p':
printall(conn);
case 'd':
delete(conn,mid);
break;
default:
die("mode should be w , r , p d");
}
return 0;
}

最佳答案

我看到的问题:

检查fopen返回值失败

你有:

struct connection fileopener(char* filename,char mode){
   struct connection conn;
   if(mode=='w')conn.fil=fopen(filename,"a+");
   else conn.fil=fopen(filename,"r+");
   return conn;
}

我建议在那里添加一个检查来处理打开文件失败的情况。

struct connection fileopener(char* filename,char mode){
   struct connection conn;
   if(mode=='w')conn.fil=fopen(filename,"a+");
   else conn.fil=fopen(filename,"r+");
   if ( conn.fil == NULL )
   {
      die("cannot open file");
   }
   return conn;
}

使用未初始化的指针

你有

void init(struct connection conn){
   int i ;
   for(i=0;i<200;i++){
      conn.db->rows[i].id=i;
      conn.db->rows[i].state=0;
   }
} 

此时conn.db尚未初始化。在使用它之前,您需要为其分配内存。将其更改为:

void init(struct connection* conn){
   int i ;
   conn->db = malloc(sizeof(*(conn->db)));
   for(i=0;i<200;i++){
      conn->db->rows[i].id=i;
      conn->db->rows[i].state=0;
   }
} 

我建议将参数类型更改为指针并为其分配内存。否则,为 conn.db 分配的内存将仅用于对象的本地副本,而不是 main 中的对象。

这意味着将 main 中对 init 的调用更改为:

init(&conn);

关于c - 如何用C语言调试一个简单的数据库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37451630/

相关文章:

c - 如何在 C/C++ 中暂停循环

sql-server - 为什么 "String or Binary data would be truncated"不是一个更具描述性的错误?

linux - -O1 和内联汇编程序的 GCC 段错误

java - 无法通过 Dockerized WebLogic 将 Debug 设置为适用于 Java,不能使用 IntelliJ 或 Studio Code

c++ - 无法弄清楚我的代码有什么问题

c - 将指针设置为 NULL,以便指向该地址的任何指针都为 NULL

c - 带有 2 个客户端的 UDP 服务器,如何为它们分配特定端口

c - 读取和写入动态分配的数组

SQL Server - 根据最近日期连接两个表

ruby - 使用 Ruby XMLRPC 使用开发人员 key 查找 UPC 数据库