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

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


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

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


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
            exit(1);
        }
        i = atoi (argv[1]); /* строка -> целое, ею изображаемое */
        if( argc > 2 ) debug = 1;

        printf ("\t*** Таблица простых чисел от 2 до %d ***\n", i);
        n = 0;
        for (j = 1; j <= i; j++)
            if (is_prime (j)){

                /* распечатка в COL колонок */
                printf ("%3d%s", j, n == COL-1 ? "\n" : "\t");
                if( n == COL-1 ) n = 0;
                else             n++;
            }
        printf( "\n---\n" );
        exit (0);
    }

1.35.  Составьте программу ввода двух комплексных чисел в виде A + B * I  (каждое  на
отдельной строке) и печати их произведения в том же виде. Используйте scanf и printf.
Перед тем, как использовать scanf, проверьте себя: что неверно в нижеприведенном опе-
раторе?

    int x;
    scanf( "%d", x );

Ответ: должно быть написано "АДРЕС от x", то есть scanf( "%d", &x );

1.36.  Напишите  подпрограмму  вычисления  корня  уравнения  f(x)=0  методом  деления
отрезка пополам.  Приведем реализацию этого алгоритма для поиска целочисленного квад-
ратного корня из целого числа (этот алгоритм может использоваться, например, в машин-
ной графике при рисовании дуг):

    /* Максимальное unsigned long число */
    #define MAXINT (~0L)
    /* Определим имя-синоним для типа unsigned long */
    typedef unsigned long ulong;
    /* Функция, корень которой мы ищем: */
    #define FUNC(x, arg)  ((x) * (x) - (arg))
    /* тогда x*x - arg = 0 означает  x*x = arg, то есть
     * x = корень_квадратный(arg)     */
    /* Начальный интервал. Должен выбираться исходя из
     * особенностей функции FUNC */
    #define  LEFT_X(arg)  0
    #define RIGHT_X(arg) (arg > MAXINT)? MAXINT : (arg/2)+1;

    /* КОРЕНЬ КВАДРАТНЫЙ, округленный вниз до целого.
     * Решается по методу деления отрезка пополам:
     *    FUNC(x, arg) = 0;       x = ?

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

     */
    ulong i_sqrt( ulong arg ) {
       register ulong   mid,   /* середина интервала    */
                        rgt,   /* правый край интервала */
                        lft;   /* левый край интервала  */
       lft = LEFT_X(arg); rgt = RIGHT_X(arg);

       do{ mid = (lft + rgt + 1 )/2;
    /* +1 для ошибок округления при целочисленном делении */
           if( FUNC(mid, arg) > 0 ){
                  if( rgt == mid ) mid--;
                  rgt =  mid ;  /* приблизить правый край */
           } else lft =  mid ;  /* приблизить левый край  */
       } while( lft < rgt );
       return mid;
    }
    void main(){ ulong i;
       for(i=0; i <= 100; i++)
           printf("%ld -> %lu\n", i, i_sqrt(i));
    }

Использованное нами при объявлении переменных ключевое слово register  означает,  что
переменная  является ЧАСТО ИСПОЛЬЗУЕМОЙ, и компилятор должен попытаться разместить ее
на регистре процессора, а не в стеке (за счет чего увеличится  скорость  обращения  к
этой переменной). Это слово используется как

    register тип переменная;
    register переменная; /* подразумевается тип int */

От регистровых переменных нельзя брать адрес: &переменная ошибочно.

1.37.  Напишите программу, вычисляющую числа треугольника Паскаля и печатающую  их  в
виде треугольника.

            C(0,n)   = C(n,n)   = 1          n = 0...
            C(k,n+1) = C(k-1,n) + C(k,n)     k = 1..n
            n - номер строки

В разных вариантах используйте циклы, рекурсию.

1.38.  Напишите функцию вычисления определенного интеграла методом  Монте-Карло.  Для
этого  вам придется написать генератор случайных чисел.  Си предоставляет стандартный
датчик ЦЕЛЫХ равномерно распределенных псевдослучайных чисел: если вы хотите получить
целое число из интервала [A..B], используйте

    int x = A + rand() % (B+1-A);

Чтобы получать разные последовательности следует задавать  некий  начальный  параметр
последовательности (это называется "рандомизация") при помощи

    srand( число ); /* лучше нечетное */

Чтобы повторить одну и ту же последовательность случайных  чисел  несколько  раз,  вы
должны поступать так:

    srand(NBEG); x=rand(); ... ; x=rand();
    /* и повторить все сначала */
    srand(NBEG); x=rand(); ... ; x=rand();

Используемый метод получения случайных чисел таков:

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

    static unsigned long int next = 1L;
    int rand(){
      next = next * 1103515245 + 12345;
      return ((unsigned int)(next/65536) % 32768);
    }
    void srand(seed) unsigned int seed;
    {     next = seed;    }

Для рандомизации часто пользуются таким приемом:

    char t[sizeof(long)];
    time(t); srand(t[0] + t[1] + t[2] + t[3] + getpid());

1.39.  Напишите функцию вычисления определенного интеграла по методу Симпсона.

    /*#!/bin/cc $* -lm
     * Вычисление интеграла по методу Симпсона
     */
    #include 

    extern double integral(), sin(), fabs();
    #define PI 3.141593

    double myf(x) double x;
    {      return sin(x / 2.0);      }

    int niter;  /* номер итерации */

    void main(){
            double integral();

            printf("%g\n", integral(0.0, PI, myf, 0.000000001));
            /* Заметьте, что myf, а не myf().
             * Точное значение интеграла равно 2.0
             */
            printf("%d итераций\n", niter );
    }

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

    double integral(a, b, f, eps)
            double a, b;    /* концы отрезка */
            double eps;     /* требуемая точность */
            double (*f)();  /* подынтегральная функция */
    {
            register long i;
            double fab = (*f)(a) + (*f)(b); /* сумма на краях */
            double h, h2;   /* шаг и удвоенный шаг */
            long n, n2;     /* число точек разбиения и оно же удвоенное */
            double Sodd, Seven;  /* сумма значений f в нечетных и в
                                    четных точках */
            double S, Sprev;/* значение интеграла на данной
                               и на предыдущей итерациях */
            double x;       /* текущая абсцисса */

            niter = 0;
            n = 10L;        /* четное число */
            n2 = n * 2;

            h = fabs(b - a) / n2;   h2 = h * 2.0;

            /* Вычисляем первое приближение */
            /* Сумма по нечетным точкам: */
            for( Sodd = 0.0, x = a+h, i = 0;
                                      i < n;
                                      i++, x += h2 )
                    Sodd += (*f)(x);

            /* Сумма по четным точкам: */
            for( Seven = 0.0, x = a+h2, i = 0;
                                        i < n-1;
                                        i++, x += h2 )
                    Seven += f(x);

            /* Предварительное значение интеграла: */
            S = h / 3.0 * (fab + 4.0 * Sodd + 2.0 * Seven );
            do{
                    niter++;
                    Sprev = S;

                    /* Вычисляем интеграл с половинным шагом */
                    h2 = h;      h /= 2.0;
                    if( h == 0.0 ) break;   /* потеря значимости */
                    n  = n2;     n2 *= 2;

                    Seven = Seven + Sodd;
                    /* Вычисляем сумму по новым точкам: */
                    for( Sodd = 0.0, x = a+h, i = 0;
                                              i < n;
                                              i++, x += h2 )
                    Sodd += (*f)(x);

                    /* Значение интеграла */
                    S = h / 3.0 * (fab + 4.0 * Sodd + 2.0 * Seven );

            } while( niter < 31 && fabs(S - Sprev) / 15.0 >= eps );
            /* Используем условие Рунге для окончания итераций */

            return ( 16.0 * S - Sprev ) / 15.0 ;
            /* Возвращаем уточненное по Ричардсону значение */
    }

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

1.40.  Где ошибка?

    struct time_now{
      int  hour, min, sec;
    } X = { 13, 08, 00 }; /* 13 часов 08 минут 00 сек.*/

Ответ: 08 - восьмеричное число (так как начинается с нуля)!  А в восьмеричных  числах
цифры 8 и 9 не бывают.

1.41.  Дан текст:

       int i = -2;
       i <<= 2;
       printf("%d\n", i); /* печать сдвинутого i : -8 */
       i >>= 2;
       printf("%d\n", i); /* печатается -2 */

Закомментируем две строки (исключая их из программы):

       int i = -2;
       i <<= 2;
    /*
       printf("%d\n", i); /* печать сдвинутого i : -8 */
       i >>= 2;
    */
       printf("%d\n", i); /* печатается -2 */

Почему теперь возникает ошибка? Указание: где кончается комментарий?
     Ответ: Си не допускает вложенных комментариев. Вместо этого  часто  используются
конструкции вроде:

    #ifdef COMMENT
      ... закомментированный текст ...
    #endif /*COMMENT*/

и вроде

    /**/ printf("here");/* отладочная выдача включена  */
    /*   printf("here");/* отладочная выдача выключена */

или

    /* выключено();    /**/
       включено();     /**/

А вот дешевый способ быстро исключить  оператор  (с  возможностью  восстановления)  -
конец  комментария  занимает  отдельную  строку,  что позволяет отредактировать такой
текст редактором почти не сдвигая курсор:

       /*printf("here");
        */

1.42.  Почему программа печатает неверное значение для i2 ?

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

    int main(int argc, char *argv[]){
            int i1, i2;

            i1 = 1;         /* Инициализируем i1 /
            i2 = 2;         /* Инициализируем i2 */
            printf("Numbers %d %d\n", i1, i2);
            return(0);
    }

Ответ: в первом операторе присваивания не закрыт комментарий - весь  второй  оператор
присваивания полностью проигнорировался! Правильный вариант:

    int main(int argc, char *argv[]){
            int i1, i2;

            i1 = 1;         /* Инициализируем i1 */
            i2 = 2;         /* Инициализируем i2 */
            printf("Numbers %d %d\n", i1, i2);
            return(0);
    }

1.43.  А вот "шальной" комментарий.

    void main(){
            int n    = 10;
            int *ptr = &n;
            int x, y = 40;

            x = y/*ptr     /* должно быть 4 */  + 1;
            printf( "%d\n", x );    /* пять */
            exit(0);
    }

    /* или такой пример из жизни - взят из переписки в Relcom */
    ...
    cost = nRecords/*pFactor     /* divided by Factor, and  */
           + fixMargin;          /* plus the precalculated  */
    ...

Результат непредсказуем.  Дело в том, что y/*ptr превратилось в  начало  комментария!
Поэтому бинарные операции принято окружать пробелами.

    x = y / *ptr   /* должно быть 4 */  + 1;

1.44.  Найдите ошибки в директивах препроцессора Си [*] (вертикальная черта  обозначает
левый край файла).

____________________
   [*] Препроцессор Си - это программа /lib/cpp

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

            |
            | #include 
            |#include  < sys/types.h >
            |#   define inc (x) ((x) + 1)
            |#define N 12;
            |#define X -2
            |
            |...  printf( "n=%d\n", N );
            |...  p = 4-X;

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

Реклама