Страницы

четверг, 18 декабря 2014 г.

Структуры в Си

Структура - это переменная, которая содержит в себе набор других переменных, которые могут быть разных типов.
Пример:
struct
{
  char sym;
  int num;
}myvar;
Тут определена переменная myvar, которая представляет собой структуру. Доступ к элементам структуры осуществляется через точку:
myvar.sym = 4;
myvar.num = 40;
Если имеется указатель на структуру, то доступ к элементам с помощью указателя происходит через стрелку. Для этого нужно создать тип нашей структуры с помощью typedef, и объявить указатель с типом нашей структуры:
typedef struct
{
  char sym;
  int num;
}tMyStruct;
tMyStruct myvar;
tMyStruct* p;
...
p = &myvar;
p->sym = 5;
p->num = 500;

С помощью структур можно применять битовые поля, которые упаковываются в число, при этом память экономится. Компилятор IAR для AVR определяет минимальный объем памяти, который выделяется под структуру, в 2 байта, даже если количество бит в структуре меньше или равно 8 (для 8 бит было бы достаточно одного байта). Далее, когда объем бит превышает 16, выделяется уже 4 байта, и т. д. - объем выделяемой для битовой структуры памяти почему-то всегда кратен 2 байтам. Примеры битовых структур:
typedef struct
{
  unsigned A : 1;
  unsigned B : 1;
} t2;

typedef struct
{
  unsigned A : 1;
  unsigned B : 1;
  unsigned C : 1;
  unsigned D : 1;
} t4;

typedef struct
{
  unsigned A : 1;
  unsigned B : 1;
  unsigned C : 1;
  unsigned D : 1;
  unsigned E : 1;
  unsigned F : 1;
  unsigned G : 1;
  unsigned H : 1;
} t8;

typedef struct
{
  unsigned A : 1;
  unsigned B : 1;
  unsigned C : 1;
  unsigned D : 1;
  unsigned E : 1;
  unsigned F : 1;
  unsigned G : 1;
  unsigned H : 1;
  unsigned Y : 1;
} t9;

typedef struct
{
  unsigned A : 1;
  unsigned B : 1;
  unsigned C : 1;
  unsigned D : 1;
  unsigned E : 1;
  unsigned F : 1;
  unsigned G : 1;
  unsigned H : 1;
  unsigned Y : 8;
} t16;

typedef struct
{
  unsigned A : 1;
  unsigned B : 1;
  unsigned C : 1;
  unsigned D : 1;
  unsigned E : 1;
  unsigned F : 1;
  unsigned G : 1;
  unsigned H : 1;
  unsigned Y : 9;
} t17;

t2 _A2;    //выделяется 2 байта, хотя достаточно одного
t4 _A4;    //выделяется 2 байта, хотя достаточно одного
t8 _A8;    //выделяется 2 байта, хотя достаточно одного
t9 _A9;    //выделяется 2 байта
t16 _A16; //выделяется 2 байта
t17 _A17; //выделяется 4 байта, хотя достаточно 3-х
Очень интересен тип данных union, который позволяет один выделенный блок памяти интерпретировать по-разному, что позволяет удобно манипулировать данными и одновременно экономить память. Например, 
union
{
  uint i;
  t9  bf;
}myunion;
Переменная myunion может выступать либо как целое myunion.i, либо как структура myunion.bf типа t9 (см. ранее определение типа t9), то есть набор битов myunion.bf.A, myunion.bf.B и т. д., что позволяет, например, менять переменную myunion.i, манипулируя битами myunion.bf. Младший D0 бит i будет всегда равен myunion.bf.A, D1 будет равен myunion.bf.B, и т. д.


a->b == (*a).b



Создание новых типов

Тип переменной определяет: её размер в памяти, тип данных, которые она может хранить и операции, которые можно производить с этой переменной.
Тип данных является категорией. В языке С++ программист может создать любой тип данных на основе базовых типов.  Новые типы данных необходимо создавать для решения конкретных практических задач. Например: реализация работы деканата.
Успех программы часто зависит от удачного выбора способа представления данных. С помощью структур возможно моделировать сложные объекты, возникающие  при  решении  задач.  Структуры представляют средство для доступа к записям, которые содержат поля одного или нескольких типов.
Для использования структуры необходимо:
1. установить шаблон для структуры
2. объявить переменную, соответствующую этому шаблону
3. осуществить доступ к компонентам структуры.

Шаблон структуры

Шаблон - это схема, описывающая содержание структуры. Установка структурного шаблона телефонный справочник:
struct sprav {
                    char fio[20];
                    long num;
                  };
Данный шаблон описывает структуру с именем  типа  структуры sprav, состоящую из двух компонентов: строки fio и целой переменной num типа long. Имя типа структуры sprav необязательно и  используется  для ссылки на эту структуру. Компоненты структуры - данные любого типа, включая и другие структуры. Имя внутри структуры может быть  таким  же,  как  имя объекта вне структуры. Если шаблон описан внутри функции - он доступен только  этой функции, если шаблон описан вне функции - он  доступен любой функции программы. Установка шаблона не вызывает никаких действий в программе.

Структурные переменные

     Объявление структурных переменных приводит  к  выделению памяти для компонент структуры, куда можно записать данные или откуда можно прочитать их. Для объявления структурных переменных имеются несколько  способов.
1. Установить структурный шаблон:
     struct sprav {
                    char fio[20];
                    long num;
                  };
Объявить простую переменную, массив структур, указатель на структуру:      struct sprav tel1, tel2[5], *tel3;
2. Установить структурный шаблон с помощью  макроопределения:
     #define SPRAV struct sprav
     SPRAV {
             char fio[20];
             long num;
           };
Объявить переменные:
     SPRAV sp1, sp2[6], *sp3;
3. Объявить переменные одновременно с установкой шаблона (если на данную структуру вы больше не ссылаетесь):
     struct {
              char fio[20];
              long num;
            } tel1, tel2[3], *tel3;
4. Ввести новый тип данных (TEL)-структура определенного вида:
     typedef struct {
                      char fio[20];
                      long num;
                    } TEL;
Объявить переменные нового типа:
     TEL tel1, tel2[6], *tel3;
Если программа достаточно объемна, представляется более удобным четвертый способ.

Инициализация структуры               

Инициализировать можно только внешние или статические структуры.
     static struct {
                     char fio[20];
                     long num;
                   } tel[2]={
                              "Иванов Ф.А.", 456756,
                              "Петров В.П.", 632345
                            };

Доступ к компонентам структуры

Доступ к компонентам структуры продемонстрируем с помощью примеров.
Пример 1.
/* Обращение к элементам структуры через имя переменной */
#include <stdio.h>
#include <conio.h>
 void main(void)
{
   struct{
             char fio[20];  /* фамилия */
             long num;      /* телефон */
         } tel1, tel2;
   clrscr();
   puts("введите фио абонента-");
   gets(tel1.fio);
   puts("введите его номер-");
   scanf("%ld",&tel1.num);
   tel2=tel1;  /* нельзя так же сравнивать структуры */
   puts("Введено:");
   printf("Фамилия :%s   номер: %ld\n",tel2.fio,tel2.num);
}

Пример 2.
/* Динамическое выделение памяти для структуры */
/* Обращение к элементам структуры через указатель */
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
  struct sprav {
                 char fio[20];
                 long num;
               };
 void main(void)
{
  struct sprav *tel1, *tel2;
  clrscr();
/* Выделение памяти для структуры */
   tel1=(struct sprav *)malloc(sizeof(struct sprav));
   tel2=(struct sprav *)malloc(sizeof(struct sprav));
   puts("введите фио абонента-");
   gets(tel1->fio);
   puts("введите его номер-");
   scanf("%ld",&tel1->num);
   *tel2= *tel1;
   puts("Введено:");
   printf("Фамилия :%s   номер: %ld\n",(*tel2).fio,(*tel2).num);
}

  Массив структур

Пример 3.
/* Массив структур. Обращение к элементам структуры через */
/* имя элемента массива */
#include <stdio.h>
#include <conio.h>
#include <string.h>
#define SPRAV struct sprav
void main(void)
{
 SPRAV{
        char fio[20];
        long num;
      };
 SPRAV tel[5];    /* массив структур - 5 элементов */
 char fio_tek[20];
 int i;
 clrscr();
/* ввод данных в массив структур */
   for(i=0; i<5; i++)  
   {
        puts("введите фио абонента-");
        gets(tel[i].fio);
        puts("введите его номер-");
        scanf("%ld",&tel[i].num);
        getchar();
   }
   puts("Выбор телефона по фамилии");
   gets(fio_tek);
/* поиск структуры по фамилии абонента */
   for(i=0; i<5; i++)
        if(!strcmp(fio_tek,tel[i].fio)) break;
   if(i!=5)    /* цикл закончен по break */
        printf("номер абонента %s равен %ld\n",fio_tek, \
                                  tel[i].num);
   else        /* цикл выполнился полностью */
        puts("Абонент не найден");
 }

Пример 4.
/* Массив структур. Память выделяется динамически. */
/* Обращение к элементам структуры через указатель */
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <alloc.h>
typedef struct{
                char fio[20];
                long num;
              } TEL;
 void main(void)
{
 TEL *tel;
 char fio_tek[20];
 int i;
 clrscr();
/* Выделение памяти для массива - 3 элемента */
 tel=(TEL *)malloc(sizeof(TEL)*3);
   for(i=0; i<3; i++)
   {
        puts("введите фио абонента-");
        gets((tel+i)->fio);
        puts("введите его номер-");
        scanf("%ld",&(tel+i)->num);
        getchar();
   }
   puts("Выбор телефона по фамилии");
   gets(fio_tek);
   for(i=0; i<5; i++,tel++)
        if(!strcmp(fio_tek,tel->fio)) break;
   if(i!=5)
        printf("номер абонента %s равен %ld\n",fio_tek, \
                              tel->num);
   else
        puts("Абонент не найден");
 }

Передача структуры в функцию

Непосредственный доступ к компонентам структуры - плохой стиль программирования. Все операции, которые разрешены применительно к структуре, должны быть при этом реализованы в виде отдельных функций. Не все компиляторы языка Си позволяют передавать структуры  в функцию по значению, поэтому в примерах передача структуры идет через указатель.
Пример 5.
/* Передача структуры в функцию через указатель на структуру */
/* Определение комплексного числа через структуру и действия */
/* над комплексными числами ( ввод, вывод, вычисление суммы) */
#include <stdio.h>
typedef struct { float a;   /* действительная часть */
                 float b;   /* мнимая часть */
               } COMPLEX;
void vvod(COMPLEX *,float,float);     
void sum(COMPLEX *,COMPLEX *,COMPLEX *);
void out(COMPLEX *);
void main(void)
{
   COMPLEX x,y,z;
   vvod(&x,2.5,6.7);
   vvod(&y,6.89,8.45);
   puts("Введены числа:");
   out(&x);
   out(&y);
   sum(&x,&y,&z);
   puts("Сумма комплексных чисел равна:");
   out(&z);
}
/* Вывод комплексного числа */
void out( COMPLEX *p)
{
   printf("(%.2f,%.2f)\n", (*p).a,(*p).b);
   return;
}
/* Вычисление суммы двух комплексных чисел */
void sum(COMPLEX *p1,COMPLEX *p2,COMPLEX *p3)
{
   (*p3).a=(*p1).a+(*p2).a;
   (*p3).b=(*p1).b+(*p2).b;
   return;
}
/* Ввод значений для элементов структуры */
void vvod(COMPLEX *p,float a, float b)
{
   p->a=a;
   p->b=b;
   return;
}

Вложенные структуры 

     Структура, являющаяся компонентом другой структуры, называется вложенной.
Пример 6.
/* Даны четыре точки - центры четырех окружностей.    Заполнить структуру окружность, если все окружности    проходят через начало координат.    */
#include<conio.h>
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
struct POINT {
                float x;
                float y;
              };
struct CIRCLE {
            struct POINT point;  /* вложенная структура */
            double r;
          } circle[2], *p;
void main (void)
{
  int i,j; 
  float a,b,c,d;
  clrscr();
  gotoxy(17,1);
  cputs("ВВЕДИТЕ КООРДИНАТЫ ТОЧЕК :\r\n");
  for(i=0;i<2;i++) 
  { 
      cprintf ("\n\n ВВЕДИТЕ X: ");
      cprintf ("X[%d]= ",i+1);
      cscanf("%f",&circle[i].point.x);
      cprintf ("\n ВВЕДИТЕ Y: ");
      cprintf ("Y[%d]= ",i+1);
      cscanf ("%f",&circle[i].point.y);
  }
  p=circle;
  gotoxy(17,12);
  cputs("РЕЗУЛЬТАТ:\r\n\n");
  for(i=0;i<2;i++)
  {
     a=p->point.x;
     b=p->point.y;
     c=sqrt(a*a+b*b);
     p->r=c;
     cprintf("\nРАДИУС : %lf ЦЕНТР (%f,%f)\r\n",p->r,a,b);
     p++;
  }

Комментариев нет:

Отправить комментарий

ваше мнение...