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

news2024/9/23 19:28:44

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


★ 程序界面

★ 功能简介

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

★ 程序特点

✔ 程序会在首次运行时在同级创建一个目录用于存放数据库信息
✔ 程序运行期间表数据存储在内存中,类似于Redis
✔ 程序运行结束表数据会刷入磁盘避免丢失
✔ 表在删除后清理前支持闪回功能,清理后空间可以复用
✔ 表记录在删除后只是标记为删除,方便后期复用并减少数据shrink的性能消化

★ 程序试用

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

★ 使用案例

##########【欢迎使用 ZDB】##########
# 作者:zzt_2009     版本:V 5.0.0 #
# [H/h]查看帮助      [E/e]退出程序 #
首次使用,正在初始化数据字典……
字典落盘成功!
字典文件初始化完成。
首次使用,正在初始化数据文件……
数据落盘成功!
数据文件初始化完成。
首次使用,已为您展示帮助文档。
# 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             #
SQL > H
# 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             #
SQL > L
# 库中所有状态的表信息如下
内存ID  表名 表状态 表编号 行数    列数
TMID[0]   T0 STA[2] OID[0] ROWS[4] COLS[2]
# STA列值:1>新/空表、2>有数据、3>已删除、4>可复用  
SQL > C
请输入表名: T1
请输入列的[数量]:2
列的[数量]:2
请输入第[1]列的[名称]:ID
请输入第[2]列的[名称]:NAME
表TMID:1,表OID:2字典落盘成功!
数据落盘成功!
SQL > C
请输入表名: T2
请输入列的[数量]:2
列的[数量]:2
请输入第[1]列的[名称]:ID
请输入第[2]列的[名称]:NAME
表TMID:2,表OID:3字典落盘成功!
数据落盘成功!
SQL > D
请输入表名: T1
已删除
字典落盘成功!
数据落盘成功!
SQL > F
请输入表OID: 1
表已闪回
字典落盘成功!
数据落盘成功!
SQL > R
请输入表名: 1
请输入新名: T1
# 更新成功:
# 库中所有状态的表信息如下
内存ID  表名 表状态 表编号 行数    列数
TMID[0]   T0 STA[2] OID[0] ROWS[4] 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>可复用  
字典落盘成功!
数据落盘成功!
SQL > A
请输入表名: T1
请输入CID(列号): 1
请输入字段新值: ID2
# 更新后表结构和数据如下:
R[00] RMID[00] : ID2    NAME
# [0]ROWS,[2]COLS
字典落盘成功!
数据落盘成功!
SQL > i
请输入表名: T1
请输入多行(列以tab分隔,新行";\n"结束)
Input > 1       a
Input > 2       b
Input > 3       c
Input > ;
插入结束!
字典落盘成功!
数据落盘成功!
# 表[T1]最新数据如下:
R[00] RMID[00] : ID2    NAME
R[01] RMID[01] : 1      a
R[02] RMID[02] : 2      b
R[03] RMID[03] : 3      c
# [3]ROWS,[2]COLS
表行列数不正确,修正完成.
数据落盘成功!
SQL > d
请输入表名: T1
请输入RMID: 2
# RID[2]已删除
# 删除后表数据如下:
R[00] RMID[00] : ID2    NAME
R[01] RMID[01] : 1      a
R[02] RMID[03] : 3      c
# [2]ROWS,[2]COLS
表行列数不正确,修正完成.
数据落盘成功!
字典落盘成功!
数据落盘成功!
SQL > u
请输入表名: T1
请输入RMID(内存行号): 3
请输入CID(列号): 2
请输入字段新值: ccc
# 更新后表数据如下:
R[00] RMID[00] : ID2    NAME
R[01] RMID[01] : 1      a
R[02] RMID[03] : 3      ccc
# [2]ROWS,[2]COLS
字典落盘成功!
数据落盘成功!
SQL > e
字典落盘成功!
数据落盘成功!
#######【感谢使用 ZDB 再见!】#######

进程已结束,退出代码0


★ 程序源码

//引用头文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
#include <direct.h>

//使用宏定义代替相关内容
#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 fr, fc = 0; //文件行数,文件列数
int rn, cn = 0; //行号、列号
int oid, noid = 0; //全局对象号、内存号
char g_temp[L]; //临时使用的字符串变量
char table_name[N]; //表名
FILE *fp;
char Path[L];
char dict_file[N] = "ZDB.dic"; //文件名
char data_file[N] = "ZDB.dat"; //文件名
typedef struct {     //字典
    int state;       //状态:0>未分配、1>有效、2>删除
    char name[N];    //名称
    char value[L];   //值
    char comment[L]; //描述
} S_Dict;
S_Dict g_dict[S];
typedef struct {     //表
    int state;       //状态:0>未分配、1>新表、2>有数、3>删除、4>可复用
    char name[N];    //名称
    int oid;         //编号
    int rows;        //行数
    int cols;        //列数
    char record[R][C][L]; //数据&状态:"">未分配、H>字段名、A>可用、D>删除
} S_Table;
S_Table g_table[S];

//函数声明
int Head(); //界面输出
int Body(); //程序主体
int Bye(); //程序退出
int Help(); //
int Iint_DB(); //
int Iint_Dir(); //
int Data_Read(); //
int Data_Write(); //
int Dict_Read(); //
int Dict_Write(); //
int List_Table(); //
int Create(char table_name[N]); //
int Drop(char table_name[N]); //
int Alter(char table_name[N], int cn, char g_temp[L]); //
int Truncate(char table_name[N]); //
int Purge(); //
int Flashback(int oid); //
int Rename(char table_name[N], char g_temp[L]); //
int Insert(char table_name[N]); //
int Delete(char table_name[N], int rn); //
int Update(char table_name[N], int rn, int cn, char g_temp[L]); //
int Select(char table_name[N]); //


//主函数
int main() {
    Head();
    Dict_Read();
    Data_Read();
    Body();
    return 0;
}

//函数定义
int Head() {
    system("CLS");
    printf("##########【欢迎使用 ZDB】##########\n");
    printf("# 作者:zzt_2009     版本:V 5.0.0 #\n");
    printf("# [H/h]查看帮助      [E/e]退出程序 #\n");
    return 1;
}

int Body() {
    //命令判断
    while (1) {
        printf("SQL > ");
        int n;
        n = getch();
        printf("%c\n", (char) n); //输出按键
        switch (n) {
            case 76: // L -> list table defination
                List_Table();
                break;
            case 67: // C -> create
                printf("请输入表名: ");
                scanf("%s", table_name);
                Create(table_name);
                break;
            case 68: // D -> drop
                printf("请输入表名: ");
                scanf("%s", table_name);
                Drop(table_name);
                break;
            case 65: // A -> alter
                printf("请输入表名: ");
                scanf("%s", table_name);
                printf("请输入CID(列号): ");
                scanf("%d", &cn);
                printf("请输入字段新值: ");
                scanf("%s", g_temp);
                Alter(table_name, cn, g_temp);
                break;
            case 70: // F -> flashback
                printf("请输入表OID: ");
                scanf("%d", &oid);
                Flashback(oid);
                break;
            case 80: // P -> purge
                Purge();
                break;
            case 84: // T -> truncate
                printf("请输入表名: ");
                scanf("%s", table_name);
                Truncate(table_name);
                break;
            case 82: // R -> rename
                printf("请输入表名: ");
                scanf("%s", table_name);
                printf("请输入新名: ");
                scanf("%s", g_temp);
                Rename(table_name, g_temp);
                break;
            case 105: // i -> insert
                printf("请输入表名: ");
                scanf("%s", table_name);
                Insert(table_name);
                break;
            case 100: // d -> delete
                printf("请输入表名: ");
                scanf("%s", table_name);
                printf("请输入RMID(内存行号): ");
                scanf("%d", &rn);
                Delete(table_name, rn);
                break;
            case 117: // u -> update
                printf("请输入表名: ");
                scanf("%s", table_name);
                printf("请输入RMID(内存行号): ");
                scanf("%d", &rn);
                printf("请输入CID(列号): ");
                scanf("%d", &cn);
                printf("请输入字段新值: ");
                scanf("%s", g_temp);
                Update(table_name, rn, cn, g_temp);
                break;
            case 115: // s -> select
                printf("请输入表名: ");
                scanf("%s", table_name);
                Select(table_name);
                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();
                Bye();
                exit(0);
            default:
                printf("命令不正确请重新输入,或按[H/h]查看帮助\n");
                break;
        }
    }
}

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");
}


int Dict_Read() {
    //printf("字典加载中…………\n");
    strcpy(Path, DefaultPATH);
    strcat(Path, dict_file);
    fp = fopen(Path, "rb");
    if (fp == NULL) {
        printf("首次使用,正在初始化数据字典……\n");
        Iint_DB();
        Iint_Dir();
        Dict_Write();
        printf("字典文件初始化完成。\n");
    }
    fread(&g_dict, sizeof(S_Dict), S, fp);
    fclose(fp);
    noid = atoi(g_dict[0].value);
    //printf("字典文件已加载[noid:%d]\n", noid);
    return 0;
}

int Data_Read() {
    //printf("数据加载中…………\n");
    strcpy(Path, DefaultPATH);
    strcat(Path, data_file);
    fp = fopen(Path, "rb");
    if (fp == NULL) {
        printf("首次使用,正在初始化数据文件……\n");
        Iint_DB();
        Iint_Dir();
        Data_Write();
        printf("数据文件初始化完成。\n");
        //
        printf("首次使用,已为您展示帮助文档。\n");
        Help();
    }
    fread(&g_table, sizeof(S_Table), S, fp);
    fclose(fp);
    //printf("数据文件已加载[%s]\n", g_table[0].name);
    return 0;
}

int Iint_DB() {
    //数据字典
    g_dict[0].state = 1;
    strcpy(g_dict[0].name, "noid");
    strcpy(g_dict[0].value, "1");
    strcpy(g_dict[0].comment, "下一个对象的编号");
    //案例表
    strcpy(g_table[0].name, "T0");
    g_table[0].state = 2;
    g_table[0].oid = 0;
    g_table[0].rows = 4;
    g_table[0].cols = 2;
    g_table[0].oid = 0;
    strcpy(g_table[0].record[0][0], "H");
    strcpy(g_table[0].record[0][1], "TEL");
    strcpy(g_table[0].record[0][2], "NAME");
    strcpy(g_table[0].record[1][0], "A");
    strcpy(g_table[0].record[1][1], "110");
    strcpy(g_table[0].record[1][2], "Police");
    strcpy(g_table[0].record[2][0], "A");
    strcpy(g_table[0].record[2][1], "120");
    strcpy(g_table[0].record[2][2], "Ambulance");
    strcpy(g_table[0].record[3][0], "A");
    strcpy(g_table[0].record[3][1], "119");
    strcpy(g_table[0].record[3][2], "Fire");
    return 0;
}

int Iint_Dir() {
    if (_mkdir(DefaultPATH) == 0) {
        //printf("目录创建成功!\n");
    } else {
        //printf("目录已存在!\n");
    }
    return 0;
}

int Dict_Write() {
    strcpy(Path, DefaultPATH);
    strcat(Path, dict_file);
    fp = fopen(Path, "wb");
    if (fp == NULL) {
        printf("无法打开文件\n");
        exit(1);
    }
    fwrite(&g_dict, sizeof(S_Dict), S, fp);
    fclose(fp);
    printf("字典落盘成功!\n");
    return 0;
}

int Data_Write() {
    strcpy(Path, DefaultPATH);
    strcat(Path, data_file);
    fp = fopen(Path, "wb");
    if (fp == NULL) {
        printf("无法打开文件\n");
        exit(1);
    }
    fwrite(&g_table, sizeof(S_Table), S, fp);
    fclose(fp);
    printf("数据落盘成功!\n");
    return 0;
}

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

int Create(char table_name[N]) {
    //判断表是否存在
    i = 0;
    while (g_table[i].state != 0) {
        if ((strcmp(g_table[i].name, table_name) == 0) && ((g_table[i].state == 1) || (g_table[i].state == 2))) {
            printf("表已存在\n");
            goto label_Create_end;
        }
        i++;
    }
    //寻找可写的区域+重置之前的表记录状态为D
    i = 0;
    while (i < S) {
        if ((g_table[i].state == 0) || (g_table[i].state == 4)) {
            g_table[i].state = 1; //设置表状态为:0>未分配、1>空表、2>有数、3>删除、4>清除
            g_table[i].oid = noid;
            g_table[i].rows = 0;
            g_table[i].cols = 0;
            strcpy(g_table[i].name, table_name);
            //记录列定义
            strcpy(g_table[i].record[0][0], "H"); //record状态:H>字段名、A>可用、D>删除
            printf("请输入列的[数量]:");
            scanf("%d", &g_table[i].cols);
            printf("列的[数量]:%d\n", g_table[i].cols);
            for (j = 0; j < g_table[i].cols; j++) {
                printf("请输入第[%d]列的[名称]:", j + 1);
                scanf("%s", &g_table[i].record[0][j + 1]);
            }
            noid++;
            strcpy(g_dict[0].value, itoa(noid, g_temp, L));
            //调试
            printf("表TMID:%d,表OID:%d", i, noid);
            //重置表旧数据状态
            j = 1;
            while (strlen(g_table[i].record[j][0]) != 0) {
                strcpy(g_table[i].record[j][0], "");
                j++;
            }
            //写盘
            Dict_Write();
            Data_Write();
            return 1;
        }
        i++;
    }
    printf("表空间已满,请扩容!");
    //goto标签
    label_Create_end:
    return 0;
}

int Drop(char table_name[N]) {
    //判断表是否存在
    i = 0;
    while (g_table[i].state != 0) {
        if ((strcmp(g_table[i].name, table_name) == 0) && ((g_table[i].state == 1) || (g_table[i].state == 2))) {
            //标记表状态为删除状态
            g_table[i].state = 3;
            printf("已删除\n");
            //写盘
            Dict_Write();
            Data_Write();
            return 1;
        }
        i++;
    }
    printf("表不存在!\n");
}

int Alter(char table_name[N], int cn, char g_temp[L]) {
    //判断表是否存在
    i = 0;
    while (g_table[i].state != 0) {
        if ((strcmp(g_table[i].name, table_name) == 0) && ((g_table[i].state == 1) || (g_table[i].state == 2))) {
            //表存在则更新字段
            rn = 0;
            if (cn != 0) {
                strcpy(g_table[i].record[rn][cn], g_temp);
                printf("# 更新后表结构和数据如下:\n");
                Select(table_name);
                //写盘
                Dict_Write();
                Data_Write();
                return 1;
            }
            printf("非列名位置不容许DDL!\n");
            return 1;
        }
        i++;
    }
    printf("表不存在!\n");
}

int Rename(char table_name[N], char g_temp[L]) {
    //判断新名是否冲突
    i = 0;
    while (g_table[i].state != 0) {
        if ((strcmp(g_table[i].name, g_temp) == 0) && ((g_table[i].state == 1) || (g_table[i].state == 2))) {
            printf("新表名已存在!\n");
            return 0;
        }
        i++;
    }
    //判断表是否存在
    i = 0;
    while (g_table[i].state != 0) {
        if ((strcmp(g_table[i].name, table_name) == 0) && ((g_table[i].state == 1) || (g_table[i].state == 2))) {
            //更新
            strcpy(g_table[i].name, g_temp);
            printf("# 更新成功:\n");
            List_Table();
            //写盘
            Dict_Write();
            Data_Write();
            return 1;
        }
        i++;
    }
    printf("表不存在!\n");
}

int Truncate(char table_name[N]) {
    //判断表是否存在
    i = 0;
    while (g_table[i].state != 0) {
        if ((strcmp(g_table[i].name, table_name) == 0) && ((g_table[i].state == 1) || (g_table[i].state == 2))) {
            //标记状态
            g_table[i].state = 1;
            //重置表旧数据状态
            j = 1;
            while (strlen(g_table[i].record[j][0]) != 0) {
                strcpy(g_table[i].record[j][0], "");
                j++;
            }
            printf("表已清空\n");
            //写盘
            Dict_Write();
            Data_Write();
            return 1;
        }
        i++;
    }
    printf("表不存在!\n");
}

int Purge() {
    //标记所有删除状态的表为可复用状态
    i = 0;
    while (g_table[i].state != 0) {
        if (g_table[i].state == 3) {
            //标记状态
            g_table[i].state = 4;
        }
        i++;
    }
    printf("回收站已清空!\n");
    //写盘
    Dict_Write();
    Data_Write();
    return 1;
}

int Flashback(int oid) {
    //判断表是否存在
    i = 0;
    while (g_table[i].state != 0) {
        if ((g_table[i].oid == oid) && (g_table[i].state == 3)) {
            //标记状态
            if (strlen(g_table[i].record[1][0]) == 0) {
                g_table[i].state = 1;
            } else {
                g_table[i].state = 2;
            }
            strcpy(g_table[i].name, itoa(g_table[i].oid, g_temp, L));
            printf("表已闪回\n");
            //写盘
            Dict_Write();
            Data_Write();
            return 1;
        }
        i++;
    }
    printf("表不存在或已被清理!\n");
}

int Insert(char table_name[N]) {
    //判断表是否存在
    i = 0;
    while (g_table[i].state != 0) {
        if ((strcmp(g_table[i].name, table_name) == 0) && ((g_table[i].state == 1) || (g_table[i].state == 2))) {
            //插入数据
            char *token;
            j = 0; //j记录输入了多少行
            printf("请输入多行(列以tab分隔,新行\";\\n\"结束)\n");
            //循环读取每行输入直到达到最大行数或者遇到文件结束符EOF
            while (j < R && fgets(g_temp, sizeof(g_temp), stdin)) {
                if (strcmp(g_temp, ";\n") == 0) { // 如果输入为";\n",则结束输入
                    break;
                }
                //打印输入提示符
                printf("Input > ");
                // 使用strtok分割输入字符串并存入表字段中
                token = strtok(g_temp, "\t\n");
                rn = 1; //由于第一行存储了表列信息,因此从第二行开始
                cn = 1; //将输入按token存入1开头的数组中
                while (rn < R) { //遍历表record,找到可以存储的位置
                    if ((strcmp(g_table[i].record[rn][0], "D") == 0) || (strlen(g_table[i].record[rn][0]) == 0)) {
                        while (token != NULL && cn < C) {
                            strcpy(g_table[i].record[rn][0], "A"); //设置record插入的首列
                            strncpy(g_table[i].record[rn][cn], token, L);
                            g_table[i].record[rn][cn][L - 1] = '\0'; // 确保字符串以null字符结尾
                            token = strtok(NULL, "\t\n");
                            cn++;
                        }
                        break;
                    }
                    rn++;
                }
                j++;
            }
            printf("插入结束!\n");
            //修改表状态
            g_table[i].state = 2;
            //写盘
            Dict_Write();
            Data_Write();
            //查看插入结果
            printf("# 表[%s]最新数据如下:\n", g_table[i].name);
            Select(g_table[i].name);
            return 1;
        }
        i++;
    }
    printf("表不存在!\n");
    return 0;
}

int Delete(char table_name[N], int rn) {
    //判断表是否存在
    i = 0;
    while (g_table[i].state != 0) {
        if ((strcmp(g_table[i].name, table_name) == 0) && ((g_table[i].state == 2) || (g_table[i].state == 1))) {
            //空表提示
            if (g_table[i].state == 1) {
                printf("# 空表,无法DML!\n");
                return 0;
            }
            //标记行
            if (rn != 0) {
                strcpy(g_table[i].record[rn][0], "D");
                printf("# RMID[%d]已删除\n", rn);
                printf("# 删除后表数据如下:\n");
                Select(table_name);
                //写盘
                Dict_Write();
                Data_Write();
                return 1;
            }
            printf("首行为列名不容许删除!\n");
            return 1;
        }
        i++;
    }
    printf("表不存在!\n");
}

int Update(char table_name[N], int rn, int cn, char g_temp[L]) {
    //判断表是否存在
    i = 0;
    while (g_table[i].state != 0) {
        if ((strcmp(g_table[i].name, table_name) == 0) && ((g_table[i].state == 2) || (g_table[i].state == 1))) {
            //空表提示
            if (g_table[i].state == 1) {
                printf("# 空表,无法DML!\n");
                return 0;
            }
            //更新字段
            if ((rn != 0) && (cn != 0) && (strcmp(g_table[i].record[rn][0], "A") == 0)) {
                //printf("%d %d %s %d\n", rn, cn, g_table[i].record[rn][0], strcmp(g_table[i].record[rn][0], "A"));
                strcpy(g_table[i].record[rn][cn], g_temp);
                printf("# 更新后表数据如下:\n");
                Select(table_name);
                //写盘
                Dict_Write();
                Data_Write();
                return 1;
            }
            printf("不容许DML的位置!\n");
            return 1;
        }
        i++;
    }
    printf("表不存在!\n");
}

int Select(char table_name[N]) {
    //判断表是否存在
    i = 0;
    while (g_table[i].state != 0) {
        if ((strcmp(g_table[i].name, table_name) == 0) && ((g_table[i].state == 2) || (g_table[i].state == 1))) {
            //输出内容
            j = 0;
            k = 0;
            rn = 0;
            while (strlen(g_table[i].record[rn][0]) != 0) { //遍历非空数组
                if (strcmp(g_table[i].record[rn][0], "D") != 0) { //检索非delete状态的记录
                    cn = 0;
                    printf("R[%02d] RMID[%02d] : ", k, rn);
                    while (strlen(g_table[i].record[rn][cn]) != 0) {
                        printf("%s\t", g_table[i].record[rn][cn + 1]);
                        j++;
                        cn++;
                    }
                    printf("\n");
                    k++;
                }
                rn++;
            }
            rn = k - 1;
            cn = j / (rn + 1) - 1;
            printf("# [%d]ROWS,[%d]COLS\n", rn, cn);
            //修正字典
            if ((g_table[i].rows != rn) || (g_table[i].cols != cn)) {
                g_table[i].rows = rn;
                g_table[i].cols = cn;
                printf("表行列数不正确,修正完成.\n", rn, cn);
                Data_Write();
            }
            return 1;
        }
        i++;
    }
    printf("表不存在!\n");
}



//end

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

20200426194203245.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1421006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言用SHBrowseForFolder弹出选择文件夹的对话框

【程序运行效果】 【程序代码】 main.c&#xff1a; #define COBJMACROS #include <stdio.h> #include <tchar.h> #include <Windows.h> #include <windowsx.h> #include <CommCtrl.h> #include <ShlObj.h> #include "resource.h&q…

JVM-类的生命周期

类的生命周期概述 类的生命周期描述了一个类加载、使用、卸载的整个过程。整体可以分为&#xff1a; 加载 连接&#xff0c;其中又分为验证、准备、解析三个子阶段 初始化 使用 卸载 加载阶段 加载(Loading)阶段第一步是类加载器根据类的全限定名通过不同的渠道以二进制流的方…

深入玩转Playwright:高级操作解析与实践

playwright高级操作 iframe切换 ​ 很多时候&#xff0c;网页可能是网页嵌套网页&#xff0c;就是存在不止一个html标签&#xff0c;这时候我们的selenium或者playwright一般来说定位不到&#xff0c;为什么呢&#xff1f; ​ 因为默认是定位到第一个标准的html标签内部。 …

费一凡:土木博士的自我救赎之道 | 提升之路系列(五)

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

五、防御保护---防火墙出口选路篇

五、防御保护---防火墙智能选路篇 一、就近选路二、策略路由选路1.策略路由的概念1.1匹配条件&#xff08;通过ACL定义&#xff09;1.2动作 三、智能选路 --- 全局路由策略1.基于链路带宽的负载分担2.基于链路质量进行负载分担3.基于链路权重进行负载分担4.基于链路优先级的主备…

股票市场

&#xff08;一&#xff09;股票市场 顾名思义&#xff0c;就是买卖股票的场所。就是为了撮合想发展但缺钱的企业与有钱但想投资的投资者。 股票市场按照交易场所&#xff0c;可分为场内市场和场外市场&#xff1a; 场内市场是指证券交易所&#xff0c; 场外市场就是证券交易…

比Filebeat更强大的日志收集工具-Fluent bit的http插件实战

文章目录 1.前言2. fluent bit http插件配置以及参数详解3. Http 接口服务3.1 开发Http 接口服务3.2 重启fluent bit向http web服务发送数据 1.前言 Fluent Bit 的 HTTP 插件提供了一种灵活而通用的机制&#xff0c;可用于将日志数据 从各种环境中传输到指定的远程服务器&#…

Python算法题集_滑动窗口最大值

本文为Python算法题集之一的代码示例 题目239&#xff1a;滑动窗口最大值 说明&#xff1a;给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗…

常见的网络安全威胁和防护方法

随着数字化转型和新兴技术在各行业广泛应用&#xff0c;网络安全威胁对现代企业的业务运营和生产活动也产生了日益深远的影响。常见的网络安全威胁通常有以下几种&#xff1a; 1. 钓鱼攻击 攻击者伪装成合法的实体&#xff08;如银行、电子邮件提供商、社交媒体平台等&#xf…

C++实现通讯录管理系统

目录 1、系统需求 2、创建项目 2.1 创建项目 3、菜单功能 4、退出功能 5、添加联系人 5.1 设计联系人结构体 5.2 设计通讯录结构体 5.3 main函数中创建通讯录 5.4 封装联系人函数 5.5 测试添加联系人功能 6、显示联系人 6.1 封装显示联系人函数 7、删除联系人 7.1…

获取依赖aar包的两种方式-在android studio里引入 如:glide

背景&#xff1a;我需要获取aar依赖到内网开发&#xff0c;内网几乎代表没网。 一、 如何需要获取依赖aar包 方式一&#xff1a;在官方的github中下载,耗时不建议 要从开发者网站、GitHub 存储库或其他来源获取 ‘com.github.bumptech.glide:glide:4.12.0’ AAR 包&#xff…

MySQL:MVCC原理详解

MySQL是允许多用户同时操作数据库的&#xff0c;那么就会出现多个事务的并发场景。那么再并发场景会出现很多问题&#xff1a;脏读、不可重复读、幻读的问题。 而解决这些问题所用到的方法就是&#xff1a;MVCC 多版本并发控制。而这个MVCC的实现是基于read_view、undoLog 如…

大规模机器学习(Large Scale Machine Learning)

1.大型数据集的学习 案例&#xff1a; 如果我们有一个低方差的模型&#xff0c;增加数据集的规模可以帮助你获得更好的结果。我们应该怎样应对一个有 100 万条记录的训练集&#xff1f; 以线性回归模型为例&#xff0c;每一次梯度下降迭代&#xff0c;我们都需要计算训练集的误…

古建筑电气火灾的防控与管理

摘要:我国古建筑多为砖木结构&#xff0c;当发生火灾事故时具有蔓延快、扑救难的特点&#xff0c;而火灾对古建筑的损害性很大&#xff0c;电气火灾事故在我国火灾事故中比重居高不下。本文通过对古建筑电气火灾成因进行分析&#xff0c;有针对性地提出了古建筑电气火灾防控对策…

日志之Loki详细讲解

文章目录 1 Loki1.1 引言1.2 Loki工作方式1.2.1 日志解析格式1.2.2 日志搜集架构模式1.2.3 Loki部署模式 1.3 服务端部署1.3.1 AllInOne部署模式1.3.1.1 k8s部署1.3.1.2 创建configmap1.3.1.3 创建持久化存储1.3.1.4 创建应用1.3.1.5 验证部署结果 1.3.2 裸机部署 1.4 Promtail…

炒黄金 vs 炒股:探寻投资路线的差异和各自的优势

在当前不景气的股市&#xff0c;人们越来越关注分散投资的方式&#xff0c;以期降低风险并稳定资产。炒黄金成为了一个备受关注的投资选择&#xff0c;与传统炒股相比&#xff0c;它到底有什么区别呢&#xff1f;本文将从多个维度深入分析这两种投资方式的差异以及各自的优势。…

微信开发者工具 git 拉取 failed invalid authentication scheme

微信开发者工具 git 拉取 failed invalid authentication scheme 拉取代码时报错,无效身份认证 解决方案: 1.检查git地址是否正常 2.检查git用户名密码是否正确

ElementUI组件:Button 按钮

button按钮 点击下载learnelementuispringboot项目源码 效果图 el-button.vue页面效果图 项目里el-button.vue代码 <script> export default {name: "el_button",// 注意这里的名称不能和 router inex.js里的name一样methods: {sendMsg() {// alert(1)xthi…

(2024,双流编码器,文本引导的风格迁移,调制,FFT 和低频滤波)FreeStyle:使用扩散模型进行文本引导风格迁移

FreeStyle: Free Lunch for Text-guided Style Transfer using Diffusion Models 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 方法 3.1 LDM 3.2 FreeStyle 的模型结构…

数据结构——并查集

1.并查集的定义 并查集其实也是一种树形结构&#xff0c;在使用中通常用森林的方式来表示 并查集的逻辑结构其实就是集合 并查集一般可以通过双亲写法&#xff08;顺序结构&#xff09;来完成&#xff0c;即通过一个数组存储父亲结点的下标 int s[10005]; int main() {for(…