Язык программирования Си. Издание 3-е, исправленное - Брайан Керниган
0/0

Язык программирования Си. Издание 3-е, исправленное - Брайан Керниган

Уважаемые читатели!
Тут можно читать бесплатно Язык программирования Си. Издание 3-е, исправленное - Брайан Керниган. Жанр: Программирование. Так же Вы можете читать полную версию (весь текст) онлайн книги без регистрации и SMS на сайте Knigi-online.info (книги онлайн) или прочесть краткое содержание, описание, предисловие (аннотацию) от автора и ознакомиться с отзывами (комментариями) о произведении.
Описание онлайн-книги Язык программирования Си. Издание 3-е, исправленное - Брайан Керниган:
Книга широко известных авторов, разработчиков языка Си, переработанная и дополненная с учетом стандарта ANSI для языка Си, 2-е английское издание которой вышло в 1988 году, давно стала классикой для всех изучающих и/или использующих как Си, так и Си++. Русский перевод этой книги впервые был выпущен изд- вом "Финансы и статистика" в 1992 г. и с тех пор пользуется неизменным спросом читателей.Для настоящего третьего русского издания перевод заново сверен с оригиналом, в него внесены некоторые поправки, учитывающие устоявшиеся за прошедшие годы изменения в терминологии, а так же учтены замечания, размещенные автором на странице http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html.Для программистов, преподавателей и студентов.Издание подготовлено при участии издательства "Финансы и статистика"
Читем онлайн Язык программирования Си. Издание 3-е, исправленное - Брайан Керниган

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 29 30 31 32 33 34 35 36 37 ... 81

find -x -n образец

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

Необязательные аргументы разрешается располагать в любом порядке, при этом лучше, чтобы остальная часть программы не зависела от числа представленных аргументов. Кроме того, пользователю было бы удобно, если бы он мог комбинировать необязательные аргументы, например так:

find -nx образец

А теперь запишем нашу программу.

#include ‹stdio.h›

#include ‹string.h›

#define MAXLINE 1000

int getline(char *line, int max);

/* find: печать строк образцами из 1-го аргумента */

main(int argc, char *argv[])

{

 char line[MAXLINE];

 long lineno = 0;

 int c, except = 0, number = 0, found = 0;

 while (--argc › 0 && (*++argv)[0] == '-')

  while (c = *++argv[0])

   switch (c) {

   case 'x':

    except = 1;

    break;

   case 'n':

    number = 1;

    break;

   default:

    printf("find: неверный параметр %cn", c);

    argc = 0;

    found = -1;

    break;

   }

 if (argc != 1)

  printf("Используйте: find -x -n образецn");

 else

  while (getline(line, MAXLINE) › 0) {

   lineno++;

   if ((strstr(line, *argv) != NULL) != except) {

    if (number)

     printf("%ld:", lineno);

    printf("%s", line);

    found++;

   }

  }

 return found;

}

Перед получением очередного аргумента argc уменьшается на 1, а argv "перемещается" на следующий аргумент. После завершения цикла при отсутствии ошибок argc содержит количество еще не обработанных аргументов, a argv указывает на первый из них. Таким образом, argc должен быть равен 1, a *argv указывать на образец. Заметим, что *++argv является указателем на аргумент- строку, a (*++argv)[0] - его первым символом, на который можно сослаться и другим способом:

**++argv;

Поскольку оператор индексирования [] имеет более высокий приоритет, чем * и ++, круглые скобки здесь обязательны, без них выражение трактовалось бы так же, как *++(argv[0]). Именно такое выражение мы применим во внутреннем цикле, где просматриваются символы конкретного аргумента. Во внутреннем цикле выражение *++argv[0] приращивает указатель argv[0].

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

Упражнение 5.10. Напишите программу expr, интерпретирующую обратную польскую запись выражения, задаваемого командной строкой, в которой каждый оператор и операнд представлены отдельным аргументом. Например,

expr 2 3 4 + *

вычисляется так же, как выражение 2*(3+4).

Упражнение 5.11. Усовершенствуйте программы entab и detab (см. упражнения 1.20 и 1.21) таким образом, чтобы через аргументы можно было задавать список "стопов" табуляции.

Упражнение 5.12. Расширьте возможности entab и detab таким образом, чтобы при обращении вида

entab -m +n

"стопы" табуляции начинались с m-й позиции и выполнялись через каждые n позиций. Разработайте удобный для пользователя вариант поведения программы по умолчанию (когда нет никаких аргументов).

Упражнение 5.13. Напишите программу tail, печатающую n последних введенных строк. По умолчанию значение n равно 10, но при желании n можно задать с помощью аргумента. Обращение вида

tail -n

печатает n последних строк. Программа должна вести себя осмысленно при любых входных данных и любом значении n. Напишите программу так, чтобы наилучшим образом использовать память; запоминание строк организуйте, как в программе сортировки, описанной в параграфе 5.6, а не на основе двумерного массива с фиксированным размером строки.

