C语言手搓迷你DBMS:建表改表与底层实现
简介这份资源是山东科技大学信息科学与工程学院《数据库系统概论》课程设计的实验报告面向计算机科学与技术专业学生及需要完成类似DBMS实践任务的学习者。报告围绕“实现一个简单的DBMS——创建表和修改表”展开完整记录了从需求分析、设计思想到程序实现的全过程涵盖CREATE TABLE与ALTER TABLE语句解析、表结构物理存储设计、命令行与图形化界面交互、程序流程图绘制等核心内容。压缩包内为1个doc文档约408KB结构完整可直接作为课程设计报告的参考模板。报告详细阐述了用数组存储表名、属性名、属性类型及约束条件的方法以及通过table.txt持久化保存表信息、启动时重新加载的设计思路并包含新建表、修改表、显示已建表信息、保存退出四个功能模块的实现说明。目前已有933人学习下载适合数据库初学者理解DBMS底层工作原理也可为课程设计选题、报告撰写与代码实现提供具体参考。1. 从一份课程设计拆起用 C 语言手搓一个能建表改表的迷你 DBMS很多人第一次接触数据库是从CREATE TABLE和ALTER TABLE这两条语句开始的。敲下去表就建好了字段就加上了至于背后发生了什么基本靠脑补。这份课程设计资源干的事情就是把脑补变成代码——用 C 语言实现一个简单的 DBMS核心功能只有两个创建表和修改表。它不依赖 MySQL、SQLite 这类现成引擎而是自己解析 SQL 语句、自己设计表结构的存储格式、自己把表信息持久化到文本文件里。适合正在学《数据库系统概论》的学生、想搞明白 DBMS 底层怎么运转的开发者以及需要一份能跑通的课程设计参考的人。下面我按“它怎么解析语句、怎么存表、怎么改表、哪里容易翻车”的顺序把这份资源拆开讲。2. 语句解析与表结构存储从字符串到内存数组的映射2.1 为什么用数组而不是链表或哈希表这份设计里表信息的存储用的是多维字符数组。表名存在char tableName[LEN][MAX]字段名存在char fieldName[LEN][LEN][MAX]字段类型和约束条件也各有对应的数组。第一维是表的编号第二维是字段的编号第三维是字符串本身。选数组而不是链表原因很直接课程设计的规模有限表的数量、每张表的字段数量都不会太大数组的随机访问比链表遍历方便得多。解析 SQL 语句时需要频繁地按索引回填字段信息数组的fieldName[tableIndex][fieldIndex]这种写法比在链表里找节点要直观。哈希表虽然查找快但实现复杂度上来了对一份教学性质的课程设计来说不划算。常见做法是给每个维度定一个上限比如#define LEN 20、#define MAX 50表示最多 20 张表、每张表最多 20 个字段、每个标识符最长 50 个字符。这个上限在真实 DBMS 里当然不够用但作为课程设计够跑通演示就行。2.2 解析 CREATE TABLE 的完整流程解析CREATE TABLE语句的核心思路是跳过空格、提取关键词、校验关键词、提取表名、循环提取字段定义。下面这段代码是从资源里摘出来的关键逻辑我加了注释说明每一步在干什么。// 判断 create 关键词 for(i 0; SQL[i] ; i); // 跳过前导空格 for(j 0; SQL[i] ! SQL[i] ! ;; i, j) { temp[j] tolower(SQL[i]); // 转小写避免大小写敏感 } temp[j] \0; if(strcmp(temp, create) ! 0) { printf(你输入的create有误请重新创建!\n); return 0; } // 判断 table 关键词 for(; SQL[i] ; i); // 跳过 create 和 table 之间的空格 for(j 0; SQL[i] ! SQL[i] ! ;; i, j) { temp[j] tolower(SQL[i]); } temp[j] \0; if(strcmp(temp, table) ! 0) { printf(你输入的table有误请重新创建!\n); return 0; } // 提取表名 for(; SQL[i] ; i); for(j 0; SQL[i] ! SQL[i] ! ;; i, j) { t_Name[j] SQL[i]; } // 将表名写入全局数组 for(int _i 0; _i j; _i) tableName[number][_i] t_Name[_i]; tableName[number][_i] \0;这段代码的逻辑是逐词推进的先确认第一个词是create再确认第二个词是table然后提取表名。每一步都做了tolower转换这样用户输入CREATE、Create、create都能识别。跳过空格用的是for(; SQL[i] ; i);这种空循环虽然写法不够优雅但在课程设计里很常见。字段提取部分是一个do-while循环每次迭代处理一个字段定义。先提取字段名再提取字段类型然后根据类型判断是否需要读取长度比如char(20)里的20最后提取约束条件primary key、unique、not null。字段类型只支持五种char、int、float、double、date分别映射到内部编码C、I、F、B、D。注意字段长度的提取只处理了个位数的情况。代码里f_t_len[number][num][1] f_length 48;把整数长度转成字符时如果长度是 20f_length 48得到的是d而不是2和0。这是一个隐藏的坑后面避坑章节会展开。2.3 表信息的持久化为什么每次全量重写保存表信息的逻辑在资源里说得很清楚打开table.txt先把文件内容清空再把内存里所有表的信息重新写进去。不是追加不是定位修改是全量覆盖。这个选择乍看很粗暴但仔细想有它的道理。如果用户修改了某张表的某个字段类型在文件里定位到那一行去改需要知道每张表在文件里的偏移量还要处理字段数量变化导致的行数变化。全量重写就简单了内存里的数组就是唯一真相文件只是数组的序列化结果。每次保存时先写表名再写字段数量然后逐个写字段名、字段类型、字段长度、约束条件。// 保存表信息的核心逻辑伪代码示意 void Save() { ofstream outFile(table.txt); for(int t 0; t number; t) { outFile tableName[t] ; // 表名 outFile Pro_Num[t] ; // 字段数量 for(int f 0; f Pro_Num[t]; f) { outFile fieldName[t][f] ; // 字段名 outFile fieldType[t][f] ; // 字段类型 outFile f_t_len[t][f] ; // 字段长度 outFile fieldCondition[t][f] ; // 约束条件 } outFile endl; } outFile.close(); }读取时的逻辑完全对称先读表名再读字段数量然后按数量循环读取每个字段的四个属性。这种“写入时按固定顺序、读取时按同样顺序”的做法是文本文件持久化最朴素也最不容易出错的方式。3. ALTER TABLE 的实现在已有表上做增删改3.1 先查表是否存在再判断操作类型ALTER TABLE的解析比CREATE TABLE多了一步先提取表名然后在已有的表数组里查找这张表。如果找不到直接报错返回。查找用的是strcmp逐个比较表名找到后记录下标al_num后续所有修改都作用在这个下标对应的表上。// 提取表名后查找是否存在 for(al_num 0; al_num number; al_num) { if(strcmp(tableName[al_num], alterName) 0) break; } if(al_num number) { printf(你输入的表 %s 不存在请重新输入!\n, t_name); return 0; }找到表之后根据ALTER后面的关键词分三种情况处理ADD加新列、DROP删约束、MODIFY改类型。资源里主要实现了ADD的逻辑DROP和MODIFY的框架也在但细节处理不如ADD完整。3.2 ADD 新列的字段解析与数组扩容ADD的逻辑是提取新列名、提取数据类型、判断是否需要长度、提取约束条件然后把这四个信息追加到该表的字段数组末尾同时把字段数量Pro_Num[al_num]加一。// 提取要添加的字段名 for(; SQL[i] ; i); for(j 0; SQL[i] ! ; i, j) { field_name[j] SQL[i]; } field_name[j] \0; // 提取字段类型与 CREATE 中逻辑相同 // ... // 追加到数组末尾 int idx Pro_Num[al_num]; // 当前字段数量就是新字段的下标 strcpy(fieldName[al_num][idx], field_name); strcpy(fieldType[al_num][idx], f_type); strcpy(f_t_len[al_num][idx], length_str); strcpy(fieldCondition[al_num][idx], condition); Pro_Num[al_num]; // 字段数量加一这里的关键是Pro_Num[al_num]既表示当前字段数量又正好是新字段要插入的下标位置。因为数组是从 0 开始编号的如果当前有 3 个字段下标 0、1、2新字段就应该放在下标 3而Pro_Num的值正好是 3。加完之后Pro_Num变成 4下次再加就放在下标 4。提示这种“数量即下标”的写法在数组追加场景里很常见但前提是字段数量不能超过数组第二维的上限。如果Pro_Num[al_num]已经等于LEN再追加就会越界。资源里没有做这个边界检查实际使用时需要自己补上。3.3 MODIFY 和 DROP 的简化处理MODIFY的逻辑是找到指定字段把它的类型和长度替换成新的值。资源里的做法是遍历该表的所有字段用strcmp找到名字匹配的那个然后直接覆盖fieldType和f_t_len数组对应位置的内容。DROP在标准 SQL 里可以删列也可以删约束资源里主要处理的是删约束。实现方式是找到对应字段后把fieldCondition数组里那个位置的内容改成NULL表示没有约束。如果要删的是列本身需要把该列之后的所有列向前移动一位同时Pro_Num减一。资源里对删列的实现不够完整这是课程设计常见的取舍——先把主要功能跑通边缘功能留个框架。4. 避坑与排查这份代码跑起来容易翻车的五个地方4.1 字段长度超过 9 时显示成乱码现象建表时写char(20)保存后重新读取字段长度显示成d或者别的奇怪字符。原因代码里把整数长度转成字符时用了f_length 48这只对 0 到 9 有效。20 48 68对应 ASCII 字符D不是2和0。解决把长度存成字符串而不是单个字符。用sprintf(f_t_len[number][num], (%d), f_length);替代原来的逐字符赋值。读取时也按字符串整体读取不要逐字符解析。4.2 表名或字段名超过数组上限导致越界现象程序运行中突然崩溃或者表信息保存后读取出来是乱码。原因tableName[LEN][MAX]里LEN是表数量上限MAX是名字长度上限。如果输入的表名超过MAXstrcpy会写越界。如果表数量超过LENnumber变量会超出数组第一维的范围。解决在提取表名和字段名时加长度检查超过上限就截断或报错。在number之前判断number LEN满了就提示“表数量已达上限”。4.3 文件路径硬编码导致换台机器就读不到现象在自己的电脑上跑得好好的换一台电脑或者换个目录程序启动后显示“无表可显示”。原因读取文件的路径写死成了C:\\Users\\Administrator\\Desktop\\DBMS.txt这个路径只在特定机器上存在。解决把文件路径改成相对路径比如table.txt让文件生成在程序运行目录下。或者用命令行参数传入文件路径提高可移植性。4.4 解析语句时对空格和逗号的处理不统一现象输入CREATE TABLE student(id int, name char(10));能成功但输入CREATE TABLE student ( id int , name char(10) ) ;就报错。原因解析代码里跳过空格和逗号的逻辑分散在各处有的地方只跳空格不跳逗号有的地方只跳一个空格不跳多个。字段名提取时用SQL[i] ! 作为结束条件如果字段名后面直接跟逗号而没有空格就会把逗号也读进字段名里。解决写一个统一的skipDelimiters()函数把空格、逗号、制表符都当作分隔符跳过。提取标识符时结束条件改成“遇到空格、逗号、分号或左括号就停”。4.5 保存时全量重写但没处理文件打开失败现象程序提示保存成功但重新启动后之前建的表全没了。原因ofstream打开文件时如果路径不存在或没有写权限会静默失败。代码里没有检查outFile.is_open()直接往里写写了个寂寞。解决打开文件后立即判断is_open()失败就打印错误信息并返回。保存完成后可以再读一次文件做校验确认写入的内容和内存里的数组一致。5. 进阶用法把文本存储换成二进制再加一个简单的查询这份课程设计的默认存储格式是纯文本好处是能用记事本直接打开看坏处是读取时要逐字符解析字段多了之后加载速度会明显变慢。一个自然的进阶方向是把表结构存成二进制文件用fwrite把整个数组结构一次性写进去读取时用fread一次性读回来。结构体定义大概是这样typedef struct { char name[MAX]; char type[10]; char length[10]; char condition[20]; } FieldDef; typedef struct { char tableName[MAX]; int fieldCount; FieldDef fields[LEN]; } TableDef; TableDef tables[LEN]; // 全局表数组 int tableCount 0;保存时fwrite(tables, sizeof(TableDef), tableCount, fp);读取时fread(tables, sizeof(TableDef), LEN, fp);然后根据实际读到的数量恢复tableCount。二进制存储不需要解析分隔符字段名里有空格也不怕读写速度比文本快一个数量级。另一个值得加的进阶功能是SELECT查询。不需要实现完整的 SQL 查询引擎只要支持SELECT * FROM 表名;这种最简单的形式就行。解析时提取表名在数组里找到对应的表然后把字段名、类型、约束条件逐行打印出来。这个功能加上之后整个程序就从“只能建表和改表”变成了“能建、能改、能看”演示效果会好很多。我自己的习惯是每次改完存储格式或者加完新功能都会用同一组测试用例跑一遍建三张表每张表三到五个字段字段类型覆盖int、char、float约束条件覆盖primary key、not null、unique。然后保存、退出、重新启动、显示所有表信息逐字段核对。这个流程走下来大部分数组越界和解析遗漏的问题都能提前暴露。从那以后我每次动存储相关的代码都强制走一遍这个回归测试省了不少事后排查的时间。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Spring启动报错Error creating bean的根因排查与解决

