C++ 开发篇+一个简单的数据库管理系统ZDB

说明:本文供数据库爱好者和初级开发人员学习使用
标签:数据库管理系统、RDBMS、小程序、C++、C++程序
系统:Windows 11 x86
CPU :Intel
IDE :Visual Studio 2022
语言:C++语言
标准:C++14
提示:如果您发现本文哪里写的有问题或者有更好的写法请留言或私信我进行修改优化


★ 程序界面

★ 功能简介

目前该C语言小程序实现了RDBMS上表的几个基础功能,如:
✔ DDL:create、drop、alter、truncate、flashback、rename、purge
✔ DML:insert、delete、update、select

★ 程序特点

✔ 程序会在首次运行时在同级创建一个目录用于存放数据库信息
✔ 程序运行期间表数据存储在内存中,类似于Redis
✔ 程序运行结束时会将表数据采用序列化方式存储为JSON格式落盘
✔ 程序采用vector实现表空间的动态调整
✔ 表在drop后purge前支持闪回,purge后相关空间可以复用
✔ 表记录在删除后只是标记为删除,方便后期复用并减少数据shrink的性能消化

★ 程序试用

https://download.csdn.net/download/zzt_2009/88971223

★ 使用案例

############【欢迎使用 ZDB】############
# 语言:C++              IDE :VS 2022 #
# 作者:zzt_2009         版本:V 6.0.0 #
# 主页:https://blog.csdn.net/zzt_2009 #
# [H/h]查看帮助          [E/e]退出程序 #
首次使用,正在初始化数据字典……
字典落盘成功!
字典文件初始化完成。
字典加载成功!
首次使用,正在初始化数据文件……
数据写入成功:写入了【1】个表
数据文件初始化完成。
首次使用,已为您显示帮助信息:
# L   For > list table def   #
# C   For > Create table     #
# D   For > Drop table       #
# A   For > Alter table      #
# R   For > Rename table     #
# T   For > Truncate table   #
# F   For > Flashback table  #
# P   For > Purge recyclebin #
# i   For > insert           #
# d   For > delete           #
# u   For > update           #
# s   For > select           #
# c   For > clear            #
# H/h For > help             #
# E/e For > exit             #
数据读取成功:加载了【1】个表
当前表空间:总大小为【1】,剩余空间【0】
SQL > L
# 库中所有状态的表信息如下
内存ID  表名 表状态 表编号 行数    列数
TMID[0] T0   STA[2] OID[0] ROWS[3] COLS[2]
# STA列值:1>新/空表、2>有数据、3>已删除、4>可复用
SQL > C
请输入表名:T1
表空间已满,已自动扩容!
当前表空间大小为:2
请输入列的[数量]:2
请输入第[1]列的[名称]:ID
请输入第[2]列的[名称]:NAME
表TMID:1,表OID:2字典落盘成功!
数据写入成功:写入了【2】个表
SQL > C
请输入表名:T2
表空间已满,已自动扩容!
当前表空间大小为:3
请输入列的[数量]:2
请输入第[1]列的[名称]:ID
请输入第[2]列的[名称]:NAME
表TMID:2,表OID:3字典落盘成功!
数据写入成功:写入了【3】个表
SQL > D
请输入表名:T1
已删除
字典落盘成功!
数据写入成功:写入了【3】个表
SQL > A
请输入表名:T2
请输入CID(列号): 2
请输入字段新值: NAME2
# 更新后表结构和数据如下:
R[00] RMID[00] : ID     NAME2
# Selected:[0]ROWS,[2]COLS
字典落盘成功!
数据写入成功:写入了【3】个表
SQL > F
请输入表OID: 1
表已闪回
字典落盘成功!
数据写入成功:写入了【3】个表
SQL > L
# 库中所有状态的表信息如下
内存ID  表名 表状态 表编号 行数    列数
TMID[0] T0   STA[2] OID[0] ROWS[3] COLS[2]
TMID[1] 1    STA[1] OID[1] ROWS[0] COLS[2]
TMID[2] T2   STA[1] OID[2] ROWS[0] COLS[2]
# STA列值:1>新/空表、2>有数据、3>已删除、4>可复用
SQL > R
请输入表名:1
请输入新名:T1
# 更新成功:
# 库中所有状态的表信息如下
内存ID  表名 表状态 表编号 行数    列数
TMID[0] T0   STA[2] OID[0] ROWS[3] COLS[2]
TMID[1] T1   STA[1] OID[1] ROWS[0] COLS[2]
TMID[2] T2   STA[1] OID[2] ROWS[0] COLS[2]
# STA列值:1>新/空表、2>有数据、3>已删除、4>可复用
字典落盘成功!
数据写入成功:写入了【3】个表
SQL > D
请输入表名:T1
已删除
字典落盘成功!
数据写入成功:写入了【3】个表
SQL > L
# 库中所有状态的表信息如下
内存ID  表名 表状态 表编号 行数    列数
TMID[0] T0   STA[2] OID[0] ROWS[3] COLS[2]
TMID[1] T1   STA[3] OID[1] ROWS[0] COLS[2]
TMID[2] T2   STA[1] OID[2] ROWS[0] COLS[2]
# STA列值:1>新/空表、2>有数据、3>已删除、4>可复用
SQL > P
回收站已清空!
字典落盘成功!
数据写入成功:写入了【3】个表
SQL > L
# 库中所有状态的表信息如下
内存ID  表名 表状态 表编号 行数    列数
TMID[0] T0   STA[2] OID[0] ROWS[3] COLS[2]
TMID[1] T1   STA[4] OID[1] ROWS[0] COLS[2]
TMID[2] T2   STA[1] OID[2] ROWS[0] COLS[2]
# STA列值:1>新/空表、2>有数据、3>已删除、4>可复用
SQL > i
请输入表名:T2
请输入数据(列以空格分隔,新行输入';'结束):
Input > 1 a
Input > 2 b
Input > ;
插入结束!
字典落盘成功!
数据写入成功:写入了【3】个表
R[00] RMID[00] : ID     NAME2
R[01] RMID[01] : 1      a
R[02] RMID[02] : 2      b
# Selected:[2]ROWS,[2]COLS
SQL > s
请输入表名:T0
R[00] RMID[00] : TEL    NAME
R[01] RMID[01] : 110    Police
R[02] RMID[02] : 120    Ambulance
R[03] RMID[03] : 119    Fire
# Selected:[3]ROWS,[2]COLS
SQL > d
请输入表名:T0
请输入RMID(内存行号): 2
# RMID[2]已删除
# 删除后表数据如下:
R[00] RMID[00] : TEL    NAME
R[01] RMID[01] : 110    Police
R[02] RMID[03] : 119    Fire
# Selected:[2]ROWS,[2]COLS
字典落盘成功!
数据写入成功:写入了【3】个表
SQL > e
字典落盘成功!
数据写入成功:写入了【3】个表
#########【感谢使用 ZDB 再见!】#########

D:\WorkSpace\C++\ZDB\x64\Debug\ZDB.exe (进程 24820)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

★ 程序源码

//引用头文件
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>  
#include <direct.h> 
#include <string>
#include <iostream> 
#include <vector> 
#include <fstream> 
#include <cstdio>  
#include <sstream>  
#include <nlohmann/json.hpp> //详情:https://github.com/nlohmann/json

using json = nlohmann::json;
using namespace std;

//禁用部分警告
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

//使用宏定义代替相关内容
#define R 99  //行
#define C 99  //列
#define N 32  //名称
#define L 99  //长度
#define S 32  //SIZE
#define DefaultPATH ".\\ZDATA\\"

//全局变量
int i, j, k = 0; //
int ts; //
int fr, fc = 0; //文件行数,文件列数
int rn, cn = 0; //行号、列号
int oid, noid = 0; //全局对象号、内存号
char g_temp[L]; //临时使用的字符串变量
char table_name[N]; //表名
char Path[L];
char dict_file[N] = "ZDB.dic"; //文件名
char data_file[N] = "ZDB.dat"; //文件名
typedef struct S_Dict { //字典:结构体
	int state;			//状态:0>未分配、1>有效、2>删除
	char name[N];		//名称
	char value[L];		//值
	char comment[L];	//描述
} S_Dict;
S_Dict g_dict[S];
class S_Table {
	//成员变量
public:
	int state;			 //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
	string name;		 //名称
	int oid;			 //对象编号
	int rows;			 //行数
	int cols;			 //列数
	string record[R][C]; //数据&状态:"">未分配、H>字段名、A>可用、D>删除
	//成员方法to_json(),用于将S_Table实例转换为JSON对象
	json to_json() const {
		json j_record = json::array();
		for (int r = 0; r <= rows; ++r) {
			json j_row = json::array();
			for (int c = 0; c <= cols; ++c) {
				j_row.push_back(record[r][c]);
			}
			j_record.push_back(j_row);
		}
		return json{ {"state", state}, {"name", name}, {"oid", oid}, {"rows", rows}, {"cols", cols}, {"record", j_record} };
	}
	//成员方法from_json(),用于将JSON对象转换为S_Table实例
	static S_Table from_json(const json& j) {
		S_Table table;
		table.state = j["state"].get<int>();
		table.name = j["name"].get<std::string>();
		table.oid = j["oid"].get<int>();
		table.rows = j["rows"].get<int>();
		table.cols = j["cols"].get<int>();
		for (int r = 0; r <= table.rows; ++r) {
			for (int c = 0; c <= table.cols; ++c) {
				table.record[r][c] = j["record"][r][c];
			}
		}
		return table;
	}
};

//函数声明
int Head(); //界面输出
int Body(vector<S_Table>& v_tables); //程序主体
int Bye(); //程序退出
int Help(); //
int Dir_Init(); //
int Dict_Init(); //
int Dict_Read(); //
int Dict_Write(); //
int Data_Init(vector<S_Table>& v_tables); //
int Data_Read(vector<S_Table>& v_tables); //
int Data_Write(vector<S_Table>& v_tables); //
int List_Table(vector<S_Table>& v_tables); //
int Select(string table_name, vector<S_Table>& v_tables); //
int Create(string table_name, vector<S_Table>& v_tables); //
int Drop(string table_name, vector<S_Table>& v_tables); //
int Alter(string table_name, vector<S_Table>& v_tables); //
int Flashback(int oid, vector<S_Table>& v_tables); //
int Purge(vector<S_Table>& v_tables); //
int Truncate(string table_name, vector<S_Table>& v_tables); //
int Rename(string table_name, vector<S_Table>& v_tables); //
int Insert(string table_name, vector<S_Table>& v_tables); //
int Delete(string table_name, vector<S_Table>& v_tables); //
int Update(string table_name, vector<S_Table>& v_tables); //

//主函数
int main() {
	Head();
	Dict_Read();
	//根据表空间大小配置 vector 数组大小
	ts = atoi(g_dict[1].value);
	vector<S_Table> v_tables(ts);
	//往 vector 数组中读取数据
	Data_Read(v_tables);
	Body(v_tables);
	return 0;
}

//函数定义
int Body(vector<S_Table>& v_tables) {
	//命令判断
	while (1) {
		printf("SQL > ");
		int n;
		n = _getch();
		printf("%c\n", (char)n); //输出按键
		switch (n) {
		case 76: // L -> list table defination
			List_Table(v_tables);
			break;
		case 67: // C -> create
			std::cout << "请输入表名:";
			std::cin >> table_name;
			Create(table_name, v_tables);
			break;
		case 68: // D -> drop
			std::cout << "请输入表名:";
			std::cin >> table_name;
			Drop(table_name, v_tables);
			break;
		case 65: // A -> alter
			std::cout << "请输入表名:";
			std::cin >> table_name;
			Alter(table_name, v_tables);
			break;
		case 70: // F -> flashback
			std::cout << "请输入表OID: ";
			std::cin >> oid;
			Flashback(oid, v_tables);
			break;
		case 80: // P -> purge
			Purge(v_tables);
			break;
		case 84: // T -> truncate
			std::cout << "请输入表名:";
			std::cin >> table_name;
			Truncate(table_name, v_tables);
			break;
		case 82: // R -> rename
			std::cout << "请输入表名:";
			std::cin >> table_name;
			Rename(table_name, v_tables);
			break;
		case 105: // i -> insert
			std::cout << "请输入表名:";
			std::cin >> table_name;
			Insert(table_name, v_tables);
			break;
		case 100: // d -> delete
			std::cout << "请输入表名:";
			std::cin >> table_name;
			Delete(table_name, v_tables);
			break;
		case 117: // u -> update
			std::cout << "请输入表名:";
			std::cin >> table_name;
			Update(table_name, v_tables);
			break;
		case 115: // s -> select
			std::cout << "请输入表名:";
			std::cin >> table_name;
			Select(table_name, v_tables);
			break;
		case 99: // c -> clear
			Head();
			break;
		case 72:  // H -> help
		case 104: // h -> help
			Help();
			break;
		case 69:  // E -> exit
		case 101: // e -> exit
			Dict_Write();
			Data_Write(v_tables);
			Bye();
			exit(0);
		default:
			printf("命令不正确请重新输入,或按[H/h]查看帮助\n");
			break;
		}
	}
}

int Update(string table_name, vector<S_Table>& v_tables) {
	i = 0;
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		if ((v_tables[i].name == table_name) && ((v_tables[i].state == 2) || (v_tables[i].state == 1))) { //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
			//存在则继续处理
			std::cout << "请输入RMID(内存行号): ";
			std::cin >> rn;
			std::cout << "请输入CID(列号): ";
			std::cin >> cn;
			std::cout << "请输入字段新值: ";
			std::cin >> g_temp;
			if (v_tables[i].state == 1) {
				printf("# 空表,无法DML!\n");
				return 0;
			}
			if ((rn != 0) && (cn != 0) && (v_tables[i].record[rn][0] == "A")) { //数据&状态:"">未分配、H>字段名、A>可用、D>删除
				v_tables[i].record[rn][cn] = g_temp;
				printf("# 更新后表数据如下:\n");
				Select(table_name, v_tables);
				//写盘
				Dict_Write();
				Data_Write(v_tables);
				return 0;
			}
			printf("不容许DML的位置!\n");
			return 0;
		}
		i++;
	}
	printf("表不存在!\n");
	return 0;
}

int Delete(string table_name, vector<S_Table>& v_tables) {
	i = 0;
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		if ((v_tables[i].name == table_name) && ((v_tables[i].state == 2) || (v_tables[i].state == 1))) { //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
			if (v_tables[i].state == 1) {
				printf("# 空表,无法DML!\n");
				return 0;
			}
			std::cout << "请输入RMID(内存行号): ";
			std::cin >> rn;
			if (rn != 0) {
				v_tables[i].record[rn][0] = "D";
				printf("# RMID[%d]已删除\n", rn);
				printf("# 删除后表数据如下:\n");
				Select(table_name, v_tables);
				Dict_Write();
				Data_Write(v_tables);
				return 0;
			}
			printf("首行为列名不容许删除!\n");
			return 0;
		}
		i++;
	}
	printf("表不存在!\n");
	return 0;
}

int Insert(string table_name, vector<S_Table>& v_tables) {
	size_t i = 0;
	while (i < v_tables.size() && (v_tables[i].state != 0)) {
		if ((v_tables[i].name == table_name) && (v_tables[i].state == 1 || v_tables[i].state == 2)) {
			int num_cols = v_tables[i].cols;
			cout << "请输入数据(列以空格分隔,新行输入';'结束):" << endl;
			string input_line;
			cin.ignore();
			cout << "Input > ";
			while (getline(cin, input_line) && input_line != ";") {
				stringstream ss(input_line);
				string item;
				rn = 1;
				cn = 1;
				while (rn < R) {
					if (v_tables[i].record[rn][0] == "D" || v_tables[i].record[rn][0].empty()) {
						break;
					}
					rn++;
				}
				if (rn >= R) {
					cerr << "表已满,无法插入更多数据。\n";
					return 0;
				}
				while (ss >> item) {
					if (cn <= num_cols) {
						v_tables[i].record[rn][cn++] = item;
					}
					else {
						cerr << "警告:列数超出预期,额外的数据已被忽略。\n";
						break;
					}
				}
				if (cn < num_cols + 1) {
					cerr << "提示:输入的列数少于预期,这行数据可能不完整。\n";
				}
				v_tables[i].record[rn][0] = "A";
				v_tables[i].state = 2;
				v_tables[i].rows = max(v_tables[i].rows, rn);
				cout << "Input > ";
			}
			cout << "插入结束!\n";

			//写盘
			Dict_Write();
			Data_Write(v_tables);
			Select(table_name, v_tables);
			return 1;
		}
		i++;
	}
	cout << "表不存在!\n";
	return 0;
}

int Rename(string table_name, vector<S_Table>& v_tables) {
	i = 0;
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		if ((v_tables[i].name == table_name) && ((v_tables[i].state == 2) || (v_tables[i].state == 1))) { //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
			std::cout << "请输入新名:";
			std::cin >> g_temp;
			j = 0;
			while ((j < v_tables.size()) && (v_tables[j].state != 0)) {
				if ((v_tables[j].name == g_temp) && ((v_tables[j].state == 1) || (v_tables[j].state == 2))) {
					printf("新表名已存在!\n");
					return 0;
				}
				j++;
			}
			v_tables[i].name = g_temp;
			printf("# 更新成功:\n");
			List_Table(v_tables);
			//写盘
			Dict_Write();
			Data_Write(v_tables);
			return 0;
		}
		i++;
	}
	printf("表不存在!\n");
	return 0;
}

int Truncate(string table_name, vector<S_Table>& v_tables) {
	i = 0;
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		if ((v_tables[i].name == table_name) && ((v_tables[i].state == 2) || (v_tables[i].state == 1))) { //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
			v_tables[i].state = 1;
			j = 1;
			while (v_tables[i].record[j][0].length() != 0) {
				v_tables[i].record[j][0] = "";
				j++;
			}
			v_tables[i].rows = 0;
			printf("表已清空\n");
			//写盘
			Dict_Write();
			Data_Write(v_tables);
			return 0;
		}
		i++;
	}
	printf("表不存在!\n");
	return 0;
}

int Purge(vector<S_Table>& v_tables) {
	i = 0;
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		if (v_tables[i].state == 3) {
			v_tables[i].state = 4;
		}
		i++;
	}
	printf("回收站已清空!\n");
	//写盘
	Dict_Write();
	Data_Write(v_tables);
	return 0;
}

int Flashback(int oid, vector<S_Table>& v_tables) {
	i = 0;
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		if ((v_tables[i].oid == oid) && (v_tables[i].state == 3)) { //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
			if (v_tables[i].record[1][0].length() == 0) {
				v_tables[i].state = 1;
			}
			else {
				v_tables[i].state = 2;
			}
			_itoa_s(v_tables[i].oid, g_temp, L, 10);
			v_tables[i].name = g_temp;
			printf("表已闪回\n");
			//写盘
			Dict_Write();
			Data_Write(v_tables);
			return 0;
		}
		i++;
	}
	printf("表不存在或已被清理!\n");
	return 0;
}

int Alter(string table_name, vector<S_Table>& v_tables) {
	i = 0;
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		if ((v_tables[i].name == table_name) && ((v_tables[i].state == 2) || (v_tables[i].state == 1))) { //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
			std::cout << "请输入CID(列号): ";
			std::cin >> cn;
			std::cout << "请输入字段新值: ";
			std::cin >> g_temp;
			rn = 0;
			if (cn != 0) {
				v_tables[i].record[rn][cn] = g_temp;
				printf("# 更新后表结构和数据如下:\n");
				Select(table_name, v_tables);
				//写盘
				Dict_Write();
				Data_Write(v_tables);
				return 0;
			}
			printf("非列名位置不容许DDL!\n");
			return 0;
		}
		i++;
	}
	printf("表不存在!\n");
	return 0;
}

int Select(string table_name, vector<S_Table>& v_tables) {
	i = 0;
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		if ((v_tables[i].name == table_name) && ((v_tables[i].state == 2) || (v_tables[i].state == 1))) { //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
			j = 0;
			k = 0;
			rn = 0;
			while (v_tables[i].record[rn][0].length() != 0) {
				if (v_tables[i].record[rn][0] != "D") {
					cn = 0;
					printf("R[%02d] RMID[%02d] : ", k, rn);
					while (v_tables[i].record[rn][cn].length() != 0) {
						cout << v_tables[i].record[rn][cn + 1] << "\t";
						j++;
						cn++;
					}
					printf("\n");
					k++;
				}
				rn++;
			}
			rn = k - 1;
			cn = v_tables[i].cols;
			printf("# Selected:[%d]ROWS,[%d]COLS\n", rn, cn);
			return 0;
		}
		i++;
	}
	printf("表不存在!\n");
	return 0;
}

int Create(string table_name, vector<S_Table>& v_tables) {
	i = 0;
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		if ((v_tables[i].name == table_name) && ((v_tables[i].state == 2) || (v_tables[i].state == 1))) { //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
			printf("表已存在\n");
			goto label_Create_end;
		}
		i++;
	}
	i = 0;
	noid = atoi(g_dict[0].value);
label_Create_start:
	while (i < v_tables.size()) {
		if ((v_tables[i].state == 0) || (v_tables[i].state == 4)) {
			v_tables[i].state = 1;
			v_tables[i].oid = noid;
			v_tables[i].rows = 0;
			v_tables[i].cols = 0;
			v_tables[i].name = table_name;
			v_tables[i].record[0][0] = "H";
			printf("请输入列的[数量]:");
			cin >> v_tables[i].cols;
			for (j = 0; j < v_tables[i].cols; j++) {
				printf("请输入第[%d]列的[名称]:", j + 1);
				cin >> v_tables[i].record[0][j + 1];
			}
			noid++;
			_itoa_s(noid, g_temp, L, 10);
			strcpy_s(g_dict[0].value, L, g_temp);
			printf("表TMID:%d,表OID:%d", i, noid);
			j = 1;
			while (v_tables[i].record[j][0].length() != 0) {
				v_tables[i].record[j][0] = "";
				j++;
			}
			//写盘
			Dict_Write();
			Data_Write(v_tables);
			return 0;
		}
		i++;
	}
	ts = (atoi(g_dict[1].value) + 1);
	v_tables.resize(ts);
	_itoa_s(ts, g_temp, L, 10);
	strcpy_s(g_dict[1].value, L, g_temp);
	printf("表空间已满,已自动扩容!\n");
	printf("当前表空间大小为:%d\n", ts);
	goto label_Create_start;
label_Create_end:
	return 0;
}

int Drop(string table_name, vector<S_Table>& v_tables) {
	i = 0;
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		if ((v_tables[i].name == table_name) && ((v_tables[i].state == 2) || (v_tables[i].state == 1))) { //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
			v_tables[i].state = 3;
			printf("已删除\n");
			//写盘
			Dict_Write();
			Data_Write(v_tables);
			return 0;
		}
		i++;
	}
	printf("表不存在\n");
	return 0;
}

int List_Table(vector<S_Table>& v_tables) {
	i = 0;
	printf("# 库中所有状态的表信息如下\n");
	printf("内存ID  表名 表状态 表编号 行数    列数\n");
	while ((i < v_tables.size()) && (v_tables[i].state != 0)) {
		cout << "TMID[" << i << "] "
			<< setw(4) << left << v_tables[i].name
			<< " STA[" << v_tables[i].state << "]"
			<< " OID[" << v_tables[i].oid << "]"
			<< " ROWS[" << v_tables[i].rows << "]"
			<< " COLS[" << v_tables[i].cols << "]" << endl;
		i++;
	}
	printf("# STA列值:1>新/空表、2>有数据、3>已删除、4>可复用\n");
	return 0;
}

int Head() {
	system("CLS");
	printf("############【欢迎使用 ZDB】############\n");
	printf("# 语言:C++              IDE :VS 2022 #\n");
	printf("# 作者:zzt_2009         版本:V 6.0.0 #\n");
	printf("# 主页:https://blog.csdn.net/zzt_2009 #\n");
	printf("# [H/h]查看帮助          [E/e]退出程序 #\n");
	return 0;
}

int Bye() {
	printf("#########【感谢使用 ZDB 再见!】#########\n");
	return 0;
}

int Help() {
	printf("# L   For > list table def   #\n");
	printf("# C   For > Create table     #\n");
	printf("# D   For > Drop table       #\n");
	printf("# A   For > Alter table      #\n");
	printf("# R   For > Rename table     #\n");
	printf("# T   For > Truncate table   #\n");
	printf("# F   For > Flashback table  #\n");
	printf("# P   For > Purge recyclebin #\n");
	printf("# i   For > insert           #\n");
	printf("# d   For > delete           #\n");
	printf("# u   For > update           #\n");
	printf("# s   For > select           #\n");
	printf("# c   For > clear            #\n");
	printf("# H/h For > help             #\n");
	printf("# E/e For > exit             #\n");
	return 0;
}

int Data_Write(vector<S_Table>& v_tables) {
	i = 0;
	json j_tables = json::array();
	for (const auto& table : v_tables) {
		if (v_tables[i].state != 0) {
			j_tables.push_back(table.to_json());
			i++;
		}
	}
	// 写入到磁盘
	std::ofstream file(DefaultPATH + string(data_file));
	if (file.is_open()) {
		file << j_tables.dump(4);
		file.close();
		cout << "数据写入成功:写入了【" << i << "】个表" << endl;
		return 0;
	}
	else {
		cerr << "无法打开文件" << endl;
	}
	return 0;
}

int Data_Read(vector<S_Table>& v_tables) {
Data_Read_start:
	ifstream file(DefaultPATH + string(data_file));
	if (file.is_open()) {
		json j_tables;
		file >> j_tables;
		file.close();
		size_t j = min(j_tables.size(), v_tables.size());
		size_t i;
		for (i = 0; i < j; ++i) {
			v_tables[i] = S_Table::from_json(j_tables[i]);
		}
		cout << "数据读取成功:加载了【" << i << "】个表" << endl;
		cout << "当前表空间:总大小为【" << v_tables.size() << "】,剩余空间【" << v_tables.size() - i << "】" << endl;
		return 0;
	}
	else {
		cout << "首次使用,正在初始化数据文件……" << endl;
		Dir_Init();
		Data_Init(v_tables);
		Data_Write(v_tables);
		printf("数据文件初始化完成。\n");
		//重新读取
		goto Data_Read_start;
	}
}

int Dict_Write() {
	strcpy_s(Path, L, DefaultPATH);
	strcat_s(Path, L, dict_file);
	ofstream fp(Path, ios::binary);
	if (!fp) {
		cerr << "无法打开文件!" << endl;
		return 0;
	}
	fp.write(reinterpret_cast<const char*>(g_dict), sizeof(g_dict));
	fp.close();
	if (!fp.good()) {
		cerr << "发生错误,在写入文件时." << endl;
	}
	printf("字典落盘成功!\n");
	return 0;
}

int Dict_Read() {
	strcpy_s(Path, L, DefaultPATH);
	strcat_s(Path, L, dict_file);
Dict_Read_start:
	ifstream fp(Path, ios::binary);
	if (!fp) {
		cout << "首次使用,正在初始化数据字典……" << endl;
		Dir_Init();
		Dict_Init();
		Dict_Write();
		printf("字典文件初始化完成。\n");
		//重新读取
		goto Dict_Read_start;
	}
	fp.read(reinterpret_cast<char*>(g_dict), sizeof(g_dict));
	if (!fp) {
		cerr << "读取文件时发生错误!" << endl;
		fp.close();
		return 0;
	}
	fp.close();
	printf("字典加载成功!\n");
	return 0;
}

int Dict_Init() {
	g_dict[0].state = 1; //状态:0>未分配、1>有效、2>删除
	strcpy_s(g_dict[0].name, N, "noid");
	strcpy_s(g_dict[0].value, L, "1");
	strcpy_s(g_dict[0].comment, L, "下一个对象的编号");
	g_dict[1].state = 1;
	strcpy_s(g_dict[1].name, N, "ts");
	strcpy_s(g_dict[1].value, L, "1");
	strcpy_s(g_dict[1].comment, L, "TableSpace:存放表的结构数组的上限值");
	return 0;
}

int Data_Init(vector<S_Table>& v_tables) {
	v_tables[0].name = "T0";
	v_tables[0].state = 2; //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
	v_tables[0].oid = 0;
	v_tables[0].rows = 3;
	v_tables[0].cols = 2;
	v_tables[0].record[0][0] = "H"; //数据&状态:"">未分配、H>字段名、A>可用、D>删除
	v_tables[0].record[0][1] = "TEL";
	v_tables[0].record[0][2] = "NAME";
	v_tables[0].record[1][0] = "A";
	v_tables[0].record[1][1] = "110";
	v_tables[0].record[1][2] = "Police";
	v_tables[0].record[2][0] = "A";
	v_tables[0].record[2][1] = "120";
	v_tables[0].record[2][2] = "Ambulance";
	v_tables[0].record[3][0] = "A";
	v_tables[0].record[3][1] = "119";
	v_tables[0].record[3][2] = "Fire";
	return 0;
}

int Dir_Init() {
	if (_mkdir(DefaultPATH) == 0) {
	}
	else {
	}
	return 0;
}


//end

※ 如果您觉得文章写的还不错, 别忘了在文末给作者点个赞哦 ~

20200426194203245.gif

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
先解释一下题目中的数据定义: - X DW10,20.30,40,50 表示定义了一个名为 X 的数据段,其中包含了 5 个双字(即 10 个字节)的数据,分别是 10、20.30(实数)、40、50,按照从左到右的顺序存放。 - Y DB4 表示定义了一个名为 Y 的数据段,其中包含了 4 个字节的数据,每个字节都是一个无符号整数。 - Z DB? 表示定义了一个名为 Z 的数据段,其中包含了 1 个字节的数据,初始值未知。 - W DB? 表示定义了一个名为 W 的数据段,其中包含了 1 个字节的数据,初始值未知。 接下来是表达式计算的过程: 1. 将 X 中的所有数据相加得到总和 S,即 S = 10 + 20.30 + 40 + 50 = 120.30。 2. 将 Y 中的所有数据相加得到总和 T,即 T = Y[0] + Y[1] + Y[2] + Y[3]。 3. 计算商 Q 和余数 R,其中 Q = INT(S / T) = INT(120.30 / T),R = S - Q * T。 4. 将 Q 和 R 分别存入 Z 和 W。 根据以上步骤,可以编写如下代码: ``` ; 数据段 姓名DW DW 0 达瓦DW DW 0 格桑普布DW DW 0 曲吉热巴DW DW 0 扎西次仁DB DB 0, 0, 0, 0 朗杰DB DB ?, 0 ; 代码段 assume cs:代码段, ds:数据段 start: ; 将 X 中的所有数据相加得到总和 S mov eax, [姓名DW] add eax, [达瓦DW] fld [格桑普布DW] fadd dword ptr [曲吉热巴DW] fadd SBYTE ptr [扎西次仁DB] fstp qword ptr [esp] ; 将浮点数结果保存到栈顶 ; 将 Y 中的所有数据相加得到总和 T movzx eax, BYTE ptr [朗杰DB] add al, BYTE ptr [朗杰DB+1] add al, BYTE ptr [朗杰DB+2] add al, BYTE ptr [朗杰DB+3] ; 计算商 Q 和余数 R mov ecx, eax ; ecx = T fild qword ptr [esp] ; 将 S 转为浮点数 fidiv dword ptr [朗杰DB] ; ST(0) = S / T fistp dword ptr [朗杰DB] ; Q = ST(0),保存到 Z 中 mov ebx, eax ; ebx = Q imul ecx ; edx:eax = T * Q mov eax, [姓名DW] add eax, [达瓦DW] fld [格桑普布DW] fadd dword ptr [曲吉热巴DW] fadd SBYTE ptr [扎西次仁DB] fsub st(0), st(1) ; ST(0) = S - T * Q fistp dword ptr [esp] ; R = ST(0),保存到 W 中 mov BYTE ptr [朗杰DB+1], al ; 将 R 存入 W 中 ; 程序结束 mov ah, 4ch int 21h end start ``` 需要注意几点: - 浮点数运算需要使用 FPU 指令,而且 FPU 寄存器的操作是栈式的。 - 在进行浮点数运算之前,需要先将整数转为浮点数,可以使用 FILD 指令。 - 在进行整数除法之前,需要先将浮点数转为整数,可以使用 FIST 指令。由于 FIST 指令会将结果存入内存中,因此需要指定存储地址。 - 由于浮点数运算和整数运算使用的寄存器不同,因此需要注意保存和恢复现场。在上面的代码中,将浮点数结果保存到栈顶,然后再从栈顶取出进行整数运算。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值