学生信息管理系统SIMS
[root@matrix sims]# ll
总计 108
-rwxr-xr-x 1 root root 23947 05-08 23:50 a
-rw-r--r-- 1 root root 198 05-04 12:00 ABOUT
-rw-r--r-- 1 root root 43 05-07 16:44 demo.c
-rw-r--r-- 1 root root 288 05-05 13:58 EXAMPLE
-rw-r--r-- 1 root root 401 05-08 23:50 main.c
-rw-r--r-- 1 root root 291 05-04 20:22 Makefile
-rw-r--r-- 1 root root 17960 05-07 20:17 misc.c
-rw-r--r-- 1 root root 3088 05-07 20:17 misc.h
-rw-r--r-- 1 root root 140 05-04 12:03 README
[root@matrix sims]# make
gcc -c main.c
gcc -c misc.c
gcc -o a main.o misc.o
[root@matrix sims]# a
欢迎使用(学生信息管理系统SIMS)\\\\\\\\
______________________________________________
用户名: root
口令: hacker
认证失败,请检查字母大小写是否正确。
用户名: root
口令: hacking
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 0
[X]记录查询失败!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 1
______________________________________________
当前位置(主页/添加记录)
学号: 101
姓名: Jeff Conrad
性别: M
年龄: 24
电话: 10086
出生(年): 1988
出生(月): 3
出生(日): 24
语文成绩: 78
数学成绩: 78
英语成绩: 88
本次索引节点为1
[V]记录添加成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 1
______________________________________________
当前位置(主页/添加记录)
学号: 102
姓名: Junkie Pro
性别: F
年龄: 25
电话: 10000
出生(年): 1988
出生(月): 4
出生(日): 3
语文成绩: 99
数学成绩: 34
英语成绩: 55
本次索引节点为2
[V]记录添加成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 1
______________________________________________
当前位置(主页/添加记录)
学号: 101
[X]ID冲突!
学号: 103
姓名: Lady GaGa
性别: M
年龄: 35
电话: 12580
出生(年): 1978
出生(月): 8
出生(日): 3
语文成绩: 99
数学成绩: 56
英语成绩: 44
本次索引节点为3
[V]记录添加成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 0
学号 姓名 性别 年龄 电话 出生 语文 数学 英语 节点
......................................................................
101 Jeff Conrad M 24 10086 1988-03-24 78 78 88 1
102 Junkie Pro F 25 10000 1988-04-03 99 34 55 2
103 Lady GaGa M 35 12580 1978-08-03 99 56 44 3
......................................................................
记录: 共3项
[V]记录查询成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 1
关键字: a
学号 姓名 性别 年龄 电话 出生 语文 数学 英语 节点
......................................................................
101 Jeff Conrad M 24 10086 1988-03-24 78 78 88 1
103 Lady GaGa M 35 12580 1978-08-03 99 56 44 3
......................................................................
记录: 共2项
[V]记录查询成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 2
资料: 学号( 0) 姓名( 1) 性别( 2) 年龄( 3) 电话( 4)
生日: 年份( 5) 月份( 6) 号数( 7)
成绩: 语文( 8) 数学( 9) 英语(10)
序号: 2
性别: M
101 Jeff Conrad M 24 10086 1988-03-24 78 78 88 1
103 Lady GaGa M 35 12580 1978-08-03 99 56 44 3
......................................................................
记录: 共2项
[V]记录查询成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 2
______________________________________________
学号: 104
[X]ID无效!
学号: 103
确定删除? (y or n): y
[V]记录删除成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 0
学号 姓名 性别 年龄 电话 出生 语文 数学 英语 节点
......................................................................
101 Jeff Conrad M 24 10086 1988-03-24 78 78 88 1
102 Junkie Pro F 25 10000 1988-04-03 99 34 55 2
......................................................................
记录: 共2项
[V]记录查询成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 3
______________________________________________
学号: 101
姓名: Jeff Conrad
性别: F
年龄: 10086
电话: 10086
出生(年): 1989
出生(月): 3
出生(日): 26
语文成绩: 99
数学成绩: 98
英语成绩: 98
[V]记录修改成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 4
______________________________________________
全部(0) 模糊(1) 条件(2)
查询方式: 0
学号 姓名 性别 年龄 电话 出生 语文 数学 英语 节点
......................................................................
101 Jeff Conrad F 1008610086 1989-03-26 99 98 98 1
102 Junkie Pro F 25 10000 1988-04-03 99 34 55 2
......................................................................
记录: 共2项
[V]记录查询成功!
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 6
______________________________________________
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
功能模块:
增加 删除 修改 查询
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
按下回车键返回:
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 7
______________________________________________
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
欢迎使用SIMS v3
版本: 3.0.0
发行者: Junkie Pro
创建日期: 2013年05月01日
QQ: 614616185
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
按下回车键返回:
______________________________________________
增加(1) 删除(2) 修改(3) 查询(4)
设置(5) 帮助(6) 关于(7) 退出(0)
选项: 0
______________________________________________
______________________________________________
\\\\\\\\感谢使用(学生信息管理系统SIMS)
[root@matrix sims]#
[root@matrix sims]# '/root/project/sims/ABOUT'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
欢迎使用SIMS v3
版本: 3.0.0
发行者: Junkie Pro
创建日期: 2013年05月01日
QQ: 614616185
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[root@matrix sims]# '/root/project/sims/README'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
功能模块:
增加 删除 修改 查询
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[root@matrix sims]# '/root/project/sims/Makefile'
a: misc.h main.o misc.o
gcc -o a main.o misc.o
misc.o: misc.h misc.c
gcc -c misc.c
main.o: misc.h main.c
gcc -c main.c
clean:
rm -f *.o
reset:
rm -f DATABASE.DB
restore:
ls -l EXAMPLE && cp -f EXAMPLE DATABASE.DB && echo RESTORE OK || echo NO EXAMPLE
help:
clear
cat README | more
[root@matrix sims]# '/root/project/sims/DATABASE.DB'
[root@matrix sims]# '/root/project/sims/EXAMPLE'
[root@matrix sims]# '/root/project/sims/main.c'
#include "misc.h"
int main(){
system("clear");
Head();
if (Login("root", "hacking", 3)){//待办----文件
Tail();
return -1;
}
while (1){
DividingLine('_', 1, 46);
Body();
int cn = ChoiceNumber("", OPTION_EXIT, OPTION_ABOUT, 3);
if (-1 == cn){
Tail();
return -1;//建议不在此使用break;以增强程序的扩展性
}
if (Execute(cn))
break;
}
Tail();
return 0;
}
[root@matrix sims]# '/root/project/sims/misc.h'
#ifndef __MISC_H__
#define __MISC_H__
#define DATABASE "DATABASE.DB"
#define TABLE_HEAD 128
#define TABLE_TAIL 256
#define KEYWORD_LIMIT 100//关键字上限为100个字符(百度一下,你就知道)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//enum枚举: 默认从0开始递增, 手动起始值(保险起见)
enum {DATATYPE_CHAR = 0, DATATYPE_INT, DATATYPE_FLOAT, DATATYPE_DOUBLE, DATATYPE_STRING};
enum {OPTION_EXIT = 0, OPTION_ADD, OPTION_DEL, OPTION_EDIT, OPTION_QUERY, OPTION_SETTING, OPTION_HELP, OPTION_ABOUT};
typedef enum {QUERY_ALL, QUERY_LIKE, QUERY_WHERE} query_e;//将QUERY_ALL排在第一位是因为键盘布局
typedef enum {CON_ID = 0, CON_NAME, CON_SEX, CON_AGE, CON_TELEPHONE, CON_YEAR, CON_MONTH, CON_DAY, CON_CHINESE, CON_MATH, CON_ENGLISH, } CONDITION;//看个人习惯,建议设置为0,而不是1
enum {SYMBOL_YES, SYMBOL_NO};//数字数位
typedef struct {size_t year, month, day;} date_s;
typedef struct {
char fill_a:3;
size_t content;
char fill_b:5;
} table_s;
typedef struct {
table_s start;
size_t id;
char name[20];
char sex[4];
size_t age;
char telephone[12];
date_s birth;
struct result_s {
size_t chinese, math, english;
} score;
size_t inode;
table_s end;
} student_s;
int Login(const char *username, const char *password, size_t n);//登录
void CleanStdin(void);//清理stdin流中残留数据
int ClearLF(char *str, size_t n);//清除字符串中'\n'字符 LF(line feed)
int IsNull(const char *str);//检测字符串是否为空
void Head(void);//显示系统头部信息
void Body(void);//显示系统主要信息
void Tail(void);//显示系统退出信息
int ChoiceNumber(const char *prompt, int begin, int end, size_t n);//选择数字
int IsExistID(size_t s_id);//检测ID是否存在
int Edit(size_t n);//修改记录
int Del(size_t n);//删除记录
int Execute(size_t n);//执行对应功能
int IsExistFile(const char *path);//检测文件是否存在
int ReadText(const char *path);//显示文本文件内容
void DividingLine(int c, size_t row, size_t col);//打印分界线
int Add(const size_t etc);//添加记录
int GetData(const char *prompt, int type, void *var, size_t n);//输入数据
int GetString(const char *prompt, char *ptr, size_t len, size_t n);//输入字符串
int ProduceInode(void);//生成索引节点
int CountRecord(void);//统计记录条目
int SearchString(const char *keyword, const char *content);//搜索字符串
void InitCA(char *ca, size_t n);//初始化字符数组
int Query(int flag);//查询所有数据
void ShowMe(const char *path, const char *object);//显示指定文本内容
int ChooseKey(const char *prompt);//获取一个按键
int NumericDigits(int integer, int flag);
int DigitalConversionString(int integer, char *buf, size_t size, int flag);
int ReverseString(char *src, size_t len);//逆转字符串
void Debug(void);
#endif//__MISC_H__
//增加重建索引节点,序列递增修改原始节点号,
//1,3,5//在生成新节点后删除了2号节点
//1,2,3//重建索引节点后
//可以按照索引节点进行数据库排序
[root@matrix sims]# '/root/project/sims/misc.c'
#include "misc.h"
int Login(const char *username, const char *password, size_t n){;
if (!(username && password))
return -1;
size_t len_user = strlen(username),
len_pswd = strlen(password);
if (!(len_user && len_pswd))
return -1;
char rec_user[len_user + 2],
rec_pswd[len_pswd + 2];//多一个字节用于检测用户是否过多输入
size_t siz_user = sizeof(rec_user),
siz_pswd = sizeof(rec_pswd);
while(n--){
printf("用户名: ");
fgets(rec_user, siz_user, stdin);
if (IsNull(rec_user))
if (ClearLF(rec_user, strlen(rec_user)))
CleanStdin();
printf("口令: ");
fgets(rec_pswd, siz_pswd, stdin);
if (IsNull(rec_pswd))
if (ClearLF(rec_pswd, strlen(rec_pswd)))
CleanStdin();
if (strcmp(username, rec_user) || strcmp(password, rec_pswd)){
puts("认证失败,请检查字母大小写是否正确。");
continue;
}
return 0;
}
return -1;
}
void CleanStdin(void){
scanf("%*[^\n]");
scanf("%*c");
}
int ClearLF(char *str, size_t n){
int i = 0;
for (i = 0; i < n; i++)
if ('\n' == str[i]){
str[i] = '\0';
return 0;
}
return -1;
}
int IsNull(const char *str){;
if (!str)
return 0;
return strlen(str) > 0 ? -1 : 0;
}
void Head(void){
puts("欢迎使用(学生信息管理系统SIMS)\\\\\\\\\\\\\\\\");
DividingLine('_', 1, 46);
}
void Body(void){
printf("增加(%d)\t删除(%d)\t修改(%d)\t查询(%d)\n设置(%d)\t帮助(%d)\t关于(%d)\t退出(%d)\n",
OPTION_ADD, OPTION_DEL, OPTION_EDIT, OPTION_QUERY, OPTION_SETTING, OPTION_HELP, OPTION_ABOUT, OPTION_EXIT);
}
void Tail(void){
DividingLine('_', 1, 46);
puts("\\\\\\\\\\\\\\\\感谢使用(学生信息管理系统SIMS)");
}
int ChoiceNumber(const char *prompt, int begin, int end, size_t n){
while(n--){
int num = -1;
printf("%s: ", IsNull(prompt) ? prompt : "选项");
int sv = scanf("%d", &num);
CleanStdin();
if (sv && num >= begin && num <= end)
return num;
printf("[X]错误%s!\n", IsNull(prompt) ? prompt : "选项");
}
return -1;
}
int IsExistID(size_t s_id){
int res = -1;
if (IsExistFile(DATABASE))
return -1;
FILE *fp = fopen(DATABASE, "rb");
if (!fp)
return -1;
student_s t = {};
while(!feof(fp)){
if (1 != fread(&t, sizeof(student_s), 1, fp))
break;
if (s_id == t.id){
res = 0;
break;
}
}
fclose(fp);
fp = NULL;
return res;
}
int Edit(size_t n){;
if (IsExistFile(DATABASE))
return -1;
int dest = -1;
int sid = -1;
while(n--){
if (!GetData("学号", DATATYPE_INT, &sid, 1))
if (!IsExistID(sid)){
dest = 0;
break;
}
else
puts("[X]ID无效!");
}
if (dest)
return -1;
FILE *fp = fopen(DATABASE, "rb+");
if (!fp)
return -1;
student_s tmp = {};
int res = !0;
while (!feof(fp)){
if (1 != fread(&tmp, sizeof(student_s), 1, fp))
break;
if (sid == tmp.id){
res = res &&
!GetString("姓名", tmp.name, sizeof(tmp.name) / sizeof(*tmp.name), 2) &&
!GetString("性别", tmp.sex, sizeof(tmp.sex) / sizeof(*tmp.sex), 2) &&
!GetData("年龄", DATATYPE_INT, &tmp.age, 2) &&
!GetString("电话", tmp.telephone, sizeof(tmp.telephone) / sizeof(*tmp.telephone), 2) &&
!GetData("出生(年)", DATATYPE_INT, &tmp.birth.year, 2) &&
!GetData("出生(月)", DATATYPE_INT, &tmp.birth.month, 2) &&
!GetData("出生(日)", DATATYPE_INT, &tmp.birth.day, 2) &&
!GetData("语文成绩", DATATYPE_INT, &tmp.score.chinese, 2) &&
!GetData("数学成绩", DATATYPE_INT, &tmp.score.math, 2) &&
!GetData("英语成绩", DATATYPE_INT, &tmp.score.english, 2);
if (res){
fseek(fp, -sizeof(student_s), SEEK_CUR);
if (1 == fwrite(&tmp, sizeof(tmp), 1, fp)){
fclose(fp);
fp = NULL;
return 0;
}
}
fclose(fp);
fp = NULL;
return -1;
}
}
}
int Del(size_t n){
size_t sid = 0;
if (IsExistFile(DATABASE))
return -1;
while (n--){
if (!GetData("学号", DATATYPE_INT, &sid, 1)){
if (IsExistID(sid))
puts("[X]ID无效!");
else
break;
}
}
if (-1 == n)
return -1;
n = 3;
int cn = 0;
while(n--){
cn = ChooseKey("确定删除? (y or n)");
if ('n' == cn)
return -1;
else if ('y' == cn)
break;
}
if (-1 == n)
return -1;
FILE *fp = fopen(DATABASE, "rb");
if (!fp){
fclose(fp);
fp = NULL;
return -1;
}
int con = 1;
while (con){
char *tfa = "tmp_";
int tfb = rand();
char tf[strlen(tfa) + NumericDigits(tfb, SYMBOL_NO) + 1];
InitCA(tf, sizeof(tf));
sprintf(tf, "%s%d", tfa, tfb);
tf[sizeof(tf) - 1] = 0;
if (IsExistFile(tf)){
con = 0;
FILE *dest = fopen(tf, "wb+");
if (!dest)
return -1;
FILE *src = fopen(DATABASE, "rb");
if (!src){
fclose(dest);
dest = NULL;
return -1;
}
student_s ts = {};
while(!feof(src)){
if (1 != fread(&ts, sizeof(student_s), 1, src))
break;
if (sid != ts.id)
if (1 != fwrite(&ts, sizeof(student_s), 1, dest))
break;
}
fclose(dest);
fclose(src);
dest = src = NULL;
remove(DATABASE);
rename(tf, DATABASE);
return 0;
}
}
return -1;
}
int Execute(size_t n){
DividingLine('_', 1, 46);
switch(n){
case OPTION_EXIT:
return -1;
case OPTION_ADD:
if (Add(3))
puts("[X]记录添加失败!");
else
puts("[V]记录添加成功!");
break;
case OPTION_DEL:
if (Del(3))
puts("[X]记录删除失败!");
else
puts("[V]记录删除成功!");
break;
case OPTION_EDIT:
if (Edit(3))
puts("[X]记录修改失败!");
else
puts("[V]记录修改成功!");
break;
case OPTION_QUERY:
printf("全部(%d) 模糊(%d) 条件(%d)\n", QUERY_ALL, QUERY_LIKE, QUERY_WHERE);
query_e flag = QUERY_ALL;
flag = ChoiceNumber("查询方式", QUERY_ALL, QUERY_WHERE, 3);
if (CountRecord() <= 0 || Query(flag))//目前可以省略CountRecord();该形式表达式可以在其它功能中采用
puts("[X]记录查询失败!");
else
puts("[V]记录查询成功!");
break;
case OPTION_SETTING:
puts("初始化数据库?");
break;
case OPTION_HELP:
ShowMe("README", "帮助文档");
break;
case OPTION_ABOUT:
ShowMe("ABOUT", "关于文档");
break;
default:;
}
return 0;//为了扩展性暂时不写在default范围内
}
int IsExistFile(const char *path){;
if (!IsNull(path))
return -1;
FILE *fp = fopen(path, "r");
if (fp){
fclose(fp);
fp = NULL;
return 0;
}
return -1;
}
int ReadText(const char *path){
FILE *fp = fopen(path, "rt");
int c = -1;
if (fp){
while((c = fgetc(fp)) != EOF)
putc(c, stdout);
fclose(fp);
fp = NULL;
}
else
return -1;
return 0;
}
void DividingLine(int c, size_t row, size_t col){
int i = 0;
while (row--){
for (i = 0; i < col; i++)
printf("%c", c);
puts("");
}
}
int Add(const size_t etc){
puts("当前位置(主页/添加记录)");//可以使用函数来改写
FILE *fp = NULL;
if (IsExistFile(DATABASE)){
fp = fopen(DATABASE, "wb+");
if (!fp)
return -1;
}
else {
fp = fopen(DATABASE, "ab+");//追加总是在末尾写入,rb+覆盖写入,不允许追加,在原有基础上修改
if (!fp)
return -1;
}
int n = etc;
//使用结构体指针,巩固知识点。
student_s dat = {0};
dat.start.content = TABLE_HEAD;
dat.end.content = TABLE_TAIL;
int res = 0;
int tms = 2;
while(tms--){
if (!GetData("学号", DATATYPE_INT, &dat.id, 1))
if (IsExistID(dat.id)){
res = !0;
break;
}
else
puts("[X]ID冲突!");
}
res = res &&
!GetString("姓名", dat.name, sizeof(dat.name) / sizeof(*dat.name), 2) &&
!GetString("性别", dat.sex, sizeof(dat.sex) / sizeof(*dat.sex), 2) &&
!GetData("年龄", DATATYPE_INT, &dat.age, 2) &&
!GetString("电话", dat.telephone, sizeof(dat.telephone) / sizeof(*dat.telephone), 2) &&
!GetData("出生(年)", DATATYPE_INT, &dat.birth.year, 2) &&
!GetData("出生(月)", DATATYPE_INT, &dat.birth.month, 2) &&
!GetData("出生(日)", DATATYPE_INT, &dat.birth.day, 2) &&
!GetData("语文成绩", DATATYPE_INT, &dat.score.chinese, 2) &&
!GetData("数学成绩", DATATYPE_INT, &dat.score.math, 2) &&
!GetData("英语成绩", DATATYPE_INT, &dat.score.english, 2) &&
!(-1 == (dat.inode = ProduceInode()));//在即将写入文件时删除数据文件返回失败状态(-1)
if (res){
if (1 != fwrite(&dat, sizeof(student_s), 1, fp)){
puts("[X]写入数据时发生错误!");
fclose(fp);
fp = NULL;//FILE*关闭后仍可用,虽不能真正写入文件,但程序可能照常运行,置为空指针,则写入是会段错误,便于发现潜在隐患
return -1;
}
printf("本次索引节点为%d\n", dat.inode);
fclose(fp);
fp = NULL;
return 0;
}
fclose(fp);
fp = NULL;
return -1;
}
int GetData(const char *prompt, int type, void *var, size_t n){
while (n--){
printf("%s: ", prompt);
int is = 0;
switch (type){
case DATATYPE_CHAR:
is = scanf("%c", var);
break;
case DATATYPE_INT:
is = scanf("%d", var);
break;
case DATATYPE_FLOAT:
case DATATYPE_DOUBLE:
is = scanf("%f", var);
break;
case DATATYPE_STRING:
//is = fgets/scanf("%s")
break;
default:
return -1;
}
CleanStdin();
if (is)
return 0;
puts("[X]输入错误!");
}
return -1;
}
int GetString(const char *prompt, char *ptr, size_t len, size_t n){
while(n--){
printf("%s: ", prompt);
fgets(ptr, len, stdin);
if (IsNull(ptr)){
if (ClearLF(ptr, strlen(ptr)))
CleanStdin();
if (IsNull(ptr))
return 0;
}
}
return -1;
}
int ProduceInode(void){;
size_t inode = 0;
if (IsExistFile(DATABASE))
return -1;
FILE *fp = fopen(DATABASE, "rb");
if (!fp)
return -1;
student_s t = {};
while(!feof(fp))
if (1 == fread(&t, sizeof(student_s), 1, fp))
inode = t.inode > inode ? t.inode : inode;
fclose(fp);
fp = NULL;
return ++inode;
}
int CountRecord(void){;
size_t count = 0;
if (IsExistFile(DATABASE))
return -1;
FILE *fp = fopen(DATABASE, "rb");
if (!fp)
return -1;
student_s t;
while(!feof(fp))
if (1 == fread(&t, sizeof(student_s), 1, fp)){
if (t.start.content != TABLE_HEAD || t.end.content != TABLE_TAIL)//主要检测表头
return -1;
count++;
}
if (ftell(fp) != count * sizeof(student_s))//检测表尾
return -1;
fclose(fp);
fp = NULL;
return count;
}
int SearchString(const char *keyword, const char *content){;
if (!(IsNull(keyword) && IsNull(content)))
return -1;
size_t len_k = strlen(keyword),
len_c = strlen(content);
if (len_k > len_c)
return -1;
int i = 0, j = 0;
char match[len_k + 1];
for (i = 0; i < len_c - len_k + 1; i++){//关系类型: 一对多
InitCA(match, sizeof(match));
for (j = i; j < i + len_k; j++)
match[j - i] = content[j];
match[j - i] = 0;
if (!strcmp(match, keyword))
return 0;
}
return -1;
}
void InitCA(char *ca, size_t n){
int i = 0;
for (i = 0; i < n; i++)
ca[i] = 0;
}
//usleep(500000);//睡眠0.1秒钟
//检测字段是否为ASCII字符集中数据,否则认为是汉子,占用不同的位宽//编写整数转换字符串函数sprintf
int Query(int flag){;
if (CountRecord() <= 0)
return -1;
FILE *fp = fopen(DATABASE, "rb");
if (!fp)
return -1;
student_s t = {};
size_t cnt = 0;
void Header(void){
puts("学号 姓名 性别 年龄 电话 出生 语文 数学 英语 节点");
DividingLine('.', 1, 70);
}
void Footer(const char *NullPrompt){
DividingLine('.', 1, 70);
if (!cnt)
if (IsNull(NullPrompt))
puts(NullPrompt);
else
puts("[*]数据库文件已发生变化!");
printf("记录: 共%u项\n", cnt);
}
void format(char *buf){//根据非ASCII字符个数和ASCII个数来确定%s,其它数据类型保持不变
}
int SAll(void){
Header();
while (!feof(fp)) {
if (1 != fread(&t, sizeof(student_s), 1, fp))
break;
printf("%-5u%-13s%-5s%-5u%-12s%04u-%02u-%02u %-5u%-5u%-5u%-3u\n", t.id, t.name, t.sex, t.age, t.telephone, t.birth.year, t.birth.month, t.birth.day, t.score.chinese, t.score.math, t.score.english, t.inode), cnt++;
}
fclose(fp);
fp = NULL;
Footer(NULL);
return 0;
}
int SLike(const char *keyword){
Header();
char buf[KEYWORD_LIMIT + 1] = {0};
while (!feof(fp)) {
if (1 != fread(&t, sizeof(student_s), 1, fp))
break;
int c = -1;
#define MATCHING(Flag, Var) \
InitCA(buf, sizeof(buf)); \
sprintf(buf, #Flag, Var); \
/*printf("正在匹配第%d项中的%s\n", ftell(fp) / sizeof(student_s), #Var);*/ \
c = c && SearchString(keyword, buf); \
if (!c) break;//该行语句属于宏MATCHING
int wc = 1;
while (wc--){
MATCHING(%u, t.id);
MATCHING(%s, t.name);
MATCHING(%s, t.sex);
MATCHING(%u, t.age);
MATCHING(%s, t.telephone);
MATCHING(%u, t.birth.year);
MATCHING(%u, t.birth.month);
MATCHING(%u, t.birth.day);
MATCHING(%u, t.score.chinese);
MATCHING(%u, t.score.math);
MATCHING(%u, t.score.english);
}
if (!c)
printf("%-5u%-13s%-5s%-5u%-12s%04u-%02u-%02u %-5u%-5u%-5u%-3u\n", t.id, t.name, t.sex, t.age, t.telephone, t.birth.year, t.birth.month, t.birth.day, t.score.chinese, t.score.math, t.score.english, t.inode), cnt++;
}
fclose(fp);
fp = NULL;
Footer("[*]没有匹配内容!");
return 0;
}
int SWhere(void){
#define PREC printf("%-5u%-13s%-5s%-5u%-12s%04u-%02u-%02u %-5u%-5u%-5u%-3u\n", src.id, src.name, src.sex, src.age, src.telephone, src.birth.year, src.birth.month, src.birth.day, src.score.chinese, src.score.math, src.score.english, src.inode), cnt++;
printf("资料: 学号(%2d) 姓名(%2d) 性别(%2d) 年龄(%2d) 电话(%2d) \n生日: 年份(%2d) 月份(%2d) 号数(%2d) \n成绩: 语文(%2d) 数学(%2d) 英语(%2d)\n",
CON_ID, CON_NAME, CON_SEX, CON_AGE, CON_TELEPHONE, CON_YEAR, CON_MONTH, CON_DAY, CON_CHINESE, CON_MATH, CON_ENGLISH);
int cn = ChoiceNumber("序号", CON_ID, CON_ENGLISH, 3);
if (-1 == cn)
return -1;
student_s dest = {0}, src = {0};
int res = -1;
#define DECIDE(C) \
if (-1 == (C)) {\
fclose(fp); \
fp = NULL; \
return -1; \
}
#define DPI(arg1, arg2) \
while (!feof(fp)) {\
if (1 != fread(&src, sizeof(student_s), 1, fp)) break;\
if (arg1 == arg2) PREC;}
#define DPS(arg1, arg2) \
while (!feof(fp)) {\
if (1 != fread(&src, sizeof(student_s), 1, fp)) break;\
if (!strcmp(arg1, arg2)) PREC;}
switch (cn) {
case CON_ID:
DECIDE(GetData("学号", DATATYPE_INT, &dest.id, 2));
DPI(dest.id, src.id);
break;
case CON_NAME:
DECIDE(GetString("姓名", dest.name, sizeof(dest.name) / sizeof(*dest.name), 2));
DPS(dest.name, src.name);
break;
case CON_SEX:
DECIDE(GetString("性别", dest.sex, sizeof(dest.sex) / sizeof(*dest.sex), 2));
DPS(dest.sex, src.sex);
break;
case CON_AGE:
DECIDE(GetData("年龄", DATATYPE_INT, &dest.age, 2));
DPI(dest.age, src.age);
break;
case CON_TELEPHONE:
DECIDE(GetString("电话", dest.telephone, sizeof(dest.telephone) / sizeof(*dest.telephone), 2));
DPS(dest.telephone, src.telephone);
break;
case CON_YEAR:
DECIDE(GetData("年份", DATATYPE_INT, &dest.birth.year, 2));
DPI(dest.birth.year, src.birth.year);
break;
case CON_MONTH:
DECIDE(GetData("月份", DATATYPE_INT, &dest.birth.month, 2));
DPI(dest.birth.month, src.birth.month);
break;
case CON_DAY:
DECIDE(GetData("号数", DATATYPE_INT, &dest.birth.day, 2));
DPI(dest.birth.day, src.birth.day);
break;
case CON_CHINESE:
DECIDE(GetData("语文", DATATYPE_INT, &dest.score.chinese, 2));
DPI(dest.score.chinese, src.score.chinese);
break;
case CON_MATH:
DECIDE(GetData("数学", DATATYPE_INT, &dest.score.math, 2));
DPI(dest.score.math, src.score.math);
break;
case CON_ENGLISH:
DECIDE(GetData("英语", DATATYPE_INT, &dest.score.english, 2));
DPI(dest.score.english, src.score.english);
break;
}
fclose(fp);
fp = NULL;
Footer("[*]没有匹配内容!");
return 0;
}
if (QUERY_ALL == flag){
return SAll();
}
else if (QUERY_LIKE == flag){
char keyword[KEYWORD_LIMIT + 1];
InitCA(keyword, sizeof(keyword));
if (GetString("关键字", keyword, sizeof(keyword), 3)){
fclose(fp);
fp = NULL;
return -1;
}
return SLike(keyword);
}
else if (QUERY_WHERE == flag){
return SWhere();
}
else
return -1;
}
void ShowMe(const char *path, const char *object){
if (IsExistFile(path)){
printf("[X]打开%s失败!\n", object);
return ;
}
ReadText(path);
ChooseKey(NULL);
}
int ChooseKey(const char *prompt){
int c = 0;
if (!IsNull(prompt))
prompt = "按下回车键返回";
printf("%s: ", prompt);
if ('\n' != (c = fgetc(stdin)))
CleanStdin();
return c;
}
int NumericDigits(int integer, int flag){//条件查询可能不用这个函数,条件查询中直接比较两个值是否完全相等,包含数据类型
int count = 0;
if (SYMBOL_YES == flag)//仅限于符号
count = integer < 0 ? 1 : 0;
else if (SYMBOL_NO == flag);
else
return -1;
integer = integer < 0 ? -1 * integer : integer;
do {
count++;
integer /= 10;
} while (integer);
return count;
}
int DigitalConversionString(int integer, char *buf, size_t size, int flag){//字符串转换数字,使用逆向算法即可int-'0'
InitCA(buf, size);
if (SYMBOL_YES == flag){
if (integer < 0)
*buf++ = '-';
}
else if (SYMBOL_NO == flag);
else
return -1;
integer = integer < 0 ? -1 * integer : integer;//可以省略该条语句,直接对负数操作效果一样
do {
*buf++ = '0' + integer % 10;
integer /= 10;
} while (integer);
return 0;
}
int ReverseString(char *src, size_t len){//将来为了支持WHERE *str*;
char buf[len + 1];
InitCA(buf, sizeof(buf));
strcpy(buf, src);
int i = 0;
for (i = 0; i < len; i++){
src[i] = buf[len - i - 1];
}
puts(buf);
puts(src);
}
void Debug(void){
int i = -54321;
int is = NumericDigits(i, SYMBOL_YES);
char buf[is + 1];
printf("-----%d\n", sizeof(buf));
DigitalConversionString(i, buf, is, SYMBOL_YES);
DigitalConversionString(i, buf, is, SYMBOL_YES);
puts(buf);
ReverseString(buf, strlen(buf));
}