1.书本原代码
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#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 <stdio.h>
#include <ctype.h>
#include <string.h>
#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 <stdio.h>
#include <ctype.h>
#include <string.h>
#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的博客-优快云博客