Читаем Язык программирования Си. Издание 3-е, исправленное полностью

for (ptr = head; ptr != NULL; ptr = ptr-›next)…

Функция install обращается к lookup, чтобы определить, имеется ли уже вставляемое имя. Если это так, то старое определение будет заменено новым. В противном случае будет образован новый элемент. Если запрос памяти для нового элемента не может быть удовлетворен, функция install выдает NULL.

struct nlist *lookup(char *);

char *strdup(char *);

/* install: заносит имя и текст (name, defn) в таблицу */

struct nlist *install(char *name, char *defn)

{

 struct nlist *np;

 unsigned hashval;

 if ((np = lookup(name)) == NULL) {/* не найден */

  np = (struct nlist *) malloc(sizeof(*np));

  if (np == NULL || (np-›name = strdup(name)) == NULL)

   return NULL;

  hashval = hash(name);

  np-›next = hashtab[hashval];

  hashtab[hashval] = np;

 }

 else /* уже имеется */

  free((void *) np-›defn); /* освобождаем прежний defn */

 if ((np-›defn = strdup(defn)) == NULL)

  return NULL;

 return np;

}

Упражнение 6.5. Напишите функцию undef, удаляющую имя и определение из таблицы, организация которой поддерживается функциями lookup и install.

Упражнение 6.6. Реализуйте простую версию #define-npoцeccopa (без аргументов), которая использовала бы программы этого параграфа и годилась бы для Си-программ. Вам могут помочь программы getch и ungetch.

<p>6.7 Средство typedef</p>

Язык Си предоставляет средство, называемое typedef, которое позволяет давать типам данных новые имена. Например, объявление

typedef int Length;

делает имя Length синонимом int. С этого момента тип Length можно применять в объявлениях, в операторе приведения и т. д. точно так же, как тип int:

Length len, maxlen;

Length *lengths[];

Аналогично объявление

typedef char *String;

делает String синонимом char *, т. e. указателем на char, и правомерным будет, например, следующее его использование:

String р, lineptr[MAXLINES], alloc(int);

int strcmp(String, String);

p = (String) malloc(100);

Заметим, что объявляемый в typedef тип стоит на месте имени переменной в обычном объявлении, а не сразу за словом typedef. С точки зрения синтаксиса слово typedef напоминает класс памяти - extern, static и т. д. Имена типов записаны с заглавных букв для того, чтобы они выделялись.

Для демонстрации более сложных примеров применения typedef воспользуемся этим средством при задании узлов деревьев, с которыми мы уже встречались в данной главе.

typedef struct tnode *Treeptr;

typedef struct tnode {/* узел дерева: */

 char *word; /* указатель на текст */

 int count; /* число вхождений */

 Treeptr left; /* левый сын */

 Treeptr right; /* правый сын */

} Treenode;

В результате создаются два новых названия типов: Treenode (структура) и Treeptr (указатель на структуру). Теперь программу talloc можно записать в следующем виде:

Treeptr talloc(void) {

 return (Treeptr) malloc(sizeof(Treenode));

}

Следует подчеркнуть, что объявление typedef не создает объявления нового типа, оно лишь сообщает новое имя уже существующему типу. Никакого нового смысла эти новые имена не несут, они объявляют переменные в точности с теми же свойствами, как если бы те были объявлены напрямую без переименования типа. Фактически typedef аналогичен #define с тем лишь отличием, что при интерпретации компилятором он может справиться с такой текстовой подстановкой, которая не может быть обработана препроцессором. Например

typedef int (*PFI)(char *, char *);

создает тип PFI - "указатель на функцию (двух аргументов типа char *), возвращающую int", который, например, в программе сортировки, описанной в главе 5, можно использовать в таком контексте:

PFI strcmp, numcmp;

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже