我面临的任务是:练习 6.2。编写一个程序,读取 C 程序的文本,并按字母顺序打印所有变量名称组,其中前 6 个字符相同,但后续字符在某些方面有所不同。不要处理引用的字符串和注释的内部。将数字 6 设置为在命令行上指定的参数。我用更简化的版本解决了它,并简单地处理了输入到终端中的单词。我将它们全部放置为一棵大二叉树,其节点也是树,但具有相同的 N 个字母。我希望我的程序不输出那些包含一个单词的树,我该如何更改程序以使其正常工作。
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
struct tnode { /* узел дерева */
char *word; /* указатель на текст */
struct tnode *left; /* левый сын */
struct tnode *right; /* правый сын */
int count; // подсчет количества слов в узле
};
struct tree_of_trees {
struct tnode *bin_tree;
struct tree_of_trees *left_son;
struct tree_of_trees *right_son;
};
/* talloc: создает tnode */
struct tnode *talloc(void)
{
return (struct tnode *) malloc(sizeof(struct tnode));
}
char *strdup_(char *s) /* делает дубликат s */
{
char *p;
p = (char *) malloc(strlen(s)+1); /* +1 для '\0' */
if (p != NULL)
strcpy(p, s);
return p;
}
/* addtree: добавляет узел со словом w в р или ниже него */
struct tnode *addtree(struct tnode *p, char *w)
{
int cond;
if (p == NULL) { /* слово встречается впервые */
p = talloc(); /* создается новый узел */
p->word = strdup_(w);
p->left = p->right = NULL;
p -> count = 1;
}
else if ((cond = strcmp(w, p -> word)) < 0){ /* меньше корня левого поддерева */
p->left = addtree(p->left, w);
p -> count++;
}
else if (cond > 0){ /* больше корня правого поддерева */
p->right = addtree(p->right, w);
p -> count++;
}
return p;
}
struct tree_of_trees *balloc(void)
{
return (struct tree_of_trees *) malloc(sizeof(struct tree_of_trees));
}
char *skip_n(char *word, int n){
return &word[n + 1];
}
char *check_n(char *word, int n){
char *p, *w;
p = w = word;
for (int i = 1; i < n; i++)
*++w = *(++word);
return p;
}
struct tree_of_trees *big_tree(struct tree_of_trees *p, struct tnode *vet, int n){
int cond;
if (vet == NULL) return p;
if (p == NULL){
p = balloc();
p->bin_tree = vet;
p->left_son = p->right_son = NULL;
}
if (strcmp(check_n(vet->word, n), check_n(p -> bin_tree -> word, n)) == 0){
if ((cond = strcmp(skip_n(vet->word, n), skip_n(p -> bin_tree -> word, n))) < 0)
p -> left_son = big_tree(p->left_son, vet, n);
else if (cond > 0)
p -> right_son = big_tree(p->right_son, vet, n);
}
return p;
}
#define BUFSIZE 100
char buf[BUFSIZE]; // буфер для ungetch
int bufp = 0; // след. свободная позиция в буфере
int getch(void) // взять (возможно возращенный) символ
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
void ungetch(int c) // вернуть символ на ввод. Чтобы избежать потери какого-либо символа и непредвиденных ошибок.
{
if (bufp >= BUFSIZE)
printf("ungetch: a lot of symbols\n");
else
buf[bufp++] = c;
}
/* getword: принимает следующее слово или символ из ввода */
int getword (char *word, int lim)
{
char c;
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];
}
void treeprint_(struct tnode *a);
// Печать дерева(из деревьев) отсортированного по алфавиту
void bigtreeprint(struct tree_of_trees *p){
if (p != NULL){
bigtreeprint(p -> left_son);
treeprint_(p -> bin_tree);
bigtreeprint(p -> right_son);
}
}
/* treeprint: упорядоченная печать дерева р */
void treeprint_(struct tnode *p)
{
if (p != NULL) {
treeprint_(p->left);
printf("%s\n", p->word);
treeprint_(p->right);
}
}
void free_tree(struct tnode *p) {
if (p != NULL) {
free_tree(p->left);
free_tree(p->right);
free(p->word);
free(p);
}
}
void free_big_tree(struct tree_of_trees *p) {
if (p != NULL) {
free_big_tree(p->left_son);
free_big_tree(p->right_son);
free_tree(p->bin_tree);
free(p);
}
}
int main(int argc, char *argv[])
{
int n = 6;
while (--argc > 0) n = atoi(*++argv);
struct tnode *root_internal;
struct tree_of_trees *root_main;
char word[100];
root_main = NULL;
root_internal = NULL;
while (getword (word, 100) != EOF){
if ((isalpha(word[0]) || word[0] == '_') && strlen(word) > n){
root_main = big_tree(root_main, root_internal, n);
root_internal = addtree(root_internal, word);
}
}
bigtreeprint(root_main);
free_big_tree(root_main);
return 0;
}