Spring启动报错Error creating bean的根因排查与解决

Spring 启动报错 “Error creating bean with name ‘externalDumpService‘” 的排查实录相信每一个做 Java 后端、尤其是用 Spring Boot 做微服务的朋友,对下面这段堆栈都不陌生:Error creating bean with name externalDumpService: Invocation of in…

2026/10/19 2:01:51 阅读更多 →
下拉框select与数据库交互:构建高可靠数据契约的实战指南

下拉框select与数据库交互:构建高可靠数据契约的实战指南

1. 项目概述:为什么一个下拉框值得花一整天去抠细节?“form表单中的下拉框select与数据库交互数据”——这行标题看起来平平无奇,像极了某次需求评审会上被随口带过的半句话:“那个下拉框,后端给个接口就行”。但我在某…

2026/10/17 23:20:20 阅读更多 →
C# 12新特性实战:主构造函数、集合表达式与性能优化指南

C# 12新特性实战:主构造函数、集合表达式与性能优化指南

简介:这本《C# 12 in a Nutshell》是OReilly出品的C#权威参考书,面向中高级开发者,系统讲解C# 12与.NET 8核心知识,涵盖语言基础、类型系统、继承、LINQ、并发与异步编程等主题。书中对CLR、BCL和运行时机制亦有深入剖析&#xff…

2026/10/19 1:57:14 阅读更多 →

最新新闻

1~30秒参考音频克隆任意声音:Seed-VC 零样本语音转换完整零训练指南

1~30秒参考音频克隆任意声音:Seed-VC 零样本语音转换完整零训练指南

1~30秒参考音频克隆任意声音:Seed-VC 零样本语音转换完整零训练指南 【免费下载链接】seed-vc zero-shot voice conversion & singing voice conversion, with real-time support 项目地址: https://gitcode.com/GitHub_Trending/se/seed-vc 有一场会要开…

2026/10/19 2:01:28 阅读更多 →
MiniCPM-V-2_6-GPTQ 视频理解全流程:64 帧看懂一整段视频

MiniCPM-V-2_6-GPTQ 视频理解全流程:64 帧看懂一整段视频

MiniCPM-V-2_6-GPTQ 视频理解全流程:64 帧看懂一整段视频 【免费下载链接】antimicrox Graphical program used to map keyboard buttons and mouse controls to a gamepad. Useful for playing games with no gamepad support. 项目地址: https://gitcode.com/Gi…

2026/10/19 2:01:28 阅读更多 →
biliTickerBuy 完整使用指南:免费开源的 B 站会员购抢票辅助工具,开售自动下单

biliTickerBuy 完整使用指南:免费开源的 B 站会员购抢票辅助工具,开售自动下单

