HOW-TO: Программа на Си. Часть 5 Сравнение версий

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

Следующая версия
Предыдущая версия
Последняя версия Следующая версия справа и слева
fullcircle:21:программа_на_си_ч5 [2010/04/02 21:36]
создано
fullcircle:21:программа_на_си_ч5 [2010/04/12 23:13]
Строка 1: Строка 1:
 ======HOW-TO:​ Программа на Си. Часть 5====== ======HOW-TO:​ Программа на Си. Часть 5======
-\+ 
 +  - [[..:​17:​программа_на_си_ч1|Программа на Си. Часть 1]] 
 +  - [[..:​18:​программа_на_си_ч2|Программа на Си. Часть 2]] 
 +  - [[..:​19:​программа_на_си_ч3|Программа на Си. Часть 3]] 
 +  - [[..:​20:​программа_на_си_ч4|Программа на Си. Часть 4]] 
 +  - [[..:​21:​программа_на_си_ч5|Программа на Си. Часть 5]] 
 +  - [[..:​22:​программа_на_си_ч6|Программа на Си. Часть 6]] 
 +  - [[..:​23:​программа_на_си_ч7|Программа на Си. Часть 7]] 
 +  - [[..:​24:​программа_на_си_ч8|Программа на Си. Часть 8]] 
 + 
 +---- 
 <style right> <style right>
 //​Автор:​ Эли Дэ Брувэр (Elie De Brauwer)// //​Автор:​ Эли Дэ Брувэр (Elie De Brauwer)//
Строка 9: Строка 20:
 =====Указатели на функции===== =====Указатели на функции=====
 Как уже говорилось,​ если int a является целой переменной,​ то int * b=&a создаёт и инициализирует указатель b на a. Посмотрите на Листинг 1. В нём есть функция divide (строки 1-4), а на строке 6 - команда typedef, определяющая новый тип данных "​mathFun"​. Это указатель на функцию,​ которая возвращает целое число и принимает два целых в качестве аргументов. В строках с 8 по 12 определяется структура,​ которая объединяет символ с функцией. Этот приём называется "​обратный вызов"​ (callback) или обработчик (handler), и его используют очень часто. Этот приём может быть использован,​ чтобы симулировать объектно-ориентированное программирование в Си. Нужно определить структуру с некоторыми данными и указателями на функции,​ и в результате получится практически класс. Но наиболее часто он используется в GUI-программировании для регистрации функции,​ которая вызывается,​ когда пользователь совершает какое-либо действие. Если у вас установлен пакет manpages-dev,​ то набрав "man qsort" вы увидите определение функции,​ которая реализует алгоритм (см. Листинг 2). Как видите,​ эта функция способна сортировать данные и указатель на неё должен быть передан функции,​ которая может выполнять сравнения,​ что полезно при сортировке массива значений независимо от их характера. Как уже говорилось,​ если int a является целой переменной,​ то int * b=&a создаёт и инициализирует указатель b на a. Посмотрите на Листинг 1. В нём есть функция divide (строки 1-4), а на строке 6 - команда typedef, определяющая новый тип данных "​mathFun"​. Это указатель на функцию,​ которая возвращает целое число и принимает два целых в качестве аргументов. В строках с 8 по 12 определяется структура,​ которая объединяет символ с функцией. Этот приём называется "​обратный вызов"​ (callback) или обработчик (handler), и его используют очень часто. Этот приём может быть использован,​ чтобы симулировать объектно-ориентированное программирование в Си. Нужно определить структуру с некоторыми данными и указателями на функции,​ и в результате получится практически класс. Но наиболее часто он используется в GUI-программировании для регистрации функции,​ которая вызывается,​ когда пользователь совершает какое-либо действие. Если у вас установлен пакет manpages-dev,​ то набрав "man qsort" вы увидите определение функции,​ которая реализует алгоритм (см. Листинг 2). Как видите,​ эта функция способна сортировать данные и указатель на неё должен быть передан функции,​ которая может выполнять сравнения,​ что полезно при сортировке массива значений независимо от их характера.
-Листинг 1:+ 
 +**Листинг 1:**
 <code c> <code c>
 01.int divide(int a, int b) 01.int divide(int a, int b)
Строка 23: Строка 35:
 11.    mathFun f; 11.    mathFun f;
 12.}; 12.};
 +</​code>​
 +
 +**Листинг 2: отрывок из man 3 qsort**
 +<code c>
 +NAME 
 +       qsort - sorts an array 
 +SYNOPSIS ​
 +       #​include <​stdlib.h> ​
 +
 +       void qsort(void *base, size_t nmemb, size_t size, 
 +                  int(*compar)(const void *, const void *)); 
 +DESCRIPTION ​
 +       ​The ​ qsort() ​ function sorts an array with nmemb elements of size size. 
 +       The base argument points to the start of the array.
 </​code>​ </​code>​
  
Строка 29: Строка 55:
  
 В Листинге 3 приведена простая реализация этой программы. В строке 3 происходит выделение хранилища для четырёх структур,​ которые заполняются оператором и указателями на функции в строках 4 по 7. Далее на строках 12-18 обрабатывается ввод пользователя. Когда пользователь что-то ввёл, в строках 20-32 производится поиск в массиве команд значения,​ соответствующего знаку операции. Если значение найдено,​ происходит обратный вызов с прочитанными данными,​ и выводится результат. И больше ничего делать не нужно. В Листинге 3 приведена простая реализация этой программы. В строке 3 происходит выделение хранилища для четырёх структур,​ которые заполняются оператором и указателями на функции в строках 4 по 7. Далее на строках 12-18 обрабатывается ввод пользователя. Когда пользователь что-то ввёл, в строках 20-32 производится поиск в массиве команд значения,​ соответствующего знаку операции. Если значение найдено,​ происходит обратный вызов с прочитанными данными,​ и выводится результат. И больше ничего делать не нужно.
 +
 +**Листинг 3: основной цикл ​ calc.c**
 +<code c>
 +01.int main()
 +02.{
 +03.    struct operator ​ functs[4];
 +04.    functs[0].c='​-';​ functs[0].f=&​minus;​
 +05.    functs[1].c='​+';​ functs[1].f=&​add;​
 +06.    functs[2].c='​*';​ functs[2].f=&​multiply;​
 +07.    functs[3].c='/';​ functs[3].f=&​divide;​
 +08.    while(1)
 +09.    {
 +10.        int a,b,i;
 +11.        char c;
 +12.        printf("​Введите a:​\n"​);​
 +13.        scanf("​%d",&​a);​
 +14.        printf("​Введите b:​\n"​);​
 +15.        scanf("​%d",&​b);​
 +16.        printf("​Введите оператор:​\n"​);​
 +17.        scanf("​%c",&​c);​ // Перенос строки
 +18.        scanf("​%c",&​c);​
 +19.        i=0;
 +20.        while(i<​4)
 +21.        {
 +22.            if(functs[i].c==c)
 +23.            {
 +24.                printf("​Результат:​ %d\n",​functs[i].f(a,​b));​
 +25.                break;
 +26.            }
 +27.            i++;
 +28.        }
 +29.        if(i==4)
 +30.        {
 +31.            printf("​Неизвестный оператор:​ %c\n",​c);​
 +32.        }
 +33.    }
 +34.    return 0;
 +35. }
 +</​code>​
  
 =====Ввод пользователя===== =====Ввод пользователя=====
Строка 39: Строка 104:
   * Сделайте,​ чтобы пользователь мог выйти из приложения введя "​q"​.   * Сделайте,​ чтобы пользователь мог выйти из приложения введя "​q"​.
   * Измените приложение,​ чтобы пользователь мог вводить не символы,​ а фразы "5 плюс 6" или "6 минус 5". Для этого необходимо будет изменить структуры,​ чтобы в качестве оператора была строка,​ а вместо считывания символа нужно будет считывать строку. Будет прекрасно,​ если вы сможете написать этот код без ошибок переполнения буфера (см. man getline) и утечек памяти. ​   * Измените приложение,​ чтобы пользователь мог вводить не символы,​ а фразы "5 плюс 6" или "6 минус 5". Для этого необходимо будет изменить структуры,​ чтобы в качестве оператора была строка,​ а вместо считывания символа нужно будет считывать строку. Будет прекрасно,​ если вы сможете написать этот код без ошибок переполнения буфера (см. man getline) и утечек памяти. ​
 +  * 
 +<note tip>Elie De Brauwer - фанатик Linux из Бельгии. Когда он не со своей семьёй,​ он любит играть с технологиями и проводит дни, ожидая,​ когда Blizzard наконец выпустит Diablo III. </​note>​
 +
 +
 +----
 +<style center>
 +  - [[..:​17:​программа_на_си_ч1|Программа на Си. Часть 1]]
 +  - [[..:​18:​программа_на_си_ч2|Программа на Си. Часть 2]]
 +  - [[..:​19:​программа_на_си_ч3|Программа на Си. Часть 3]]
 +  - [[..:​20:​программа_на_си_ч4|Программа на Си. Часть 4]]
 +  - [[..:​21:​программа_на_си_ч5|Программа на Си. Часть 5]]
 +  - [[..:​22:​программа_на_си_ч6|Программа на Си. Часть 6]]
 +  - [[..:​23:​программа_на_си_ч7|Программа на Си. Часть 7]]
 +  - [[..:​24:​программа_на_си_ч8|Программа на Си. Часть 8]]
 +
 +----
 +
 +//​[[..:​21|К содержанию номера]]//​
 +
 +//​[[:​fullcircle|К архиву журналов]]//​
 +</​style>​
 +
 +{{tag>​howto Си Програмирование Full_Circle}}