hash的简单应用:完成c语言中的define关键字的功能

本文探讨如何利用hash表实现C语言中的#define功能,通过散列查找方法将宏定义转换为非负整数,存储在数组内的链表中,解决冲突采用拉链法。文章源于《K&R C程序设计语言》P125页的内容,附带源代码和测试结果,同时给出了课后练习题。
摘要由CSDN通过智能技术生成

缘由

经常读到这样那样的技术,hash表的技术很早就学习过了,但是一直不太明白它能拿来做什么,这次发现其可以用来完成C语言中define关键字的功能,顿时觉得非常伟大。故记录了下来。

其实现在学的什么多东西都这样的感觉,感觉学到了,了解了,但是却不知道能拿来做什么。最近了解到用C写的redis可以作为缓存来使用,以nosql方式完成,或者说是键值对的方式,速度非常快,并且一直存放在内存中。据说用了3万行左右的代码,我其实很想试着了解或者学习一下源码,这样比一直看书好多了,不那么苦闷。当然这个redis肯定也是用hash来完成的,所以,和这个主题多少还有点关系吧。说到这里unix高级环境编程的倒数第二章就是讲数据库编程的,我先看了看原理,也非常充实。不过最近阅读的C++ primer就没那么爽了,十分干燥,十分重理论,呼,稍稍抱怨几句。

其实这篇的博客的内容也就是K&R C程序设计语言 P125页的内容。我只是作了稍稍深刻的理解和敲了敲书上的例子代码。

define

大家都应该知道define关键字的作用,就是用一个字符代替另一个字符,在实际的编程中我们都是用一个字符串来代替数字,字符串能够表明这个数字的含义,编译器会在遇到这个字符串的地方通通换成,我们想要替换的数字(字也可以)。
比如这个就是大家经常遇见的:

#define MAXBUFFSIZE 1024

如果只看到1024会很迷茫,但是看到MAXBUFFSIZE就比较明白。

思路

我们用hash的散列查找方法,将输入的名字MAXBUFFSIZE,转为一个非负的整数,将这个整数作为下标,存在一个数组内。数组里存放的是一个链表的表头,每个链表元素里面存放的就是名字和被替换的文本1024,还有就是该链表的下一个元素。这样我们可以看出,我们解决hash冲突的方式就是拉链法。下图应该可以清楚阐述这一段文字:

源代码以及测试结果

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HASHSIZE 101
static struct nlist *hashtab[HASHSIZE]; /* pointer table */
//链表的每一个元素的结构
struct nlist { /* table entry: */
	struct nlist *next; /* next entry in chain */
	char *name; /* defined name */
	char *defn; /* replacement text */
};
//计算hash值
unsigned hash(char *s)
{
	unsigned hashval;
	for (hashval = 0; *s != '\0'; s++)
	hashval = *s + 31 * hashval;
	return hashval % HASHSIZE;
}

//查找这个name
struct nlist *lookup(char *s)
{
	struct nlist *np;

	for (np = hashtab[hash(s)]; np != NULL; np = np->next)
		if (strcmp(s, np->name) == 0)
			return np; /* found */
		
	return NULL; /* not found */
}

//插入一个新的define
struct nlist *install(char *name, char *defn)
{
	struct nlist *np;
	unsigned hashval;
	if ((np = lookup(name)) == NULL) { /* not found */
		np = (struct nlist *) malloc(sizeof(*np));
		if (np == NULL || (np->name = strdup(name)) == NULL)
		return NULL;
		hashval = hash(name);
		np->next = hashtab[hashval];//这里是想将新建的np插入到表头
		hashtab[hashval] = np;
	} else {/* already there */
		free((void *) np->defn); /*free previous defn */
	}
		
	if ((np->defn = strdup(defn)) == NULL)
		return NULL;

	return np;
}

int main(){
	struct nlist *np;
	install("A","1");
	install("B","2");
	install("A","11");
	install("ADLASDKLASJDLKASJDKLAJSDLKAJSDALSJDLKASJDLKJASLKDJASLKDJLASKJDLASJDLASJDLSAJLDAJSLKDAJSLKDJALKSJDALSD","4");
	install("Z","aspodkpaoskdpaoskdpaoskdpoaskdpoakspodkaspodkapsodkaposkdpoaskdpoaskdpakspodkaspodkpaoskdpoaskdasd");

	np=lookup("A");
	printf("name:%s define:%s \n",np->name,np->defn);

	np=lookup("B");
	printf("name:%s define:%s \n",np->name,np->defn);

	np=lookup("A");
	printf("name:%s define:%s \n",np->name,np->defn);

	np=lookup("ADLASDKLASJDLKASJDKLAJSDLKAJSDALSJDLKASJDLKJASLKDJASLKDJLASKJDLASJDLASJDLSAJLDAJSLKDAJSLKDJALKSJDALSD");
	printf("name:%s define:%s \n",np->name,np->defn);

	np=lookup("Z");
	printf("name:%s define:%s \n",np->name,np->defn);

	getchar();
	return 0;


}


结果:

课后练习题

Exercise 6-5

 Write a function undef that will remove a name and definition from the table maintained by lookup and install.
答:
全部源代码,包括测试代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HASHSIZE 101
static struct nlist *hashtab[HASHSIZE]; /* pointer table */

struct nlist { /* table entry: */
	struct nlist *next; /* next entry in chain */
	char *name; /* defined name */
	char *defn; /* replacement text */
};

unsigned hash(char *s)
{
	unsigned hashval;
	for (hashval = 0; *s != '\0'; s++)
	hashval = *s + 31 * hashval;
	return hashval % HASHSIZE;
}


struct nlist *lookup(char *s)
{
	struct nlist *np;

	for (np = hashtab[hash(s)]; np != NULL; np = np->next)
		if (strcmp(s, np->name) == 0)
			return np; /* found */
		
	return NULL; /* not found */
}


struct nlist *install(char *name, char *defn)
{
	struct nlist *np;
	unsigned hashval;
	if ((np = lookup(name)) == NULL) { /* not found */
		np = (struct nlist *) malloc(sizeof(*np));
		if (np == NULL || (np->name = strdup(name)) == NULL)
		return NULL;
		hashval = hash(name);
		np->next = hashtab[hashval];//这里是想将新建的np插入到表头
		hashtab[hashval] = np;
	} else {/* already there */
		free((void *) np->defn); /*free previous defn */
	}
		
	if ((np->defn = strdup(defn)) == NULL)
		return NULL;

	return np;
}
//删除一个已经define了的条目
int undef(char *name)
{	
	struct nlist *np,*pre=NULL;
	unsigned h=hash(name);
	for (np = hashtab[h]; np != NULL; np = np->next){
		if (strcmp(name, np->name) == 0){
			break;
		}
		pre=np;//记录np的前一个元素
	}
	if(np==NULL){
		return -1;//本来就没有这个元素
	}
	if (pre==NULL)//说明np是第一个元素
	{
		hashtab[h]=np->next;
	}else{
		pre->next=np->next;
		free((void *)np->name);//答案书上写的要怎么做
		free((void *)np->defn);
		free((void *)np);
	}
	return 1;
}

int main(){
	struct nlist *np;
	install("A","1");
	install("B","2");
	install("A","11");
	install("ADLASDKLASJDLKASJDKLAJSDLKAJSDALSJDLKASJDLKJASLKDJASLKDJLASKJDLASJDLASJDLSAJLDAJSLKDAJSLKDJALKSJDALSD","4");
	install("Z","aspodkpaoskdpaoskdpaoskdpoaskdpoakspodkaspodkapsodkaposkdpoaskdpoaskdpakspodkaspodkpaoskdpoaskdasd");

	np=lookup("A");
	printf("name:%s define:%s \n",np->name,np->defn);

	np=lookup("B");
	printf("name:%s define:%s \n",np->name,np->defn);

	np=lookup("A");
	printf("name:%s define:%s \n",np->name,np->defn);

	np=lookup("ADLASDKLASJDLKASJDKLAJSDLKAJSDALSJDLKASJDLKJASLKDJASLKDJLASKJDLASJDLASJDLSAJLDAJSLKDAJSLKDJALKSJDALSD");
	printf("name:%s define:%s \n",np->name,np->defn);

	np=lookup("Z");
	printf("name:%s define:%s \n",np->name,np->defn);

	if(undef("Z")==1){//等于1表示成功undef
		np=lookup("Z");
		if(np!=NULL){
			printf("name:%s define:%s \n",np->name,np->defn);
		}else{
			printf("不存在Z的deifine");
		}
		
	}

	
	getchar();
	return 0;


}

Exercise 6-6

Implement a simple version of the #define processor (i.e., no arguments) suitable for use with C programs, based on the routines of this section. You may also find getch and ungetch helpful.
答:
暂时未研究


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值