Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






  • Сервис онлайн-записи на собственном Telegram-боте
    Тот, кто работает в сфере услуг, знает — без ведения записи клиентов никуда. Мало того, что нужно видеть свое расписание, но и напоминать клиентам о визитах тоже. Нашли самый бюджетный и оптимальный вариант: сервис VisitTime.
    Для новых пользователей первый месяц бесплатно.
    Чат-бот для мастеров и специалистов, который упрощает ведение записей:
    Сам записывает клиентов и напоминает им о визите;
    Персонализирует скидки, чаевые, кэшбэк и предоплаты;
    Увеличивает доходимость и помогает больше зарабатывать;
    Начать пользоваться сервисом
  • Указатели на функции






     

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

    (*comp)(v[i], v[left])

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

    int *comp(void *, void *) /* НЕВЕРНО */

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

    Мы уже рассматривали функцию strcmp, сравнивающую две строки. Ниже приведена функция numcmp, которая сравнивает две строки, рассматривая их как числа; предварительно они переводятся в числовые значения функцией atof.

    #include ‹stdlib.h›

     

    /* numcmp: сравнивает s1 и s2 как числа */

    int numcmp(char *s1, char *s2)

    {

    double v1, v2;

     

    v1 = atof(s1);

    v2 = atof(s2);

    if (v1 ‹ v2)

    return -1;

    else if (v1 › v2)

    return 1;

    else

    return 0;

    }

    Функция swap, меняющая местами два указателя, идентична той, что мы привели ранее в этой главе за исключением того, что объявления указателей заменены на void*.

    void swap(void *v[], int i, int j)

    {

    void *temp;

    temp = v[i];

    v[i] = v[j];

    v[j] = temp;

    }

    Программу сортировки можно дополнить и множеством других возможностей; реализовать некоторые из них предлагается в качестве упражнений.

    Упражнение 5.14. Модифицируйте программу сортировки, чтобы она реагировала на параметр -r, указывающий, что объекты нужно сортировать в обратном порядке, т. е. в порядке убывания. Обеспечьте, чтобы -r работал и вместе с -n.

    Упражнение 5.15. Введите в программу необязательный параметр -f, задание которого делало бы неразличимыми символы нижнего и верхнего регистров (например, a и A должны оказаться при сравнении равными).

    Упражнение 5.16. Предусмотрите в программе необязательный параметр -d, который заставит программу при сравнении учитывать только буквы, цифры и пробелы. Организуйте программу таким образом, чтобы этот параметр мог работать вместе с параметром -f.

    Упражнение 5.17. Реализуйте в программе возможность работы с полями: возможность сортировки по полям внутри строк. Для каждого поля предусмотрите свой набор параметров. Предметный указатель этой книги (Имеется в виду оригинал книги на английским языке. - Примеч. пер.) упорядочивался с параметрами: -df для терминов и -n для номеров страниц.

     






    © 2023 :: MyLektsii.ru :: Мои Лекции
    Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
    Копирование текстов разрешено только с указанием индексируемой ссылки на источник.