Главная · Поиск книг · Поступления книг · 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 ... 22 23 24 25 26 27 28  29 30 31 32 33 34 35 ... 87
файле символов.  Поэтому для его хранения требуется больше одного байта  (нужен  хотя
бы еще 1 бит).  Проверка на конец файла в программе обычно выглядит так:

          ...
     while((ch = getchar()) != EOF ){
          putchar(ch);
          ...
     }

-    Пусть ch имеет тип unsigned char.  Тогда ch всегда лежит в интервале  0...255  и
     НИКОГДА  не  будет  равно  (-1).  Даже если getchar() вернет такое значение, оно
     будет приведено к типу unsigned char обрубанием и станет равным 255.  При  срав-
     нении  с  целым (-1) оно расширится в int добавлением нулей слева и станет равно
     255.  Таким образом, наша программа никогда не завершится, т.к. вместо  признака
     конца файла она будет читать символ с кодом 255 (255 != -1).
-    Пусть ch имеет тип signed char.  Тогда перед сравнением с целым числом EOF  байт
     ch  будет  приведен  к  типу signed int при помощи расширения знакового бита (7-
     ого). Если getchar вернет значение (-1), то оно  будет  сначала  в  присваивании
     значения байту ch обрублено до типа char: 255; но в сравнении с EOF значение 255
     будет приведено к типу int и получится (-1). Таким образом, истинный конец файла
     будет  обнаружен.   Но  теперь,  если из файла будет прочитан настоящий символ с
     кодом 255, он будет приведен в сравнении к целому значению (-1)  и  будет  также
     воспринят  как конец файла.  Таким образом, если в нашем файле окажется символ с
     кодом 255, то программа воспримет его как фальшивый конец файла и  оставит  весь
     остаток  файла  необработанным  (а  в нетекстовых файлах такие символы - не ред-
     кость).
-    Пусть ch имеет тип int или unsigned int (больше 8 бит).  Тогда все корректно.

Отметим, что в UNIX признак конца файла в самом файле физически НЕ ХРАНИТСЯ.  Система
в  любой  момент  времени  знает длину файла с точностью до одного байта; признак EOF
вырабатывается стандартными функциями тогда, когда обнаруживается, что указатель чте-
ния  достиг  конца файла (то есть позиция чтения стала равной длине файла - последний
байт уже прочитан).
     В MS DOS же в текстовых файлах признак конца (EOF) хранится явно и  обозначается
символом  CTRL/Z.  Поэтому,  если  программным  путем записать куда-нибудь в середину
файла символ CTRL/Z, то некоторые программы перестанут "видеть" остаток  файла  после
этого символа!
     Наконец отметим, что разные функции при достижении  конца  файла  выдают  разные
значения:  scanf,  fscanf,  fgetc, getc, getchar выдают EOF, read - выдает 0, а gets,
fgets - NULL.

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

4.17.  Напишите программу, которая запрашивает ваше имя и приветствует вас. Для ввода
имени используйте стандартные библиотечные функции

      gets(s);
     fgets(s,slen,fp);

В чем разница?
     Ответ: функция gets() читает строку (завершающуюся '\n')  из  канала  fp==stdin.
Она  не  контролирует длину буфера, в которую считывается строка, поэтому если строка
окажется слишком длинной - ваша программа повредит свою  память  (и  аварийно  завер-
шится). Единственный возможный совет - делайте буфер достаточно большим (очень туман-
ное понятие!), чтобы вместить максимально возможную (длинную) строку.
     Функция fgets() контролирует длину строки: если строка на входе  окажется  длин-
нее, чем slen символов, то остаток строки не будет прочитан в буфер s, а будет остав-
лен "на потом". Следующий вызов fgets прочитает этот сохраненный остаток. Кроме  того
fgets, в отличие от gets, не обрубает символ '\n' на конце строки, что доставляет нам
дополнительные хлопоты по его уничтожению, поскольку в Си "нормальные" строки  завер-
шаются просто '\0', а не "\n\0".

    char buffer[512]; FILE *fp = ... ; int len;
          ...
    while(fgets(buffer, sizeof buffer, fp)){
      if((len = strlen(buffer)) && buffer[len-1] == '\n')
      /* @ */                      buffer[--len] =  '\0';
      printf("%s\n", buffer);
    }

Здесь len - длина строки. Если бы мы выбросили оператор, помеченный  '@',  то  printf
печатал  бы  текст  через  строку,  поскольку  выдавал бы код '\n' дважды - из строки
buffer и из формата "%s\n".
     Если в файле больше нет строк (файл дочитан до конца), то функции gets  и  fgets
возвращают значение NULL.  Обратите внимание, что NULL, а не EOF.  Пока файл не дочи-
тан, эти функции возвращают свой первый аргумент - адрес буфера, в который была запи-
сана очередная строка файла.
     Фрагмент для обрубания символа перевода строки может выглядеть еще так:

    #include 
    #include 
    char buffer[512]; FILE *fp = ... ;
          ...
    while(fgets(buffer, sizeof buffer, fp) != NULL){
      char *sptr;
      if(sptr = strchr(buffer, '\n'))
        *sptr = '\0';
      printf("%s\n", buffer);
    }

4.18.  В чем отличие puts(s); и fputs(s,fp); ?
     Ответ: puts выдает строку s в канал stdout.  При этом puts выдает сначала строку
s,  а  затем  - дополнительно - символ перевода строки '\n'.  Функция же fputs символ
перевода строки не добавляет.  Упрощенно:

    fputs(s, fp) char *s; FILE *fp;
    { while(*s) putc(*s++, fp); }
    puts(s) char *s;
    { fputs(s, stdout); putchar('\n'); }

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

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

      #include 
      main() {
          int fp;
          int i;
          char str[20];

          fp = fopen("файл");
          fgets(stdin, str, sizeof str);
          for( i = 0; i < 40; i++  );
               fputs(fp, "Текст, выводимый в файл:%s",str );
          fclose("файл");
      }

Мораль: надо быть внимательнее к формату вызова и смыслу библиотечных функций.

4.20.  Напишите программу, которая распечатывает самую длинную строку из файла  ввода
и ее длину.

4.21.  Напишите программу, которая выдает n-ую строку  файла.   Номер  строки  и  имя
файла задаются как аргументы main().

4.22.  Напишите программу

    slice -сКакой +сколько файл

которая выдает сколько строк файла файл, начиная со строки  номер  сКакой  (нумерация
строк с единицы).

    #include 
    #include 
    long line, count, nline, ncount; /* нули */
    char buf[512];

    void main(int argc, char **argv){
      char c; FILE *fp;

      argc--; argv++;
      /* Разбор ключей */
      while((c = **argv) == '-' || c == '+'){
        long atol(), val; char *s = &(*argv)[1];
        if( isdigit(*s)){
           val = atol(s);
           if(c == '-')     nline  = val;
           else             ncount = val;
        } else fprintf(stderr,"Неизвестный ключ %s\n", s-1);
        argc--; ++argv;
      }
      if( !*argv ) fp = stdin;
      else if((fp = fopen(*argv, "r")) == NULL){
        fprintf(stderr, "Не могу читать %s\n", *argv);
        exit(1);
      }
    for(line=1, count=0; fgets(buf, sizeof buf, fp); line++){
          if(line >= nline){
             fputs(buf, stdout); count++;
          }
          if(ncount && count == ncount)
             break;
      }

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

      fclose(fp); /* это не обязательно писать явно */
    }
    /* End_Of_File */

4.23.  Составьте программу, которая распечатывает последние n строк файла ввода.

4.24.  Напишите программу, которая делит входной файл на файлы по n строк в каждом.

4.25.  Напишите программу, которая читает 2 файла  и  печатает  их  вперемежку:  одна
строка  из первого файла, другая - из второго.  Придумайте, как поступить, если файлы
содержат разное число строк.

4.26.  Напишите программу сравнения двух файлов, которая  будет  печатать  первую  из
различающихся строк и позицию символа, в котором они различаются.

4.27.  Напишите программу для интерактивной работы с файлом.  Сначала у вас  запраши-
вается имя файла, а затем вам выдается меню:

    1. Записать текст в файл.
    2. Дописать текст к концу файла.
    3. Просмотреть файл.
    4. Удалить файл.
    5. Закончить работу.

Текст вводится в файл построчно с клавиатуры. Конец ввода - EOF (т.е.  CTRL/D),  либо
одиночный символ '.' в начале строки.  Выдавайте число введенных строк.
     Просмотр файла должен вестись постранично: после выдачи очередной  порции  строк
выдавайте подсказку

    --more-- _

(курсор остается в той же строке и обозначен подчерком) и ожидайте  нажатия  клавиши.
Ответ  'q'  завершает просмотр.  Если файл, который вы хотите просмотреть, не сущест-
вует - выдавайте сообщение об ошибке.
     После выполнения действия программа вновь запрашивает имя файла.  Если вы  отве-
тите вводом пустой строки (сразу нажмете , то должно использоваться имя файла,
введенное на предыдущем шаге.  Имя файла, предлагаемое по умолчанию, принято писать в
запросе в [] скобках.

    Введите имя файла [oldfile.txt]: _

Когда вы научитесь работать с экраном  дисплея  (см.  главу  "Экранные  библиотеки"),
перепишите меню и выдачу сообщений с использованием позиционирования курсора в задан-
ное место экрана и с выделением текста инверсией.  Для выбора имени файла  предложите
меню:  отсортированный список имен всех файлов текущего каталога (по поводу получения
списка файлов см. главу про взаимодействие с UNIX).  Просто для  распечатки  текущего
каталога на экране можно также использовать вызов
     system("ls -x");
а для считывания каталога в программу[*]

    FILE *fp = popen("ls *.c", "r");
    ... fgets(...,fp); ... // в цикле, пока не EOF
    pclose(fp);

(в этом примере читаются только имена .c файлов).

4.28.  Напишите программу удаления n-ой строки из файла; вставки строки  после  m-ой.
К  сожалению, это возможно только путем переписывания всего файла в другое место (без
будет вполне законно, поскольку в данном случае
                                                sp
                                                   - не имя массива (т.е.  константа,

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

4.29.  Составьте программу перекодировки текста, набитого в кодировке КОИ-8,  в  аль-
тернативную  кодировку и наоборот.  Для этого следует составить таблицу перекодировки
из 256 символов: c_new=TABLE[c_old]; Для решения обратной  задачи  используйте  стан-
дартную функцию strchr().  Программа читает один файл и создает новый.

4.30.  Напишите программу, делящую большой файл на  куски  заданного  размера  (не  в
строках,  а  в килобайтах).  Эта программа может применяться для записи слишком боль-
шого файла на дискеты (файл режется на части и записывается на несколько дискет).

    #include 
    #include 
    #define min(a,b)  (((a) < (b)) ? (a) : (b))
    #define KB                   1024  /* килобайт */
    #define PORTION         (20L* KB)  /* < 32768  */
    long    ONEFILESIZE  = (300L* KB);
    extern char    *strrchr(char *, char);
    extern long     atol   (char *);
    extern errno;           /* системный код ошибки  */
    char    buf[PORTION];   /* буфер для копирования */

    void main (int ac, char *av[]) {
        char    name[128], *s, *prog = av[0];
        int     cnt=0, done=0, fdin, fdout;
    /* M_UNIX автоматически определяется
     * компилятором в UNIX */
    #ifndef M_UNIX  /* т.е. MS DOS */
        extern int _fmode; _fmode = O_BINARY;
        /* Задает режим открытия и создания ВСЕХ файлов */
    #endif
        if(av[1] && *av[1] == '-'){ /* размер одного куска */
            ONEFILESIZE = atol(av[1]+1) * KB; av++; ac--;
        }
        if (ac < 2){
          fprintf(stderr, "Usage: %s [-size] file\n", prog);
          exit(1);
        }
        if ((fdin = open (av[1], O_RDONLY)) < 0) {
    fprintf (stderr, "Cannot read %s\n", av[1]); exit (2);
        }
        if ((s = strrchr (av[1], '.'))!= NULL) *s = '\0';
Предыдущая страница Следующая страница
1 ... 22 23 24 25 26 27 28  29 30 31 32 33 34 35 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама