Главная · Поиск книг · Поступления книг · 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 ... 12 13 14 15 16 17 18  19 20 21 22 23 24 25 ... 87

            a = str1; b = str2;

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

            while( *b )
                   *++a = *b++;
            printf( "str=%s a=%s\n", str1, a );
        }

Ответ:

       str=xyzdef a=def
       str=xxyzef a=zef

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

    char *s;
    for(s = "Ситроен"; *s; s+= 2){
        putchar(s[0]); if(!s[1]) break;
    }
    putchar('\n');

2.39.  Что напечатает программа? Рассмотрите продвижение указателя  s,  указателей  -
элементов массива strs[]. Разберитесь с порядком выполнения операций. В каких случаях
++ изменяет указатель, а в каких - букву в строке? Нарисуйте себе картинку, изобража-
ющую  состояние указателей - она поможет вам распутать эти спагетти.  Уделите разбору
этого примера достаточное время!

    #include       /* определение NULL */
    /* Латинский алфавит: abcdefghijklmnopqrstuvwxyz */
    char *strs[] = {
      "abcd","ABCD","0fpx","159",
      "hello","-gop","A1479",NULL
    };
    main(){
      char c,      **s = strs,       *p;
      c = *++*s;   printf("#1 %d %c %s\n", s-strs, c, *s);
      c = **++s;   printf("#2 %d %c %s\n", s-strs, c, *s);
      c = **s++;   printf("#3 %d %c %s\n", s-strs, c, *s);
      c = ++**s;   printf("#4 %d %c %s\n", s-strs, c, *s);
      c = (**s)++; printf("#5 %d %c %s\n", s-strs, c, *s);
      c = ++*++*s; printf("#6 %d %c %s\n", s-strs, c, *s);
      c = *++*s++; printf("#7 %d %c %s %s\n",
                              s-strs, c, *s, strs[2]);
      c = ++*++*s++; printf("#8 %d %c %s %s\n",
                              s-strs, c, *s, strs[3]);
      c = ++*++*++s; printf("#9 %d %c %s\n", s-strs,c,*s);
      c = ++**s++;   printf("#10 %d %c %s\n",s-strs,c,*s);
      p = *s; c = ++*(*s)++;
      printf("#11 %d %c %s %s %s\n",s-strs,c,*s,strs[6],p);
      c = ++*((*s)++); printf("#12 %d %c %s %s\n",
                                s-strs, c, *s, strs[6]);
      c = (*++(*s))++; printf("#13 %d %c %s %s\n",
                                s-strs, c, *s, strs[6]);
      for(s=strs; *s; s++)
          printf("strs[%d]=\"%s\"\n", s-strs, *s);
      putchar('\n');
    }

Печатается:

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

    #1 0 b bcd               strs[0]="bcd"
    #2 1 A ABCD              strs[1]="ABCD"
    #3 2 A 0fpx              strs[2]="px"
    #4 2 1 1fpx              strs[3]="69"
    #5 2 1 2fpx              strs[4]="hello"
    #6 2 g gpx               strs[5]="iop"
    #7 3 p 159 px            strs[6]="89"
    #8 4 6 hello 69
    #9 5 h hop
    #10 6 i A1479
    #11 6 B 1479 1479 B1479
    #12 6 2 479 479
    #13 6 7 89 89

Учтите, что конструкция

    char *strs[1] = { "hello" };

означает, что в strs[0] содержится указатель на начальный байт  безымянного  массива,
содержащего строку "hello".  Этот указатель можно изменять!  Попробуйте составить еще
подобные примеры из *, ++, ().

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

    char str[25] = "Hi, ";
    char *f(char **s){ int cnt;
      for(cnt=0; **s != '\0'; (*s)++, ++cnt);
      return("ny" + (cnt && (*s)[-1] == ' ') + (!cnt));
    }
    void main(void){ char *s = str;
      if( *f(&s) == 'y') strcat(s,  "dude");
      else               strcat(s, " dude");
      printf("%s\n", str);
    }

Что она напечатает, если задать

    char str[25]="Hi,";   или    char str[25]="";

2.41.  В чем состоит ошибка? (Любимая ошибка начинающих)

      main(){
         char *buf;     /* или char buf[]; */
         gets( buf );
         printf( "%s\n", buf );
      }

Ответ: память под строку buf не выделена, указатель buf не проинициализирован и смот-
рит неизвестно куда. Надо было писать например так:

    char buf[80];
            или
    char mem[80], *buf = mem;

Обратите на этот пример особое внимание, поскольку, описав указатель (но  никуда  его
не направив), новички успокаиваются, не заботясь о выделении памяти для хранения дан-
ных. Указатель должен указывать на ЧТО-ТО, в чем можно хранить данные, а не "висеть",
указывая "пальцем в небо"! Запись информации по "висячему" указателю разрушает память
программы и приводит к скорому (но часто  не  немедленному  и  потому  таинственному)
краху.

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

     Вот программа, которая  также  использует  неинициализированный  указатель.   На
машине  SPARCstation  20 эта программа убивается операционной системой с диагностикой
"Segmentation fault" (SIGSEGV).  Это как раз и значит обращение по указателю,  указы-
вающему "пальцем в небо".

    main(){
            int *iptr;
            int  ival  = *iptr;

            printf("%d\n", ival);
    }

2.42.  Для получения строки "Life is life" написана программа:

    main(){
        char buf[ 60 ];
        strcat( buf, "Life " );
        strcat( buf, "is "   );
        strcat( buf, "life"  );
        printf( "%s\n", buf );
    }

Что окажется в массиве buf?
Ответ: в начале массива окажется мусор, поскольку автоматический массив не  инициали-
зируется байтами '\0', а функция strcat() приписывает строки к концу строки. Для исп-
равления можно написать

            *buf = '\0';

перед   первым    strcat()-ом,    либо    вместо    первого    strcat()-а    написать
strcpy( buf, "Life " );

2.43.  Составьте макроопределение copystr(s1, s2) для копирования строки s2 в  строку
s1.

2.44.  Составьте макроопределение lenstr(s) для вычисления длины строки.
     Многие современные компиляторы сами обращаются с подобными короткими (1-3 опера-
тора)  стандартными функциями как с макросами, то есть при обращении к ним генерят не
вызов функции, а подставляют текст ее тела в место обращения.  Это  делает  объектный
код  несколько "толще", но зато быстрее. В расширенных диалектах Си и в Си++ компиля-
тору можно предложить обращаться так и с вашей функцией - для этого  функцию  следует
объявить как inline (такие функции называются еще "intrinsic").

2.45.  Составьте рекурсивную и нерекурсивную версии  программы  инвертирования  (зер-
кального отображения) строки:

            abcdef --> fedcba.

2.46.  Составьте функцию index(s, t), возвращающую номер первого вхождения символа  t
в строку s; если символ t в строку не входит, функция возвращает -1.
     Перепишите эту функцию с указателями, чтобы она возвращала указатель  на  первое
вхождение символа. Если символ в строке отсутствует - выдавать NULL.  В UNIX System-V
такая функция называется strchr.  Вот возможный ответ:

    char *strchr(s, c) register char *s, c;
    {    while(*s && *s != c) s++;
         return *s == c ? s : NULL;
    }

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

Заметьте, что p=strchr(s,'\0'); выдает указатель на конец строки.  Вот пример исполь-
зования:

    extern char *strchr();
    char *s = "abcd/efgh/ijklm";
    char *p = strchr(s, '/');
    printf("%s\n", p==NULL ? "буквы / нет" : p);
    if(p) printf("Индекс вхождения = s[%d]\n", p - s );

2.47.  Напишите  функцию  strrchr(),  указывающую  на  последнее  вхождение  символа.
Ответ:

    char *strrchr(s, c) register char *s, c;
    {     char *last = NULL;
          do if(*s == c) last = s; while(*s++);
          return last;
    }

Вот пример ее использования:

    extern char *strrchr();
    char p[] = "wsh";         /* эталон */
    main(argc, argv) char *argv[];{
        char *s = argv[1];    /* проверяемое имя */
        /* попробуйте вызывать
         * a.out csh
         * a.out /bin/csh
         * a.out wsh
         * a.out /usr/local/bin/wsh
         */
        char *base =
             (base = strrchr(s, '/')) ? base+1 : s;
        if( !strcmp(p, base))
             printf("Да, это %s\n" , p);
        else printf("Нет, это %s\n", base);

        /* еще более изощренный вариант: */
        if( !strcmp(p,(base=strrchr(s,'/')) ? ++base :
                                             (base=s))
          )  printf("Yes %s\n", p);
        else printf("No  %s\n", base);
    }

2.48.  Напишите макрос substr(to,from,n,len) который записывает  в  to  кусок  строки
from начиная с n-ой позиции и длиной len.  Используйте стандартную функцию strncpy.
Ответ:

    #define substr(to, from, n, len) strncpy(to, from+n, len)

или более корректная функция:

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

    char *substr(to, from, n, len) char *to, *from;
    {
       int lfrom = strlen(from);
       if(n < 0 ){ len += n; n = 0; }
       if(n >= lfrom || len <= 0)
            *to = '\0';  /* пустая строка */
       else{
            /* длина остатка строки: */
            if(len > lfrom-n) len = lfrom - n;
            strncpy(to, from+n, len);
            to[len] = '\0';
       }
       return to;
    }

2.49.  Напишите функцию, проверяющую, оканчивается ли строка на ".abc", и если нет  -
приписывающую  ".abc"  к концу.  Если же строка уже имеет такое окончание - ничего не
делать. Эта функция полезна для генерации имен файлов с  заданным  расширением.  Сде-
лайте расширение аргументом функции.
     Для сравнения конца строки s со строкой p следует использовать:

    int ls = strlen(s), lp = strlen(p);
    if(ls >= lp && !strcmp(s+ls-lp, p)) ...совпали...;

2.50.  Напишите функции вставки символа c в указанную позицию  строки  (с  раздвижкой
строки)  и  удаления  символа  в заданной позиции (со сдвижкой строки). Строка должна
изменяться "на месте", т.е. никуда не копируясь. Ответ:

    /* удаление */
    char delete(s, at) register char *s;
    {
            char c;
            s += at; if((c = *s) == '\0') return c;
            while( s[0] = s[1] ) s++;
            return c;
    }
    /* либо просто strcpy(s+at, s+at+1); */

    /* вставка */
    insert(s, at, c) char s[], c;
    {
            register char *p;
            s += at; p = s;
            while(*p) p++;  /* на конец строки */
            p[1] = '\0';    /* закрыть строку  */
            for( ; p != s; p-- )
                    p[0] = p[-1];
            *s = c;
    }

2.51.  Составьте программу удаления символа c из строки s в каждом случае,  когда  он
встречается.
Ответ:

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

    delc(s, c) register char *s; char c;
    {
       register char *p = s;
       while( *s )
         if( *s != c ) *p++ = *s++;
         else           s++;
       *p = '\0'; /* не забывайте закрывать строку ! */
    }

2.52.  Составьте программу удаления из строки  S1  каждого  символа,  совпадающего  с
каким-либо символом строки S2.

2.53.  Составьте функцию scopy(s,t), которая копирует строку s в t, при этом  символы
табуляции  и перевода строки должны заменяться на специальные двухсимвольные последо-
вательности "\n" и "\t".  Используйте switch.

2.54.  Составьте функцию, которая "укорачивает" строку, заменяя изображения  спецсим-
волов (вроде "\n") на сами эти символы ('\n').  Ответ:

    extern char *strchr();
    void unquote(s) char *s;
    {       static char from[] = "nrtfbae",
                        to  [] = "\n\r\t\f\b\7\33";
            char c, *p, *d;

            for(d=s; c = *s; s++)
                    if( c == '\\'){
                            if( !(c = *++s)) break;
                            p = strchr(from, c);
                            *d++ = p ? to[p - from] : c;
                     }else  *d++ = c;
            *d = '\0';
    }

2.55.  Напишите программу, заменяющую в строке S все вхождения подстроки P на  строку
Q, например:

         P = "ура"; Q = "ой";
         S = "ура-ура-ура!";
            Результат: "ой-ой-ой!"

2.56.  Кроме функций работы со строками (где предполагается, что массив байт заверша-
Предыдущая страница Следующая страница
1 ... 12 13 14 15 16 17 18  19 20 21 22 23 24 25 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама