(十六)记录 -- 5. 创建记录的数据库

5. 创建记录的数据库

用来存储结构化对象集合的数据结构(特别是当这些结构存储在一个数据文件中时)常被称为数据库(database)。

当需要通过其他函数访问数据时,同时传递两个变量(数组本身及其有效大小)会造成很大的麻烦。

如果将数组的有效大小与数据记录结合为一个单独的对象,会使操作变得简单。

可以定义一个新的结构类型来完成上述工作,该类型包含了上述的两部分值。

将新类型定义为指向记录的指针效率会更高。因此,整个员工数据库可以按照下面的结构定义:

typedef struct {
    employeeT staff[MaxEmployees];
    int nEmployees;
} *employeeDB;

此定义创建了一个名为employeeDB的新类型,可以用以下代码来声明employeeDB类型的变量,如下所示:

employeeDB db;


5.1 创建员工信息数据库

到目前为止,变量db仅包含了指针的内存空间,且没有为该变量分配任何存储空间。

仍然需要为记录的字段以及每位员工的记录分配存储空间。

为更好地理解如何操作,可以画出需要创建的结构。

和程序分解的过程一样,最好的方法是自顶向下画出结构图,然后再对每一个层次的结构进行精雕细琢。


在第一层中,数据库仅仅是一个指针,它指向的记录的具体内容暂时无需了解,如下图所示:

为完善上图, 需要查看employeeDB记录的细节,这时就可以用由包含数组staff及员工实际数量的结构来替代虚线框。如下图所示:

最后,staff数组中的每一个元素(根据最近的employeeT类型定义)都是一个指向记录的指针, 因此完整的图应该包含指向单独employeeT结构的指针,如下图所示:


为了创建这个结构,应该从部分着手。对于结构中的每一个由指针指向的方框,都需要调用函数New来为该记录分配存储空间。

假设我们需要编写程序从用户处读入一个员工信息数据库。对于每一个记录,程序需要得到每个雇员五方面的信息。

需要用一个空白的name字段作为数据库结束的标记。每个记录都应该存入数据库中,且要对记录进行计数。


读入数据库的操作,应该定义为一个函数。

由于数据库为一个指针, ReadEmployeeDatabase只能分配指针需要的存储空间,并返回一个指针。

因此,主程序声明一个数据库:

employeeDB db;

并通过调用以下函数读入值:

db = ReadEmployeeDatabase();

ReadEmployeeDatabase的实现, 采用逐步精化的方法。

只需将其分解为两个函数:
函数ReadEmployeeDatabase创建资料库结构;
函数ReadOneEmployee读入每个员工的信息。

由于函数ReadoneEmployee负责从文件中读入数据,因此该函数必须能够判断文件是否结束, 并将信息通过返回一个特殊的标志传递给ReadEmployeeDatabase。

由于函数ReadOneEmployee返回的值为employeeT类型的指针,因此最好用NULL作为文件结束标志。


函数ReadEmployeeDatabase的代码为:

static employeeDB ReadEmployeeDatabase(void) {
	employeeDB db;
	employeeT emp;
	int nEmployees;

	db = New(employeeDB);
	nEmployees = 0;

	printf("Enter a database name (use blank to stop).\n");

	while ((emp = ReadOneEmployee()) != NULL) {
		db->staff[nEmployees] = emp;
		nEmployees++;
	}
	db->nEmployees = nEmployees;

	return db;
}

函数ReadoneEmployee为每个员工分配空间,并为每个字段输入信息,代码如下:

static employeeT ReadOneEmployee(void) {
    employeeT emp;
    string name;

    printf("Name: ");
    name = malloc(50);
    fgets(name, 50, stdin);

    emp = New(employeeT);
    emp->name = name;
    return emp;
}


5.2 数据库的使用

一旦创建了一个数据库,就可以用它来作为程序的数据源,这样的程序可能用来生成报告,也可能用来计算统计结果。

例如,可以改写前面介绍的过程ListEmployees,让它运用新的数据库结构,如下所示:

static void ListEmployees(employeeDB db) {
	int i;

	for (i = 0; i< db->nEmployees; i++) {
		printf("%s(%s)", db->staff[i]->name, db->staff[i]->title);
	}
}

另外,由于employeeDB表示一个指针,同样也可以编写函数改变记录的内部数据。

下述的过程将所有与扣税款补贴大于或等于5的员工薪水增加一倍:

static void GiveRaise(employeeDB db) {
	int i;

	for (i = 0; i < db->nEmployees; i++) {
		if (db->staff[i]->withoutholding >= 5) {
			db->staff[i]->salary *= 2
		}
	}
}





参考

《C语言的科学和艺术》 —— 16 记录

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值