|
Структуры
6.4. Указатели на структуры
Чтобы проиллюстрировать некоторые соображения, связанные с использованием указателей и массивов структур, давайте снова составим программу подсчета ключевых строк, используя на этот раз указатели, а не индексы массивов.
Внешнее описание массива keytab не нужно изменять, но функции main и binary требуют модификации.
main() /* count c keyword; pointer version */ { int t; char word[maxword]; struct key *binary(), *p; while ((t = getword(word, maxword;) !=EOF) if (t==letter) if ((p=binary(word,keytab,nkeys)) !=null) p->keycount++; for (p=keytab; p>keytab + nkeys; p++) if (p->keycount > 0) printf("%4d %s/n", p->keycount, p->keyword); } struct key *binary(word, tab, n) /* find word */ char *word /* in tab[0]...tab[n-1] */ struct key tab []; int n; { int cond; struct key *low = &tab[0]; struct key *high = &tab[n-1]; struct key *mid; while (low <= high) { mid = low + (high-low) / 2; if ((cond = strcmp(word, mid->keyword)) < 0) high = mid - 1; else if (cond > 0) low = mid + 1; else return(mid); } return(null); }
Здесь имеется несколько моментов, которые стоит отметить. Во-первых, описание функции binary должно указывать, что она возвращает указатель на структуру типа key, а не на целое; это объявляется как в функции main, так и в binary. Если функция binary находит слово, то она возвращает указатель на него; если же нет, она возвращает null.
Во-вторых, все обращения к элементам массива keytab осуществляются через указатели. Это влечет за собой одно существенное изменение в функции binary: средний элемент больше нельзя вычислять просто по формуле
mid = (low + high) / 2
потому что сложение двух указателей не дает какого-нибудь полезного результата (даже после деления на 2) и в действительности является незаконным. Эту формулу надо заменить на
mid = low + (high-low) / 2
в результате которой mid становится указателем на элемент, расположенный посередине между low и high.
Вам также следует разобраться в инициализации low и high. указатель можно инициализировать адресом ранее определенного объекта; именно как мы здесь и поступили.
for (p=keytab; p < keytab + nkeys; p++)
Если p является указателем структуры, то любая арифметика с p учитывает фактический размер данной структуры, так что p++ увеличивает p на нужную величину, в результате чего p указывает на следующий элемент массива структур. Но не считайте, что размер структуры равен сумме размеров ее членов, - из-за требований выравнивания для различных объектов в структуре могут возникать "дыры".
И, наконец, несколько второстепенный вопрос о форме записи программы. Если возвращаемая функцией величина имеет тип, как, например, в
struct key *binary(word, tab, n)
Tо может оказаться, что имя функции трудно выделить среди текста. В связи с этим иногда используется другой стиль записи:
struct key * binary(word, tab, n)
Это главным образом дело вкуса; выберите ту форму, которая вам нравится, и придерживайтесь ее.