5.11 Указатели на функции

В Си сама функция не является переменной, но можно определить указатель на функцию и работать с ним, как с обычной переменной: присваивать, размещать в массиве, передавать в качестве параметра функции, возвращать как результат из функции и т. д. Для иллюстрации этих возможностей воспользуемся программой сортировки, которая уже встречалась в настоящей главе. Изменим ее так, чтобы при задании необязательного аргумента -n вводимые строки упорядочивались по их числовому значению, а не в лексикографическом порядке.

Сортировка, как правило, распадается на три части: на сравнение, определяющее упорядоченность пары объектов; перестановку, меняющую местами пару объектов, и сортирующий алгоритм, который осуществляет сравнения и перестановки до тех пор, пока все объекты не будут упорядочены. Алгоритм сортировки не зависит от операций сравнения и перестановки, так что передавая ему в качестве параметров различные функции сравнения и перестановки, его можно настроить на различные критерии сортировки.

Лексикографическое сравнение двух строк выполняется функцией strcmp (мы уже использовали эту функцию в ранее рассмотренной программе сортировки); нам также потребуется программа numcmp, сравнивающая две строки как числовые значения и возвращающая результат сравнения в том же виде, в каком его выдает strcmp. Эти функции объявляются перед main, а указатель на одну из них передается функции qsort. Чтобы сосредоточиться на главном, мы упростили себе задачу, отказавшись от анализа возможных ошибок при задании аргументов.

#include ‹stdio.h›

#include ‹string.h›

#define MAXLINES 5000 /* максимальное число строк */

char *lineptr[MAXLINES]; /* указатели на строки текста */

int readlines(char *lineptr[], int nlines);

void writelines(char *lineptr[], int nlines);

void qsort(void *lineptr[], int left, int right,

int (*comp)(void *, void *));

int numcmp(char *, char *);

/* сортировка строк */

main(int argc, char *argv[])

{

 int nlines; /* количество прочитанных строк */

 int numeric = 0; /* 1, если сорт. по числ. знач. */

 if (argc › 1 && strcmp(argv[1], "-n") == 0)

  numeric = 1;

 if ((nlines = readlines(lineptr, MAXLINES)) ›= 0) {

  qsort((void **) lineptr, 0, nlines-1,

   (int (*)(void*,void*))(numeric ? numcmp : strcmp));

  writelines(lineptr, nlines);

  return 0;

 } else {

  printf("Bведено слишком много строкn");

  return 1;

 }

}

В обращениях к функциям qsort, strcmp и numcmp их имена трактуются как адреса этих функций, поэтому оператор& перед ними не нужен, как он не был нужен и перед именем массива.

Мы написали qsort так, чтобы она могла обрабатывать данные любого типа, а не только строки символов. Как видно из прототипа, функция qsort в качестве своих аргументов ожидает массив указателей, два целых значения и функцию с двумя аргументами-указателями. В качестве аргументов-указателей заданы указатели обобщенного типа void *. Любой указатель можно привести к типу void * и обратно без потери информации, поэтому мы можем обратиться к qsort, предварительно преобразовав аргументы в void *. Внутри функции сравнения ее аргументы будут приведены к нужному ей типу. На самом деле эти преобразования никакого влияния на представления аргументов не оказывают, они лишь обеспечивают согласованность типов для компилятора.

/* qsort: сортирует v[left]…v[right] по возрастанию */

void qsort(void *v[], int left, int right, int (*comp)(void *, void *))

{

 int i, last;

 void swap(void *v[], int, int);

 if (left ›= right) /* ничего не делается, если */

  return; /* в массиве менее двух элементов */

 swap(v, left, (left + right)/2);

 last = left;

 for (i = left+1; i ‹= right; i++)

  if ((*comp)(v[i], v[left]) ‹ 0)

   swap(v, ++last, i);

 swap(v, left, last);

 qsort(v, left, last-1, comp);

 qsort(v, last+1, right, comp);

}

Повнимательней приглядимся к объявлениям. Четвертый параметр функции qsort:

int (*comp)(void *, void *)

сообщает, что comp - это указатель на функцию, которая имеет два аргумента- указателя и выдает результат типа int. Использование comp в строке

if ((*comp)(v[i], v[left]) ‹ 0)

согласуется с объявлением "comp - это указатель на функцию", и, следовательно, *comp - это функция, а

1 ... 29 30 31 32 33 34 35 36 37 ... 81
На этой странице вы можете бесплатно читать книгу Язык программирования Си. Издание 3-е, исправленное - Брайан Керниган бесплатно.
Похожие на Язык программирования Си. Издание 3-е, исправленное - Брайан Керниган книги

Оставить комментарий

Рейтинговые книги