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

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


    Прохождения игр    
Stoneshard |#6| Rotten Willow Tavern
Stoneshard |#5| Mannshire
Stoneshard |#4| Plot and Death
Stoneshard |#3| Northern Journey

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


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

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

Предыдущая страница Следующая страница
1 ... 26 27 28 29 30 31 32  33 34 35 36 37 38 39 ... 87
ванию каждого из полей):

    struct XYS s1, s2;  ...
    s2 = s1;

в отличие от массивов, которые присваивать целиком нельзя:

    int a[5], b[5];  a = b; /* ОШИБОЧНО ! */

Пример обращения к полям структуры:

    typedef struct _Point {
        short x, y; /* координаты точки */
        char *s;    /* метка точки      */
    } Point;
    Point p; Point *pptr; short *iptr;
    struct _Curve {
      Point points[25]; /* вершины ломанной */
      int color;        /* цвет линии       */
    } aLine[10], *linePtr = & aLine[0];
            ...
    pptr = &p; /* указатель на структуру p */
    p.x = 1; p.y = 2; p.s = "Grue";
    linePtr->points[2].x  = 54; aLine[5].points[0].y  = 17;

                   В ы р а ж е н и е                 значение
    ---------+------------+------------+-----------+-----------
    p.x      | pptr->x    | (*pptr).x  | (&p)->x   | 1
    ---------+------------+------------+-----------+-----------
                                          &p->x    | ошибка
    -----------+----------------+------------------+-----------
    iptr= &p.x | iptr= &pptr->x | iptr= &(pptr->x) | адрес поля
    -----------+----------------+--------+---------+-----------
    *pptr->s   | *(pptr->s)     | *p.s   |  p.s[0] | 'G'
    -----------+----------------+--------+---------+-----------
    pptr->s[1] | (&p)->s[1]     |  p.s[1]          | 'r'
    -----------+----------------+------------------+-----------
                  &p->s[1]                         | ошибка
    -----------+----------------+------------------+-----------
    (*pptr).s  | pptr->s        | p.s              | "Grue"
    -----------+----------------+------------------+-----------
    *pptr.s                                        | ошибка
    -----------------------------------------------+-----------

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

            Вообще (&p)->field   =  p.field
                   pptr->field   =  (*pptr).field

     Объединения - это агрегаты данных, которые могут хранить в себе значения  данных
разных типов на одном и том же месте.

            struct a{ int x, y; char *s; } A;
            union  b{ int i; char *s; struct a aa; } B;

            Структура:
       ________________________
    A: | A.x         int      |   Три поля
       ------------------------   расположены подряд.
       | A.y         int      |   Получается как бы
       ------------------------   "карточка" с графами.
       | A.s         char *   |
       ------------------------

    А у объединений поля расположены "параллельно",
    на одном месте в памяти.
       _______________________________________________________
    B: | B.i  int | B.s  char *  | B.aa     : B.aa.x  int    |
       -----------|              | struct a : B.aa.y  int    |
                  ---------------|          : B.aa.s  char * |
                                 |___________________________|

Это как бы "ящик" в который можно поместить значение любого типа из перечисленных, но
не  ВСЕ  ВМЕСТЕ ("и то и это", как у структур), а ПО ОЧЕРЕДИ ("или/или").  Размер его
достаточно велик, чтоб вместить самый большой из перечисленных типов данных.
     Мы можем занести в union значение и интерпретировать его как другой тип данных -
это  иногда используется в машинно-зависимых программах. Вот пример, выясняющий поря-
док байтов в short числах:

     union lb {
            char s[2]; short i;
     } x;
     unsigned hi, lo;
     x.i = (02 << 8) | 01;
     hi = x.s[1]; lo = x.s[0];
     printf( "%d %d\n", hi, lo);

или так:

    #include 
    union {
            int i;
            unsigned char s[sizeof(int)];
    } u;
    void main(){
            unsigned char *p;
            int n;

            u.i = 0x12345678;
            for(n=0, p=u.s; n < sizeof(int); n++, p++){
                    printf("%02X ", *p);
            }
            putchar('\n');
    }

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

или порядок слов в long числах:

    union xx {
      long l;
      struct ab {
        short a;  /* low word  */
        short b;  /* high word */
      } ab;
    } c;
    main(){ /* На IBM PC 80386 печатает 00020001 */
      c.ab.a = 1; c.ab.b = 2; printf("%08lx\n", c.l );
    }

5.1.  Найдите ошибки в описании структурного шаблона:

            structure { int arr[12],
                        char string,
                        int *sum
                      }

5.2.  Разработайте структурный шаблон, который содержал бы название месяца,  трехбук-
венную  аббревиатуру месяца, количество дней в месяце и номер месяца. Инициализируйте
его для невисокосного года.

      struct month {
             char name[10];  /* или char *name; */
             char abbrev[4]; /* или char *abbrev; */
             int  days;
             int  num;
      };

      struct month months[12] = {           /* индекс */
             {"Январь" , "Янв", 31, 1 },    /*  0     */
             {"Февраль", "Фев", 28, 2 },    /*  1     */
                    ...
             {"Декабрь", "Дек", 31, 12},    /* 11     */
      }, *mptr = & months[0];  /* или *mptr = months */

      main(){
            struct month *mptr;
            printf( "%s\n", mptr[1].name );
            printf( "%s %d\n", mptr->name, mptr->num );
      }

Напишите функцию, сохраняющую массив months  в  файл;  функцию,  считывающую  его  из
файла. Используйте fprintf и fscanf.
     В чем будет разница в функции чтения, когда поле name описано как  char name[10]
и как char *name?
     Ответ: во втором случае для сохранения прочитанной строки надо заказывать память
динамически  при  помощи  malloc() и сохранять в ней строку при помощи strcpy(), т.к.
память для хранения самой строки в структуре не зарезервирована (а только для  указа-
теля на нее).
     Найдите ошибку в операторах функции main().  Почему печатается не  "Февраль",  а
какой-то мусор? Указание: куда указывает указатель mptr, описанный в main()? Ответ: в
"неизвестно куда" - это локальная переменная (причем не получившая начального  значе-
ния  - в ней содержится мусор), а не то же самое, что указатель mptr, описанный выше!
Уберите описание mptr из main.

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

     Заметим, что для распечатки всех или нескольких  полей  структуры  следует  ЯВНО
перечислить  в printf() все нужные поля и указать форматы, соответствующие типам этих
полей. Не существует формата или стандартной  функции,  позволяющей  распечатать  все
поля сразу (однако такая функция может быть написана вами для конкретного типа струк-
тур).  Также не существует формата для scanf(), который вводил бы структуру  целиком.
Вводить можно только по частям - каждое поле отдельно.

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

5.4.  Переделайте предыдущую программу таким образом, чтобы она по  написанному  бук-
вами названию месяца возвращала общее число дней года вплоть до этого месяца. В прог-
рамме используйте функцию strcmp().

5.5.  Переделайте предыдущую программу таким образом, чтобы она запрашивала у пользо-
вателя  день,  месяц,  год  и выдавала общее количество дней в году вплоть до данного
дня. Месяц может обозначаться номером, названием месяца или его аббревиатурой.

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

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

    struct man {
            char name[20];
            int salary;
    } workers[] = {
            { "Иванов",  200 },
            { "Петров",  180 },
            { "Сидоров", 150 }
    }, *wptr, chief = { "начальник", 550 };

    main(){
       struct man *ptr, *cptr, save;

       ptr = wptr = workers + 1;
       cptr = &chief;
       save = workers[2]; workers[2] = *wptr; *wptr = save;
       wptr++; ptr--; ptr->salary = save.salary;

       printf( "%c %s %s %s %s\n%d %d %d %d\n%d %d %c\n",
         *workers[1].name, workers[2].name, cptr->name,
           ptr[1].name, save.name,
             wptr->salary, chief.salary,
               (*ptr).salary, workers->salary,
         wptr - ptr, wptr - workers, *ptr->name );
    }

Ответ:

    С Петров начальник Сидоров Сидоров
    180 550 150 150
    2 2 И

5.8.  Разберите следующий пример:

    #include 
    struct man{

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

            char *name, town[4]; int salary;
            int addr[2];
    } men[] = {
            { "Вася",  "Msc",     100,  { 12,  7 } },
            { "Гриша", "Len",     120,  { 6,  51 } },
            { "Петя",  "Rig",     140,  { 23, 84 } },
            { NULL,    ""   ,      -1,  { -1, -1 } }
    };
    main(){
       struct man *ptr, **ptrptr;
       int i;

       ptrptr = &ptr;
       *ptrptr = &men[1];     /* men+1 */

       printf( "%s    %d    %s   %d   %c\n",
                ptr->name,
                      ptr->salary,
                            ptr->town,
                                 ptr->addr[1],
                                      ptr[1].town[2] );

       (*ptrptr)++;

       /* копируем *ptr в men[0] */
       men[0].name    = ptr->name;       /* (char *) #1 */
       strcpy( men[0].town, ptr->town ); /* char []  #2 */
       men[0].salary  =     ptr->salary; /* int      #3 */
       for( i=0; i < 2; i++ )
           men[0].addr[i] = ptr->addr[i];  /* массив #4 */

       /* распечатываем массив структур */
       for(ptr=men; ptr->name; ptr++ )
           printf( "%s %s %d\n",
                    ptr->name, ptr->town, ptr->addr[0]);
    }

Обратите внимание на такие моменты:
1)   Как производится работа с указателем на указатель (ptrptr).
2)   При копировании структур отдельными полями, поля  скалярных  типов  (int,  char,
     long,  ..., указатели) копируются операцией присваивания (см. строки с пометками
     #1 и #3). Поля векторных типов (массивы) копируются  при  помощи  цикла,  поэле-
     ментно  пересылающего  массив  (строка  #4).  Строки (массивы букв) пересылаются
     стандартной функцией strcpy (строка #2). Все это относится  не  только  к  полям
     структур,  но и к переменным таких типов. Структуры можно также копировать не по
     полям, а целиком: men[0]= *ptr;
3)   Запись аргументов функции printf() лесенкой позволяет лучше видеть, какому  фор-
     мату соответствует каждый аргумент.
4)   При распечатке массива структур мы печатаем не определенное их количество  (рав-
     ное  размеру массива), а пользуемся указателем NULL в поле name последней струк-
     туры как признаком конца массива.
5)   В поле town мы храним строки из 3х букв, однако выделяем для хранения массив  из
     4х  байт. Это необходимо потому, что строка "Msc" состоит не из 3х, а из 4х бай-
     тов: 'M','s','c','\0'.
При работе со структурами и указателями большую помощь могут оказать рисунки. Вот как
(например) можно нарисовать данные из этого примера (массив men изображен не весь):

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

            --ptr--       --ptrptr--
        ptr |  *  |<------|---*    |
            ---|---       ----------
               |
              /    =========men[0]==
             / men:|name  |    *---|-----> "Вася"
             |     |---------------|
             |     |town  |M|s|c|\0|
             |     |---------------|
             |     |salary| 100    |
             |     |---------------|
             |     |addr  | 12 | 7 |
             \     -----------------
Предыдущая страница Следующая страница
1 ... 26 27 28 29 30 31 32  33 34 35 36 37 38 39 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама