Главная · Поиск книг · Поступления книг · 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

            for( nline=0; nline < lines ; nline++ ){
                    naster = 1 + 2 * nline;

                    /* лидирующие пробелы */
                    printn(' ', lines-1  - nline);

                    /* звездочки */
                    printn('*', naster);

                    /* перевод строки */
                    putchar( '\n' );
            }
            exit(0);        /* завершение программы */
    }

1.12.  В чем состоит ошибка?

    main(){  /* печать фразы 10 раз */
       int i;
       while(i < 10){
           printf("%d-ый раз\n", i+1);
           i++;
       }
    }

Ответ: автоматическая переменная i не была проинициализирована и  содержит  не  0,  а
какое-то  произвольное  значение.  Цикл может выполниться не 10, а любое число раз (в
том числе и 0 по случайности).  Не забывайте  инициализировать  переменные,  возьмите
описание с инициализацией за правило!

       int i = 0;

Если бы переменная i была статической, она бы имела начальное значение 0.
     В данном примере было бы еще лучше использовать цикл for, в котором все операции
над индексом цикла собраны в одном месте - в заголовке цикла:

    for(i=0; i < 10; i++) printf(...);

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

1.13.  Вспомогательные переменные, не несущие смысловой нагрузки (вроде счетчика пов-
торений  цикла,  не  используемого в самом теле цикла) принято по традиции обозначать
однобуквенными именами, вроде i, j. Более того, возможны даже такие курьезы:

    main(){
      int  _ ;
      for( _ = 0; _ < 10; _++) printf("%d\n", _ );
    }

основанные на том, что подчерк в идентификаторах - полноправная буква.

1.14.  Найдите 2 ошибки в программе:

            main(){
                    int x = 12;

                    printf( "x=%d\n" );
                    int y;
                    y = 2 * x;
                    printf( "y=%d\n", y );
            }

Комментарий: в теле функции все описания должны идти перед всеми выполняемыми  опера-
торами  (кроме операторов, входящих в состав описаний с инициализацией).  Очень часто
после внесения правок в программу некоторые описания  оказываются  после  выполняемых
операторов.   Именно  поэтому  рекомендуется  отделять  строки описания переменных от
выполняемых операторов пустыми строками (в этой книге это часто не делается для  эко-
номии места).

1.15.  Найдите ошибку:

    int n;
    n = 12;
    main(){
            int y;
            y = n+2;
            printf( "%d\n", y );
    }

Ответ: выполняемый оператор n=12 находится  вне  тела  какой-либо  функции.   Следует
внести  его  в  main()  после описания переменной y, либо переписать объявление перед
main() в виде

    int n = 12;

В последнем случае присваивание переменной n значения 12 выполнит компилятор  еще  во
время  компиляции программы, а не сама программа при своем запуске. Точно так же про-
исходит со всеми статическими данными (описанными как static, либо расположенными вне
всех функций); причем если их начальное значение не указано явно - то подразумевается
0 ('\0', NULL, "").  Однако нулевые значения не хранятся в скомпилированном выполняе-
мом файле, а требуемая "чистая" память расписывается при старте программы.

1.16.  По поводу описания переменной с инициализацией:

    TYPE x = выражение;

является (почти) эквивалентом для

    TYPE x;         /* описание */
    x = выражение;  /* вычисление начального значения */

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

Рассмотрим пример:

    #include 
    extern double sqrt();   /* квадратный корень */
    double x   = 1.17;
    double s12 = sqrt(12.0);            /* #1 */
    double y   = x * 2.0;               /* #2 */
    FILE  *fp  = fopen("out.out", "w"); /* #3 */
    main(){
      double ss = sqrt(25.0) + x;       /* #4 */
      ...
    }

Строки с метками #1, #2 и #3 ошибочны. Почему?
     Ответ: при инициализации статических данных (а s12, y и fp таковыми и  являются,
так  как описаны вне какой-либо функции) выражение должно содержать только константы,
поскольку оно вычисляется КОМПИЛЯТОРОМ. Поэтому ни использование значений переменных,
ни вызовы функций здесь недопустимы (но можно брать адреса от переменных).
     В строке #4 мы инициализируем автоматическую переменную ss, т.е.  она  отводится
уже  во  время  выполнения программы. Поэтому выражение для инициализации вычисляется
уже не компилятором, а самой программой, что дает нам право использовать  переменные,
вызовы функций и.т.п., то есть выражения языка Си без ограничений.

1.17.  Напишите  программу,  реализующую  эхо-печать  вводимых  символов.   Программа
должна  завершать  работу  при получении признака EOF.  В UNIX при вводе с клавиатуры
признак EOF обычно обозначается одновременным нажатием клавиш CTRL  и  D  (CTRL  чуть
раньше),  что  в  дальнейшем  будет  обозначаться CTRL/D; а в MS DOS - клавиш CTRL/Z.
Используйте getchar() для ввода буквы и putchar() для вывода.

1.18.  Напишите программу, подсчитывающую число символов поступающих со  стандартного
ввода. Какие достоинства и недостатки у следующей реализации:

    #include 
    main(){ double cnt = 0.0;
            while (getchar() != EOF) ++cnt;
            printf("%.0f\n", cnt );
    }

Ответ: и достоинство и недостаток в том, что счетчик имеет тип double.  Достоинство -
можно  подсчитать очень большое число символов; недостаток - операции с double обычно
выполняются гораздо медленнее, чем с int и long  (до  десяти  раз),  программа  будет
работать  дольше.   В  повседневных  задачах  вам  вряд ли понадобится иметь счетчик,
отличный от long cnt; (печатать его надо по формату "%ld").

1.19.  Составьте программу перекодировки вводимых символов со стандартного  ввода  по
следующему правилу:

            a -> b
            b -> c
            c -> d
            ...
            z -> a
     другой символ -> *

Коды строчных латинских букв расположены подряд по возрастанию.

1.20.  Составьте программу перекодировки вводимых символов со стандартного  ввода  по
следующему правилу:

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

            B -> A
            C -> B
            ...
            Z -> Y
     другой символ -> *

Коды прописных латинских букв также расположены по возрастанию.

1.21.  Напишите программу, печатающую номер и код введенного символа в восьмеричном и
шестнадцатеричном  виде.   Заметьте,  что если вы наберете на вводе строку символов и
нажмете клавишу ENTER, то программа напечатает вам на один символ больше, чем вы наб-
рали.   Дело  в  том,  что код клавиши ENTER, завершившей ввод строки - символ '\n' -
тоже попадает в вашу программу (на экране  он  отображается  как  перевод  курсора  в
начало следующей строки!).

1.22.  Разберитесь, в чем состоит разница между символами '0'  (цифра  нуль)  и  '\0'
(нулевой байт). Напечатайте

      printf( "%d %d %c\n", '\0', '0', '0' );

Поставьте опыт: что печатает программа?

    main(){
            int c = 060;  /* код символа '0' */
            printf( "%c %d %o\n", c, c, c);
    }

Почему печатается 0 48 60?  Теперь напишите вместо
  int c = 060;
строчку
  char c = '0';

1.23.  Что напечатает программа?

    #include 
    void main(){
            printf("ab\0cd\nxyz");
            putchar('\n');
    }

Запомните, что '\0' служит признаком конца строки в памяти, а '\n' - в файле.  Что  в
строке "abcd\n" на конце неявно уже расположен нулевой байт:

    'a','b','c','d','\n','\0'

Что строка "ab\0cd\nxyz" - это

    'a','b','\0','c','d','\n','x','y',z','\0'

Что строка "abcd\0" - избыточна, поскольку будет иметь на  конце  два  нулевых  байта
(что  не  вредно,  но зачем?).  Что printf печатает строку до нулевого байта, а не до
закрывающей кавычки.
Программа эта напечатает ab и перевод строки.
Вопрос: чему равен sizeof("ab\0cd\nxyz")?  Ответ: 10.

1.24.  Напишите программу, печатающую целые числа от 0 до 100.

1.25.  Напишите программу, печатающую квадраты и кубы целых чисел.

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

1.26.  Напишите программу, печатающую сумму квадратов первых n целых чисел.

1.27.  Напишите программу, которая переводит секунды в дни, часы, минуты и секунды.

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

1.29.  Напишите программу, шифрующую текст файла путем замены значения символа  (нап-
ример, значение символа C заменяется на C+1 или на ~C ).

1.30.  Напишите программу, которая при введении с клавиатуры буквы печатает на терми-
нале  ключевое  слово,  начинающееся с данной буквы. Например, при введении буквы 'b'
печатает "break".

1.31.  Напишите программу, отгадывающую задуманное вами число в пределах от 1 до 200,
пользуясь  подсказкой с клавиатуры "=" (равно), "<" (меньше) и ">" (больше). Для уга-
дывания числа используйте метод деления пополам.

1.32.  Напишите программу, печатающую степени двойки

            1, 2, 4, 8, ...

Заметьте, что, начиная с некоторого n, результат становится отрицательным из-за пере-
полнения целого.

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

       x(0)   =  a

                 1      a
       x(n+1) =  - * ( ----  + x(n))
                 2     x(n)

Итерировать, пока не будет | x(n+1) - x(n) | < 0.001
     Внимание! В данной задаче массив не нужен. Достаточно хранить текущее и предыду-
щее значения x и обновлять их после каждой итерации.

1.34.  Напишите программу, распечатывающую простые числа до 1000.

            1, 2, 3, 5, 7, 11, 13, 17, ...

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

    /*#!/bin/cc primes.c -o primes -lm
     *        Простые числа.
     */
    #include 
    #include 
    int debug = 0;

    /* Корень квадратный из числа по методу Ньютона */
    #define eps 0.0001
    double  sqrt (x) double x;
    {
        double  sq, sqold, EPS;

        if (x < 0.0)
            return -1.0;
        if (x == 0.0)
            return 0.0;  /* может привести к делению на 0 */
        EPS = x * eps;
        sq = x;
        sqold = x + 30.0;         /* != sq */
        while (fabs (sq * sq - x) >= EPS) {
        /*     fabs( sq - sqold )>= EPS    */
            sqold = sq;
            sq = 0.5 * (sq + x / sq);
        }
        return sq;
    }

    /* таблица прoстых чисел */
    int is_prime (t) register int    t; {
        register int    i, up;
        int             not_div;

        if (t == 2 || t == 3 || t == 5 || t == 7)
            return 1;               /* prime */
        if (t % 2 == 0 || t == 1)
            return 0;               /* composite */
        up = ceil (sqrt ((double) t)) + 1;
        i = 3;
        not_div = 1;
        while (i <= up && not_div) {
            if (t % i == 0) {
                if (debug)
                    fprintf (stderr, "%d поделилось на %d\n",
                                       t,               i);
                not_div = 0;
                break;
            }
            i += 2;  /*
                      * Нет смысла проверять четные,
                      * потому что если делится на 2*n,
                      * то делится и на 2,
                      * а этот случай уже обработан выше.
                      */
        }
        return not_div;
    }

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

    #define COL 6
    int     n;
    main (argc, argv) char **argv;
    {
        int     i,
                j;
        int     n;

        if( argc < 2 ){
            fprintf( stderr, "Вызов: %s число [-]\n", argv[0] );
Предыдущая страница Следующая страница
1  2 3 4 5 6 7 8 9 10 11 12 13 14 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама