实验程序是用vc6编译,一定注意文件扩展名为c,不是cpp,在下载:http://download.csdn.net/detail/dijkstar/4036742
注意事项和遇到的问题都已经在实现程序注释中,如下:
#include <stdio.h>
#include <stdlib.h> //rand函数使用
#include <string.h>
#include "include/table.h"
#include "include/atom.h"
#pragma comment(lib, "libcii.lib")
//产生一个[M, N]区间上的随机数
int my_rand(int M,int N)
{
return (int)((double)rand()/(double)RAND_MAX*(N-M+1)+M);
}
//遍历输出函数
void Print(const void *key, void **val, void *cl)
{
char *k = (char *)key;
int **v = (int **)val;
printf("%s --- %d\n", k, *v);
}
//遍历修改函数
// 简单修改为一个固定的值
void Edit(const void *key, void **val, void *cl)
{
int **v = (int **)val;
*v = 10000;
}
void main()
{
//注意:C语言一定要将这些变量声明放在函数的头部
Table_T t1;
int i = 0;
char tmpKey[100] = {0};
char *key = NULL;
int val;
void **ary;
int tmp1 = 0, *tmp = &tmp1;
//创建表
t1 = Table_new(0, NULL, NULL);
//添加数据
//注意:本不应该这样向表中添加数据
for (; i<10; i++)
{
sprintf(tmpKey, "key%02d", i); //生成临时【key】
val = my_rand(1000, 9999); //生成【val】
key = Atom_string(tmpKey);
//第二项【key】的地址必须是一个“原子”(即每次字符串的地址不能相同!!)
// 不要简单的传递一个字符串地址,因为字符串地址不同于“原子”的地址
//第三项【val】传递时,参见该函数的源码实现——记载的是地址值,而不是将该地址的内容拷贝进去到表中
// 这里简单传递的值是一个int,如果是一个结构体变量,也应该是将结构体变量的地址值直接传递进去,
// 再次强调,Table_put内部直接赋值了地址值,而不是拷贝该地址上的内容!!
Table_put(t1, key, val);
}
//输出表长度
printf("表长度 = %d\n", Table_length(t1));
//返回表中的某一个项
// 再次注意:不要简单的传递一个字符串地址,而是传递一个原子址
val = (int)Table_get(t1, Atom_string("key03"));
printf("查找返回:key03 = %d\n", val);
//修改返回的这个val值:修改不了,再次验证这个测试程序向表中传递的【val】是一个值,不是地址(指针)
*tmp = (int)Table_get(t1, Atom_string("key03"));
*tmp = 10000;
val = (int)Table_get(t1, Atom_string("key03"));
printf("确认不能修改:key03 = %d\n", val);
//输出表方式1
printf("输出表方式1:Table_toArray\n");
ary = Table_toArray(t1, NULL);
for (i=0; ary[i]; i+=2)
{
//第二项内容,简单的是一个int:当时传递时就是这个样子!!
printf("%s --- %d\n", (char *)ary[i], (int)ary[i+1]);
}
//输出表方式2
printf("\n输出表方式1:Table_map\n");
Table_map(t1, Print, NULL);
//删除
val = (int)Table_remove(t1, Atom_string("key03"));
printf("删除的key03 = %d\n", val);
//再次输出表方式2,检查“key03”是否存在?
printf("\n确认“key03”不存在\n");
Table_map(t1, Print, NULL);
//遍历修改
Table_map(t1, Edit, NULL);
//再次输出表方式2,检查每一项是否修改
printf("\n确认每一项都已经修改\n");
Table_map(t1, Print, NULL);
}
输出结果为:
表长度 = 10
查找返回:key03 = 8278
确认不能修改:key03 = 8278
输出表方式1:Table_toArray
key03 --- 8278
key04 --- 6265
key05 --- 5318
key06 --- 4152
key07 --- 9063
key08 --- 8405
key09 --- 7719
key00 --- 1011
key01 --- 6072
key02 --- 2739
输出表方式1:Table_map
key03 --- 8278
key04 --- 6265
key05 --- 5318
key06 --- 4152
key07 --- 9063
key08 --- 8405
key09 --- 7719
key00 --- 1011
key01 --- 6072
key02 --- 2739
删除的key03 = 8278
确认“key03”不存在
key04 --- 6265
key05 --- 5318
key06 --- 4152
key07 --- 9063
key08 --- 8405
key09 --- 7719
key00 --- 1011
key01 --- 6072
key02 --- 2739
确认每一项都已经修改
key04 --- 10000
key05 --- 10000
key06 --- 10000
key07 --- 10000
key08 --- 10000
key09 --- 10000
key00 --- 10000
key01 --- 10000
key02 --- 10000
Press any key to continue
通过这个实验,深刻理解了原子的“唯一性”和地址指针。
注:① 实验程序中使用的key是原子,根据Table函数接口说明,是一个void *类型,因此可以传递一个int,一个char等等来做【key】;
② 不清楚的地方,跟踪进入到源程序实现,可以明白怎么回事。如Table_new()的后面两个参数,一个是比较函数,一个是哈希函数,都可以传递为NULL,此时使用了内部函数。
③ Table_put函数,第三个参数(最后一个参数)是一个void *val,是一个指针类型,但是请注意,调用这个函数时,不是将该地址上的内容,拷贝到内部表中,而是简单的讲地址记下来。同时想起了MFC这几个函数:
CComboBox::SetItemData
CListBox::SetItemData
CTreeCtrl::SetItemData
请借助这几个函数来理解Table_put函数。