练习 6-1 上述 getword 函数不能正确处理下划线、字符串常量、注释及预处理器控制指令。请编写一个更完善的 getword 函数。

1.书本原代码

#include  
#include  
#include  

#define MAXWORD 100 
#define BUFSIZE 100
#define NKEYS (sizeof (keytab) / sizeof(keytab[0]))

char buf[BUFSIZE];
int bufp = 0;

int getword(char*, int);
int binsearch(char* word, struct key*, int n);

struct key {
	char* word;
	int count;
};

/* 计数C关键字 */
int main()
{
	int n;
	char word[MAXWORD];
	struct key  keytab[] = {
	"auto", 0,
	"break", 0,
	"case", 0,
	"char", 0,
	"const", 0,
	"continue", 0,
	"default", 0,
	"unsigned", 0,
	"void", 0,
	"volatile", 0,
	"while", 0 };
	while (getword(word, MAXWORD) != EOF)
		if (isalpha(word[0]))
			if ((n = binsearch(word, keytab, NKEYS)) >= 0)
				keytab[n].count++;
	//打印
	for (n = 0; n < NKEYS; n++)
		if (keytab[n].count > 0)
			printf("%4d %s\n",
				keytab[n].count, keytab[n].word);
	return 0;
}
/* binsearch: 找到词标签[0]…标签(n - 1) */
int binsearch(char* word, struct key tab[], int n)
{
	int cond;
	int low, high, mid;
	low = 0;
	high = n - 1;
	while (low <= high) {
		mid = (low + high) / 2;
		if ((cond = strcmp(word, tab[mid].word)) < 0)
			high = mid - 1;
		else if (cond > 0)
			low = mid + 1;
		else
			return mid;
	}
	return -1;
}

/* getword: 从输入得到下一个字或词 */
int getword(char* word, int lim)
{
	int c, getch(void);
	void ungetch(int);
	char* w = word;
	while (isspace(c = getch()));
	if (c != EOF)
		*w++ = c;
	if (!isalpha(c)) {
		*w = '\0';
		return c;
	}
	for (; --lim > 0; w++)
		if (!isalnum(*w = getch())) {
			ungetch(*w);
			break;
		}
	*w = '\0';
	return word[0];
}
int getch(void)
{
	return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c)
{
	if (bufp >= BUFSIZE)
		printf("ungetch:too many characters");
	else buf[bufp++] = c;
}

2.题目代码

#include  
#include  
#include  

#define MAXWORD 100 
#define BUFSIZE 100
#define NKEYS (sizeof (keytab) / sizeof(keytab[0]))

char buf[BUFSIZE];
int bufp = 0;

int comment(void);
int getch(void);
int getword(char*, int);
void ungetch(int c);
int binsearch(char*, struct key*, int);

struct key {
	char* word;
	int count;
};

/* 计数C关键字 */
int main(void)
{
	int n;
	char word[MAXWORD];
	struct key keytab[] = {
		{"break", 0 },
		{"case", 0 },
		{"char", 0 },
		{"const", 0 },
		{"continue", 0 },
		{"else",0},
		{"if",0},
		{"struct",0}
	};
	while (getword(word, MAXWORD) != EOF)
		if (isalpha(word[0]))
			if ((n = binsearch(word, keytab, NKEYS)) >= 0)
				keytab[n].count++;
	//打印
	for (n = 0; n < NKEYS; n++)
		if (keytab[n].count > 0)
			printf("%4d %s\n",
				keytab[n].count, keytab[n].word);
	return 0;
}
/* binsearch: 找到词标签[0]…标签(n - 1) */
int binsearch(char* word, struct key tab[], int n)
{
	int cond;
	int low, high, mid;
	low = 0;
	high = n - 1;
	while (low <= high) {
		mid = (low + high) / 2;
		if ((cond = strcmp(word, tab[mid].word)) < 0)
			high = mid - 1;
		else if (cond > 0)
			low = mid + 1;
		else
			return mid;
	}
	return -1;
}

/* getword: 从输入得到下一个字或词 */
int getword(char* word, int lim)
{
	int getchar(void);
	void ungetch(int);
	int t, tm;
	char* w = word;
	while (isspace(t = getchar()))
		;
	if (t != EOF)
		*w++ = t;
	if (isalpha(t) || t == '_' || t == '#')/*这块的代码经测试没有问题*/
	{
		for (; --lim > 0; w++)
		{
			if (!isalnum(*w = getchar()) && *w != '_')
			{
				ungetch(*w);
				break;
			}
		}
	}
	else if (t == '\'' || t == '"')/*经测试此函数也没什么问题*/
	{
		for (; --lim > 0; w++)
			if ((*w = getchar()) == '\\')
				*++w = getchar();
			else if (*w == t)/*与自己重复时,注定常量输入结束*/
			{
				w++;
				break;
			}
			else if (*w == EOF)/*正确处理下划线和预处理器控制符时都没有这么判断,为什么这里会有这个判断*/
				break;
	}
	else if (t == '/')/*能够正确处理注释,且跳过注释类容,只返回一个字符,经测试无误*/
	{
		if ((tm = getchar()) == '*')
		{
			t = comment();
		}
	}
	*w = '\0';
	return t;
}

int comment(void)
{
	char temp;
	while ((temp = getchar()) != EOF)
		if (temp == '*')
			if ((temp = getchar()) == '/')
				break;
			else
				ungetch(temp);
	return temp;
}

int getch(void)
{
	return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c)
{
	if (bufp >= BUFSIZE)
		printf("ungetch:too many characters");
	else buf[bufp++] = c;
}

代码源于:《C程序设计语言》(《The C Programming Language》)第二版第六章练习题 - 哔哩哔哩 (bilibili.com)

本代码经测试不能解决例如:if_else等带下滑线会被输入问题

3.修改

#include  
#include  
#include  

#define MAXWORD 100 
#define BUFSIZE 100
#define NKEYS (sizeof (keytab) / sizeof(keytab[0]))

char buf[BUFSIZE];
int bufp = 0;

int comment(void);
int getch(void);
int getword(char*, int);
void ungetch(int c);
int binsearch(char*, struct key*, int);

struct key {
	char* word;
	int count;
};

/* 计数C关键字 */
int main(void)
{
	int n;
	char word[MAXWORD];
	struct key keytab[] = {
		{"break", 0 },
		{"case", 0 },
		{"char", 0 },
		{"const", 0 },
		{"continue", 0 },
		{"else",0},
		{"if",0},
		{"struct",0}
	};
	while (getword(word, MAXWORD) != EOF)
		if (isalpha(word[0]))
			if ((n = binsearch(word, keytab, NKEYS)) >= 0)
				keytab[n].count++;
	//打印
	for (n = 0; n < NKEYS; n++)
		if (keytab[n].count > 0)
			printf("%4d %s\n",
				keytab[n].count, keytab[n].word);
	return 0;
}
/* binsearch: 找到词标签[0]…标签(n - 1) */
int binsearch(char* word, struct key tab[], int n)
{
	int cond;
	int low, high, mid;
	low = 0;
	high = n - 1;
	while (low <= high) {
		mid = (low + high) / 2;
		if ((cond = strcmp(word, tab[mid].word)) < 0)
			high = mid - 1;
		else if (cond > 0)
			low = mid + 1;
		else
			return mid;
	}
	return -1;
}

/* getword: 从输入得到下一个字或词 */
int getword(char* word, int lim)
{
	int getchar(void);
	void ungetch(int);
	int t, tm;
	char* w = word;
	while (isspace(t = getchar()))
		;
	if (t != EOF)
		*w++ = t;
	if (isalpha(t) || t == '_' || t == '#')/*这块的代码经测试没有问题*/
	{
		for (; --lim > 0; w++)
		{
			if (!isalnum(*w = getchar()) && *w != '_')
			{
				ungetch(*w);
				break;
			}
		}
	}
	else if (t == '\'' || t == '"')/*经测试此函数也没什么问题*/
	{
		for (; --lim > 0; w++)
			if ((*w = getchar()) == '\\')
				*++w = getchar();
			else if (*w == t)/*与自己重复时,注定常量输入结束*/
			{
				w++;
				break;
			}
			else if (*w == EOF)/*正确处理下划线和预处理器控制符时都没有这么判断,为什么这里会有这个判断*/
				break;
	}
	else if (t == '/')/*能够正确处理注释,且跳过注释类容,只返回一个字符,经测试无误*/
	{
		if ((tm = getchar()) == '*')
		{
			t = comment();
		}
	}
	*w = '\0';
	return t;
}

int comment(void)
{
	char temp;
	while ((temp = getchar()) != EOF)
		if (temp == '*')
			if ((temp = getchar()) == '/')
				break;
			else
				ungetch(temp);
	return temp;
}

int getch(void)
{
	return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c)
{
	if (bufp >= BUFSIZE)
		printf("ungetch:too many characters");
	else buf[bufp++] = c;
}

参考于:能够正确处理下划线、字符串常数、注释及预编译器控制指令的getword()函数_baidu_34263241的博客-CSDN博客

你可能感兴趣的:(蓝桥杯,c语言,c++,visual,studio)