下面给出几个例子:
写散列表
自己以前也写过,记得调试时候好痛苦,那么大的散列,找起数据来一点都不方便。
《C专家编程》中作者叙述他的同事这样写散列表:
他首先让最简单的情况能够运行,就是散列函数总是返回一个0。散列函数如下:
/* hash_file: Placeholder for more sophisticated future
routine */
int hash_filename ( char * s){
return 0 ;
}
调用这个散列函数的代码如下:
/*
* find_file: Locate a previously created file descriptor or make a new one if necessary.
*/
file find_filename ( char * s)
{
int hash_value = hash_filename(s);
file f;
for (f = file_hash_table[hash_value]; f != NIL;f = f -> flink) {
if (strcmp(f -> fname, s) == SAME) {
return f;}}
/* file not found, so make a new one: */
f = allocate_file(s);
f -> flink = file_hash_table[hash_value];
file_hash_table[hash_value] = f;
return f;
}
FSM实现cdecl
有限自动机(FSM)可以用作程序的控制结构。
它的基本思路是用一张表保存所有可能的状态,并列出进入每个状态时可能执行的所有动作,其中最后一个动作就是计算(通常在当前状态和下一次输入字符的基础上,另外再经过一次表查询)下一个应该进入的状态。你从一个“初始状态”开始。在这一过程中,翻译表可能告诉你进入了一个错误的状态,表示一个预期之外的或错误的输入。你不停地在各种状态间转换,直到到达结束状态。
不过这个例子,只需要一个函数函数指针就够了。在主循环里,程序将调用指针所指向的函数,并循环往复,直到结束函数被调用(到达FSM的终结状态)或遇到一个错误状态。
1. 状态机图,详见《C专家编程》第3章
2. 首先编写代码控制状态的转换。让每个动作程序简单打印一条信息,显示它已被调用。对他进行深入调试。
3. 增加代码处理并分析输入的声明。
完整代码:
/*
* FSM 实现 cdecl
*/
#include < stdio.h >
#include < string .h >
#include < ctype.h >
#define MAXTOKENS 100
#define MAXTOKENLEN 64
enum type_tag {
IDENTIFIER, QUALIFIER, TYPE
}; // 标识符,限定符,类型
struct token {
char type;
char string [MAXTOKENLEN];
};
int top = - 1 ;
struct token stack[MAXTOKENS]; // 保存第一个标识符之前的所有标记
struct token this ; // 保存刚刚读入的那个标记
#define pop stack[top--]
#define push(s) stack[++top] = s
enum type_tag classify_string( void ) { /* 字符串分类,推断标识符类型 */
char * s = this . string ;
if (strcmp(s, " const " ) == 0 ) {
strcpy(s, " read-only " );
return QUALIFIER;
}
if (strcmp(s, " volatile " ) == 0 )
return QUALIFIER;
if (strcmp(s, " void " ) == 0 )
return TYPE;
if (strcmp(s, " char " ) == 0 )
return TYPE;
if (strcmp(s, " signed " ) == 0 )
return TYPE;
if (strcmp(s, " unsigned " ) == 0 )
return TYPE;
if (strcmp(s, " short " ) == 0 )
return TYPE;
if (strcmp(s, " int " ) == 0 )
return TYPE;
if (strcmp(s, " long " ) == 0 )
return TYPE;
if (strcmp(s, " float " ) == 0 )
return TYPE;
if (strcmp(s, " double " ) == 0 )
return TYPE;
if (strcmp(s, " struct " ) == 0 )
return TYPE;
if (strcmp(s, " union " ) == 0 )
return TYPE;
if (strcmp(s, " enum " ) == 0 )
return TYPE;
return IDENTIFIER;
}
void gettoken( void ) { /* 读取下一个标记到”this“ */
char * p = this . string ;
// 略过空白字符
while (( * p = getchar()) == ' ' )
;
if (isalnum( * p)) {
// 读入的标识符以A-Z,0-9开头
while (isalnum( *++ p = getchar()))
;
ungetc( * p, stdin);
* p = ' \0 ' ;
this .type = classify_string();
return ;
}
this . string [ 1 ] = ' \0 ' ;
this .type = * p;
return ;
}
/* 状态函数 */
void initialize(), get_array(), get_params(), get_lparen(), get_ptr_part(),
get_type();
void ( * nextstate)( void ) = initialize;
int main() {
/* 在不同的状态间切换,直到指针值为NULL */
while (nextstate != NULL)
( * nextstate)();
return 0 ;
}
void initialize() {
gettoken();
while ( this .type != IDENTIFIER) {
push( this );
gettoken();
}
printf( " %s is " , this . string );
gettoken();
nextstate = get_array;
}
void get_array() {
nextstate = get_params;
while ( this .type == ' [ ' ) {
printf( " array " );
gettoken(); /* a number or ']' */
if (isdigit( this . string [ 0 ])) {
printf( " 0..%d " , atoi( this . string ) - 1 );
gettoken(); /* read the ']' */
}
gettoken(); /* read next past the ']' */
printf( " of " );
nextstate = get_lparen;
}
}
void get_params() {
nextstate = get_lparen;
if ( this .type == ' ( ' ) {
while ( this .type != ' ) ' ) {
gettoken();
}
gettoken();
printf( " function returning " );
}
}
/* 左小括号 */
void get_lparen() {
nextstate = get_ptr_part;
if (top >= 0 ) {
if (stack[top].type == ' ( ' ) {
pop;
gettoken(); /* read past ')' */
nextstate = get_array;
}
}
}
void get_ptr_part() {
nextstate = get_type;
if (stack[top].type == ' * ' ) {
printf( " pointer to " );
pop;
nextstate = get_lparen;
} else if (stack[top].type == QUALIFIER) {
printf( " %s " , pop. string );
nextstate = get_lparen;
}
}
void get_type() {
nextstate = NULL;
/* process tokens that we stacked while reading to
identifier */
while (top >= 0 ) {
printf( " %s " , pop. string );
}
printf( " \n " );
}