biliTickerBuy 完整使用指南:免费开源的 B 站会员购抢票辅助工具,开售自动下单 【免费下载链接】biliTickerBuy b站会员购购票辅助工具 项目地址: https://gitcode.com/GitHub_Trending/bi/biliTickerBuy 开售那几秒,你连刷七八次页面,「立即购买」刚亮起就弹出排队提示…

2026/10/19 2:01:28 阅读更多 →
低功耗设计中的反直觉陷阱:为什么进入 STOP 模式电流反而变大了?

低功耗设计中的反直觉陷阱:为什么进入 STOP 模式电流反而变大了?

摘要: 可穿戴设备续航从 7 天缩水到 2 天,电池容量没变、固件逻辑没改,问题出在低功耗模式上。更诡异的是——进入 STOP 模式后电流反而比 RUN 模式更大。这不是硬件故障,而是低功耗设计里最反直觉的一类陷阱:GPIO 悬空、外设时钟未关、上拉下拉配错、调试接口未禁用……每…

2026/10/19 2:01:28 阅读更多 →
Qwen-Image-Layered-6bit分层质量调优:steps与resolution如何取舍才最划算

Qwen-Image-Layered-6bit分层质量调优:steps与resolution如何取舍才最划算

【免费下载链接】Qwen-Image-Layered-6bit 项目地址: https://ai.gitcode.com/hf_mirrors/zimengxiong/Qwen-Image-Layered-6bit 点击查看 免费下载 Qwen-Image-Layered-6bit 是面向 Apple Silicon 的 6-bit 量化图像分层模型,能把任意图片分解为多张 R…

2026/10/19 2:01:28 阅读更多 →
ABAP Cloud 的 OLTP 开发,从数据增删改查走向完整的业务事务

ABAP Cloud 的 OLTP 开发,从数据增删改查走向完整的业务事务

采购申请页面上的保存按钮,背后通常不只有一次数据库写入。申请抬头需要保存,行项目需要关联,金额需要计算,供应商需要校验,当前操作者还必须具备相应权限。只要其中一项没有满足业务要求,系统就不能把这张申请当成一份完整、有效的业务单据。 这类围绕业务数据开展读取…

2026/10/19 2:00:28 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →