Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Aliens Vs Predator |#5| Unexpected meeting
Aliens Vs Predator |#4| Boss fight with the Queen
Aliens Vs Predator |#3| Escaping from the captivity of the xenomorph
Aliens Vs Predator |#2| RO part 2 in HELL

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Богатырев А. Весь текст 1009.15 Kb

Хрестоматия по программированию на Си в Unix

Предыдущая страница Следующая страница
1 2 3  4 5 6 7 8 9 10 11 12 13 14 ... 87
(x) стоит пробел, который изменяет весь  смысл  макроопределения:  вместо  макроса  с
параметром inc(x) мы получаем, что слово inc будет заменяться на (x)((x)+1).  Заметим
однако, что пробелы после # перед именем директивы  вполне  допустимы.   В  четвертом
случае показана характерная опечатка - символ ; после определения. В результате напи-
санный printf() заменится на

            printf( "n=%d\n", 12; );

где лишняя ; даст синтаксическую ошибку.
     В пятом случае ошибки нет, но нас ожидает неприятность в строке  p=4-X;  которая
расширится в строку p=4--2; являющуюся синтаксически неверной.  Чтобы избежать подоб-
ной ситуации, следовало бы написать

            p = 4 - X;  /* через пробелы */

но еще проще (и лучше) взять макроопределение в скобки:

            #define X (-2)

1.45.  Напишите функцию max(x, y), возвращающую большее из  двух  значений.  Напишите
аналогичное  макроопределение.   Напишите  макроопределения min(x, y) и abs(x) (abs -
модуль числа).  Ответ:

    #define abs(x)   ((x)  <  0   ? -(x) : (x))
    #define min(x,y) (((x) < (y)) ?  (x) : (y))

Зачем x взят в круглые скобки (x)? Предположим, что мы написали

    #define abs(x)  (x < 0 ? -x : x )
                вызываем
    abs(-z)                  abs(a|b)
                получаем
    (-z < 0 ? --z : -z )     (a|b < 0 ? -a|b : a|b )

У нас появилась "дикая" операция --z; а выражение a|b<0 соответствует a|(b<0), с сов-
сем  другим порядком операций!  Поэтому заключение всех аргументов макроса в его теле
в круглые скобки позволяет избежать многих неожиданных проблем. Придерживайтесь этого
правила!
     Вот пример, показывающий зачем полезно брать в скобки все определение:

    #define div(x, y)     (x)/(y)

При вызове

А. Богатырев, 1992-95                  - 19 -                               Си в UNIX

         z = sizeof div(1, 2);
             превратится в
         z = sizeof(1) / (2);

что равно sizeof(int)/2, а не sizeof(int). Вариант

    #define div(x, y) ((x) / (y))

будет работать правильно.

1.46.  Макросы,  в  отличие  от  функций,  могут  порождать  непредвиденные  побочные
эффекты:

    int sqr(int x){ return x  *  x; }
    #define SQR(x)       ((x) * (x))
    main(){ int y=2, z;
       z = sqr(y++); printf("y=%d z=%d\n", y, z);
       y = 2;
       z = SQR(y++); printf("y=%d z=%d\n", y, z);
    }

Вызов функции sqr печатает "y=3 z=4", как мы и ожидали.  Макрос же SQR расширяется в

       z = ((y++) * (y++));

и результатом будет "y=4 z=6", где z совсем не похоже на квадрат числа 2.

1.47.  ANSI препроцессор[*] языка Си имеет оператор ## - "склейка лексем":

    #define VAR(a, b)       a ## b
    #define CV(x)           command_ ## x
    main(){
      int VAR(x, 31) = 1;
      /* превратится в int x31 = 1; */
      int CV(a) = 2; /* даст int command_a = 2; */
      ...
    }

Старые версии препроцессора не обрабатывают такой оператор, поэтому раньше  использо-
вался такой трюк:

    #define VAR(a, b)       a/**/b

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

1.48.  Напишите программу, распечатывающую максимальное и минимальное из ряда  чисел,
вводимых  с  клавиатуры.  Не  храните  вводимые числа в массиве, вычисляйте max и min
сразу при вводе очередного числа!

____________________
   [*] ANSI - American National Standards Institute, разработавший стандарт на язык  Си
и его окружение.

А. Богатырев, 1992-95                  - 20 -                               Си в UNIX

    #include 
    main(){
      int max, min, x, n;
      for( n=0; scanf("%d", &x) != EOF; n++)
            if( n == 0 ) min = max = x;
            else{
               if( x > max ) max = x;
               if( x < min ) min = x;
            }
      printf( "Ввели %d чисел: min=%d max=%d\n",
                     n,            min,   max);
    }

Напишите аналогичную программу для поиска максимума и минимума среди  элементов  мас-
сива, изначально min=max=array[0];

1.49.  Напишите программу, которая сортирует массив  заданных  чисел  по  возрастанию
(убыванию) методом пузырьковой сортировки.  Когда вы станете более опытны в Си, напи-
шите сортировку методом Шелла.

    /*
     * Сортировка по методу Шелла.
     * Сортировке подвергается массив указателей на данные типа obj.
     *      v------.-------.------.-------.------0
     *             !       !      !       !
     *             *       *      *       *
     *            элементы типа obj
     * Программа взята из книги Кернигана и Ритчи.
     */

    #include 
    #include 
    #include 
    #define obj char

    static shsort (v,n,compare)
    int n;              /* длина массива */
    obj *v[];           /* массив указателей */
    int (*compare)();   /* функция сравнения соседних элементов */
    {
            int g,      /* расстояние, на котором происходит сравнение */
                i,j;    /* индексы сравниваемых элементов */
            obj *temp;

            for( g = n/2 ; g > 0  ; g /= 2 )
            for( i = g   ; i < n  ; i++    )
            for( j = i-g ; j >= 0 ; j -= g )
            {
                    if((*compare)(v[j],v[j+g]) <= 0)
                        break;      /* уже в правильном порядке */

                    /* обменять указатели */
                    temp = v[j]; v[j] = v[j+g]; v[j+g] = temp;
                    /* В качестве упражнения можете написать
                     * при помощи curses-а программу,
                     * визуализирующую процесс сортировки:
                     * например, изображающую эту перестановку
                     * элементов массива */
            }
    }

А. Богатырев, 1992-95                  - 21 -                               Си в UNIX

    /* сортировка строк */
    ssort(v) obj **v;
    {
            extern less();  /* функция сравнения строк */
            int len;

            /* подсчет числа строк */
            len=0;
            while(v[len]) len++;
            shsort(v,len,less);
    }

    /* Функция сравнения строк.
     * Вернуть целое меньше нуля, если a <  b
     *                      ноль, если a == b
     *               больше нуля, если a >  b
     */
    less(a,b) obj *a,*b;
    {
            return strcoll(a,b);
            /* strcoll - аналог strcmp,
             * но с учетом алфавитного порядка букв.
             */
    }

    char *strings[] = {
            "Яша", "Федя", "Коля",
            "Гриша", "Сережа", "Миша",
            "Андрей Иванович", "Васька",
            NULL
    };
    int main(){
            char **next;

            setlocale(LC_ALL, "");

            ssort( strings );
            /* распечатка */
            for( next = strings ; *next ; next++ )
                    printf( "%s\n", *next );
            return 0;
    }

1.50.  Реализуйте алгоритм быстрой сортировки.

А. Богатырев, 1992-95                  - 22 -                               Си в UNIX

    /* Алгоритм быстрой сортировки. Работа алгоритма "анимируется"
     * (animate-оживлять) при помощи библиотеки curses.
     *      cc -o qsort qsort.c -lcurses -ltermcap
     */
    #include "curses.h"

    #define N 10     /* длина массива */

    /* массив, подлежащий сортировке */
    int target [N] = {
            7, 6, 10, 4, 2,
            9, 3,  8, 5, 1
    };

    int maxim;      /* максимальный элемент массива */

    /* quick sort */
    qsort (a, from, to)
            int a[];      /* сортируемый массив */
            int from;     /* левый начальный индекс */
            int to;       /* правый конечный индекс */
    {
            register i, j, x, tmp;

            if( from >= to ) return;
            /* число элементов <= 1 */

            i = from; j = to;
            x = a[ (i+j) / 2 ];     /* значение из середины */

            do{
                    /* сужение вправо */
                    while( a[i] < x ) i++ ;

                    /* сужение влево */
                    while( x < a[j] ) j--;

                    if( i <= j ){   /* обменять */
                            tmp = a[i]; a[i] = a[j] ; a[j] = tmp;
                            i++;  j--;

                            demochanges();  /* визуализация */
                    }
            } while( i <= j );

            /* Теперь обе части сошлись в одной точке.
             * Длина левой части = j - from + 1
             *       правой      = to - i   + 1
             * Все числа в левой части меньше всех чисел в правой.
             * Теперь надо просто отсортировать каждую часть в отдельности.
             * Сначала сортируем более короткую (для экономии памяти
             * в стеке ). Рекурсия:
             */
            if( (j - from)  <  (to - i) ){
                    qsort( a, from, j );
                    qsort( a, i, to   );
            } else {
                    qsort( a, i,   to );
                    qsort( a, from, j );
            }
    }

А. Богатырев, 1992-95                  - 23 -                               Си в UNIX

    int main (){
            register i;

            initscr();      /* запуск curses-а */

            /* поиск максимального числа в массиве */
            for( maxim = target[0], i = 1 ;  i < N ; i++ )
                    if( target[i] > maxim )
                        maxim = target[i];

            demochanges();
            qsort( target, 0, N-1 );
            demochanges();

            mvcur( -1, -1, LINES-1, 0);
            /* курсор в левый нижний угол */

            endwin();       /* завершить работу с curses-ом */
            return 0;
    }

    #define GAPY  2
    #define GAPX 20

    /* нарисовать картинку */
    demochanges(){
            register i, j;
            int h = LINES - 3 * GAPY - N;
            int height;

            erase();        /* зачистить окно */
            attron( A_REVERSE );

            /* рисуем матрицу упорядоченности */
            for( i=0 ; i < N ; i++ )
                    for( j = 0; j < N ; j++ ){
                        move( GAPY + i , GAPX + j * 2 );
                        addch( target[i] >= target[j] ? '*' : '.' );
                        addch( ' ' );
                        /* Рисовать '*' если элементы
                         * идут в неправильном порядке.
                         * Возможен вариант проверки target[i] > target[j]
                         */
                    }
            attroff( A_REVERSE );

            /* массив */
            for( i = 0 ; i < N ; i++ ){
                    move( GAPY + i , 5 );
                    printw( "%4d", target[i] );

                    height = (long) h * target[i] / maxim ;
                    for( j = 2 * GAPY + N + (h - height) ;
                                          j < LINES - GAPY; j++ ){
                            move( j, GAPX + i * 2 );
                            addch( '|' );
                    }
            }
            refresh();      /* проявить картинку */
            sleep(1);
    }

А. Богатырев, 1992-95                  - 24 -                               Си в UNIX

1.51.  Реализуйте приведенный фрагмент программы без использования оператора  goto  и
без меток.

            if ( i > 10 ) goto M1;
            goto M2;
            M1: j = j + i; flag = 2; goto M3;
            M2: j = j - i; flag = 1;
            M3:       ;

Заметьте, что помечать можно только оператор (может быть пустой);  поэтому  не  может
встретиться фрагмент

    { ..... Label:  }  а только { ..... Label: ; }

1.52.  В каком случае оправдано использование оператора goto?
     Ответ: при выходе из вложенных  циклов,  т.к.  оператор  break  позволяет  выйти
Предыдущая страница Следующая страница
1 2 3  4 5 6 7 8 9 10 11 12 13 14 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама