Структуры. Инициализация структуры в си (c struct)

Тип переменной определяет: её размер в памяти, тип данных, которые она может хранить и операции, которые можно производить с этой переменной.

Тип данных является категорией. В языке С++ программист может создать любой тип данных на основе базовых типов. Новые типы данных необходимо создавать для решения конкретных практических задач. Например: реализация работы деканата.

Успех программы часто зависит от удачного выбора способа представления данных. С помощью структур возможно моделировать сложные объекты, возникающие при решении задач. Структуры представляют средство для доступа к записям, которые содержат поля одного или нескольких типов.

Для использования структуры необходимо:
1. установить шаблон для структуры
2. объявить переменную, соответствующую этому шаблону
3. осуществить доступ к компонентам структуры.

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

Шаблон - это схема, описывающая содержание структуры. Установка структурного шаблона телефонный справочник:

struct sprav {
char fio;
long num;
};

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

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

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

1. Установить структурный шаблон:

struct sprav {
char fio;
long num;
};

Объявить простую переменную, массив структур, указатель на структуру: struct sprav tel1, tel2, *tel3;

2. Установить структурный шаблон с помощью макроопределения:

#define SPRAV struct sprav
SPRAV {
char fio;
long num;
};

Объявить переменные:

SPRAV sp1, sp2, *sp3;

3. Объявить переменные одновременно с установкой шаблона (если на данную структуру вы больше не ссылаетесь):

struct {
char fio;
long num;
} tel1, tel2, *tel3;

4. Ввести новый тип данных (TEL)-структура определенного вида:

typedef struct {
char fio;
long num;
} TEL;

Объявить переменные нового типа:

TEL tel1, tel2, *tel3;

Если программа достаточно объемна, представляется более удобным четвертый способ.

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

Инициализировать можно только внешние или статические структуры.

static struct {
char fio;
long num;
} tel={
"Иванов Ф.А.", 456756,
"Петров В.П.", 632345
};

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

Доступ к компонентам структуры продемонстрируем с помощью примеров.

/* Обращение к элементам структуры через имя переменной */
#include
#include
void main(void)
{
struct{
char fio; /* фамилия */
long num; /* телефон */
} tel1, tel2;

puts("введите фио абонента-");
gets(tel1.fio);
puts("введите его номер-");
scanf("%ld",&tel1.num);
tel2=tel1; /* нельзя так же сравнивать структуры */
puts("Введено:");
printf("Фамилия:%s номер: %ld\n",tel2.fio,tel2.num);
}

/* Динамическое выделение памяти для структуры */

#include
#include
#include
struct sprav {
char fio;
long num;
};

void main(void)
{
struct sprav *tel1, *tel2;

clrscr();
/* Выделение памяти для структуры */
tel1=(struct sprav *)malloc(sizeof(struct sprav));
tel2=(struct sprav *)malloc(sizeof(struct sprav));

gets(tel1->fio);
puts("введите его номер-");
scanf("%ld",&tel1->num);
*tel2= *tel1;
puts("Введено:");
printf("Фамилия:%s номер: %ld\n",(*tel2).fio,(*tel2).num);
}

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

/* Массив структур. Обращение к элементам структуры через */
/* имя элемента массива */
#include
#include
#include
#define SPRAV struct sprav

void main(void)
{
SPRAV{
char fio;
long num;
};

SPRAV tel; /* массив структур - 5 элементов */
char fio_tek;
int i;

clrscr();
/* ввод данных в массив структур */
for(i=0; i<5; i++)
{
puts("введите фио абонента-");
gets(tel[i].fio);
puts("введите его номер-");
scanf("%ld",&tel[i].num);
getchar();
}

gets(fio_tek);
/* поиск структуры по фамилии абонента */
for(i=0; i<5; i++)
if(!strcmp(fio_tek,tel[i].fio)) break;
if(i!=5) /* цикл закончен по break */

tel[i].num);
else /* цикл выполнился полностью */
puts("Абонент не найден");
}

/* Массив структур. Память выделяется динамически. */
/* Обращение к элементам структуры через указатель */
#include
#include
#include
#include

typedef struct{
char fio;
long num;
} TEL;

void main(void)
{
TEL *tel;
char fio_tek;
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("Абонент не найден");
}

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

Непосредственный доступ к компонентам структуры - плохой стиль программирования. Все операции, которые разрешены применительно к структуре, должны быть при этом реализованы в виде отдельных функций. Не все компиляторы языка Си позволяют передавать структуры в функцию по значению, поэтому в примерах передача структуры идет через указатель.

/* Передача структуры в функцию через указатель на структуру */
/* Определение комплексного числа через структуру и действия */
/* над комплексными числами (ввод, вывод, вычисление суммы) */

#include
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;
}

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

Структура, являющаяся компонентом другой структуры, называется вложенной.

/* Даны четыре точки - центры четырех окружностей. Заполнить структуру окружность, если все окружности проходят через начало координат. */

#include
#include
#include
#include
struct POINT {
float x;
float y;
};
struct CIRCLE {
struct POINT point; /* вложенная структура */
double r;
} circle, *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++;
}

Последнее обновление: 02.10.2018

Наряду с классами структуры представляют еще один способ создания обственных типов данных в C#. Более того многие примитивные типы, например, int, double и т.д., по сути являются структурами.

Например, определим структуру, которая представляет человека:

Struct User { public string name; public int age; public void DisplayInfo() { Console.WriteLine($"Name: {name} Age: {age}"); } }

Как и классы, структуры могут хранить состояние в виде переменных и определять поведение в виде методов. Так, в данном случае определены две переменные - name и age для хранения соответственно имени и возраста человека и метод DisplayInfo для вывода информации о человеке.

Используем эту структуру в программе:

Using System; namespace HelloApp { struct User { public string name; public int age; public void DisplayInfo() { Console.WriteLine($"Name: {name} Age: {age}"); } } class Program { static void Main(string args) { User tom; tom.name = "Tom"; tom.age = 34; tom.DisplayInfo(); Console.ReadKey(); } } }

В данном случае создается объект tom. У него устанавливаются значения глобальных переменных, и затем выводится информация о нем.

Конструкторы структуры

Как и класс, структура может определять констукторы. Но в отличие от класса нам не обязательно вызывать конструктор для создания объекта структуры:

User tom;

Однако если мы таким образом создаем объект структуры, то обязательно надо проинициализировать все поля (глобальные переменные) структуры перед получением их значений или перед вызовом методов структуры. То есть, например, в следующем случае мы получим ошибку, так как обращение к полям и методам происходит до присвоения им начальных значений:

User tom; int x = tom.age; // Ошибка tom.DisplayInfo(); // Ошибка

Также мы можем использовать для создания структуры конструктор по умолчанию, при вызове которого полям структуры будет присвоено значение по умолчанию (например, для числовых типов это число 0):

User tom = new User(); tom.DisplayInfo(); // Name: Age: 0

Также мы можем определить свои конструкторы. Например, изменим структуру User:

Using System; using System.Reflection; namespace HelloApp { struct User { public string name; public int age; public User(string name, int age) { this.name = name; this.age = age; } public void DisplayInfo() { Console.WriteLine($"Name: {name} Age: {age}"); } } class Program { static void Main(string args) { User tom = new User("Tom", 34); tom.DisplayInfo(); User bob = new User(); bob.DisplayInfo(); Console.ReadKey(); } } }

Важно учитывать, что если мы определяем конструктор в структуре, то он должен инициализировать все поля структуры, как в данном случае устанавливаются значения для переменных name и age.

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

User person = new User { name = "Sam", age = 31 };

Но в отличие от класса нельзя инициализировать поля структуры напрямую при их объявлении, например, следующим образом:

Struct User { public string name = "Sam"; // ! Ошибка public int age = 23; // ! Ошибка public void DisplayInfo() { Console.WriteLine($"Name: {name} Age: {age}"); } }

Структуры в си (c) - это объединенные данные, у которых есть некоторая логическая взаимосвязь. В отличие от массивов, структуры могут содержать данные разных типов. Вот пару примеров структур в си (c): структура класс (имя учащегося, буква класса, средний балл); структура футбольная команда (тренер, название команды, место в турнирной таблице). Т.е. структуру вы будете использовать довольно часто. Теперь давайте рассмотрим, как описываются структуры в си:

struct klass {
char name;
char klass_name;
float bal;
};

struct

Любая структура в языке си (c) должна начинаться с ключевого слова - struct , которое сообщает компилятору, что тут у нас будет структура. Все данные в структуре (struct) пишутся в фигурных скобках, и в конце ставится запятая с точкой (;). Советую сразу ставить запятую с точкой, что бы не было ошибок.

Как вы видите, в структуре (struct) у нас находятся данные различных типов, но они объединены в логическую связь, так как в моем примере они являются определенным школьным классом. Данные в структуре должны иметь уникальные имена, но в различных структурах можно использовать одинаковые названия.

Структура, которая создана выше не занимает в памяти компьютера места, так как мы, на самом деле, просто создали свой тип данных. Объявление структуры ни чем не отличается от объявления любого типа данных в языке си (c). Вот пример:

struct klass a, b, *c;

Мы объявили переменную а типа struct klass, массив b, состоящий из 5 элементов типа struct klass и указатель на переменную struct klass.

Так же можно объявлять переменные сразу после объявления структуры:

struct klass {
char name;
char klass_name;
float bal;
} a, b, *c;

А какие же операции можно проделывать со структурами? Ответ на этот вопрос лучше перечислить по пунктам:

  1. присваивание полю структуры значение того же типа
  2. можно получить адрес структуры. Не забываем операцию взятия адреса (&)
  3. можно обращаться к любому полю структуры
  4. для того, что бы определить размер структуры можно использовать операцию sizeof()

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

Инициализация структуры в языке си (c) происходит так же, как и при инициализации массива. Вот пример инициализации структуры:

struct klass a = {"Sergey", "B", 4.5 };

Т.е. мы создаем переменную типа struct klass и присваиваем всем трем полям, которые у нас определенны в структуре, значения. Порядок очень важен при инициализации структуры , так как компьютер сам не может отсортировывать данные. Если какое-либо поле у вас будет не заполненным, то оно автоматом заполнится 0 - для целочисленных типов; NULL - для указателей; \0 (ноль-терминатор) - для строковых типов.

А теперь только представьте — вы сами можете создавать, своего рода, типы данных, которые вам необходимы и с которыми вам будет удобно работать! И это несложно!

Структура — это, некое объединение различных переменных (даже с разными типами данных), которому можно присвоить имя. Например можно объединить данные об объекте Дом: город (в котором дом находится), улица, количество квартир, интернет(проведен или нет) и т.д. в одной структуре. В общем, можно собрать в одну совокупность данные обо всем, что угодно, точнее обо всем, что необходимо конкретному программисту. Всем сразу стало понятно:)

Если вы только приступаете к знакомству со структурами в С++, сначала, вам необходимо ознакомиться с синтаксисом структур в языке С++ . Рассмотрим простой пример, который поможет познакомиться со структурами и покажет, как с ними работать. В этой программе мы создадим структуру, создадим объект структуры, заполним значениями элементы структуры (данные об объекте) и выведем эти значения на экран. Ну что же, приступим!

#include using namespace std; struct building //Создаем структуру! { char *owner; //здесь будет храниться имя владельца char *city; //название города int amountRooms; //количество комнат float price; //цена }; int main() { setlocale (LC_ALL, "rus"); building apartment1; //это объект структуры с типом данных, именем структуры, building apartment1.owner = "Денис"; //заполняем данные о владельце и т.д. apartment1.city = "Симферополь"; apartment1.amountRooms = 5; apartment1.price = 150000; cout << "Владелец квартиры: " << apartment1.owner << endl; cout << "Квартира находится в городе: " << apartment1.city << endl; cout << "Количество комнат: " << apartment1.amountRooms << endl; cout << "Стоимость: " << apartment1.price << " $" << endl; return 0; }

В строках 4 — 10 мы создаем структуру. Чтобы ее объявить используем зарезервированное слово struct и даем ей любое, желательно логичное, имя. В нашем случае — building . С правилами именования переменных, вы можете ознакомиться в этой статье . Далее открываем фигурную скобку { , перечисляем 4 элемента структуры через точку с запятой; , закрываем фигурную скобку } и в завершении ставим точку с запятой; . Это будет нашим шаблоном (формой) структуры.

В строке 16 объявляем объект структуры. Как и для обычных переменных, необходимо объявить тип данных. В этом качестве выступит имя нашей созданной структуры — building .

Как же заполнить данными (инициализировать) элементы структуры? Синтаксис таков: Имя объекта далее оператор точка. и имя элемента структуры. Например: apartment1.owner . Таким образом, в строках 18-21 присваиваем данные элементам структуры.

И так, данные мы внесли. Следующий вопрос: «Как к ним обратиться, как работать и использовать их в программе?» Ответ — «Очень просто — так же, как и при инициализации, используя точку. и имя элемента структуры». В строках 23 — 26 выводим заполненные элементы структуры на экран.

И вот что мы увидим в результате, когда скомпилируем нашу программу:

Владелец квартиры: Денис Квартира находится в городе: Симферополь Количество комнат: 5 Стоимость: 150000 $

Что ещё важно знать:

  • Объект структуры можно объявить до функции main() . Это выглядело бы так:
struct building { char *owner char *city; int amountRooms; float price; }apartment1; //объявление объекта типа building
  • Инициализировать структуру можно и таким способом:
building apartment1 = {"Денис", "Симферополь", 5, 150000};

но так делают крайне редко;

  • Структуру можно вкладывать в другие структуры (это мы рассмотрим в следующем примере).

Дополним предыдущий пример, чтобы увидеть дополнительные возможности работы со структурами.

Пример:

#include using namespace std; struct date //создаем еще одну структуру, чтобы вложить ее в структуру building // дата постройки { char *month; // Месяц постройки дома int year; // Год }; struct building { char *owner; char *city; int amountRooms; float price; date built; //вкладываем одну структуру в определение второй }; void show(building object) //создаем функцию, которая принимает структуру, как параметр { cout << "Владелец квартиры: " << object.owner << endl; cout << "Квартира находится в городе: " << object.city << endl; cout << "Количество комнат: " << object.amountRooms << endl; cout << "Стоимость: " << object.price << " $" << endl; cout << "Дата постройки: " << object.built.month << " " << object.built.year << endl; } int main() { setlocale (LC_ALL, "rus"); building apartment1; apartment1.owner = "Денис"; apartment1.city = "Симферополь"; apartment1.amountRooms = 5; apartment1.price = 150000; apartment1.built.month = "январь"; apartment1.built.year = 2013; struct building *pApartment; //это указатель на структуру pApartment = &apartment1; //Обратите внимание, как нужно обращаться к элементу структуры через указатель //используем оператор -> cout << "Владелец квартиры: " << pApartment->owner << endl; cout << "Квартира находится в городе: " << pApartment->city << endl; cout << "Количество комнат: " << pApartment->amountRooms << endl; cout << "Стоимость: " << pApartment->price << " $" << endl; cout << "Дата постройки: " << pApartment->built.month << " " << pApartment->built.year << "\n\n\n"; building apartment2; //создаем и заполняем второй объект структуры apartment2.owner = "Игорь"; apartment2.city = "Киев"; apartment2.amountRooms = 4; apartment2.price = 300000; apartment2.built.month = "январь"; apartment2.built.year = 2012; building apartment3 = apartment2; //создаем третий объект структуры и присваиваем ему данные объекта apartment2 show(apartment3); cout << endl << endl; return 0; }

Коментарии по коду программы:

Строка 17 — создание объекта built типа date в определении структуры building . Строки 42 — 43 : создаем указатель на структуру struct building *pApartment; и далее присваиваем ему адрес уже созданного и заполненного данными объекта pApartment = &apartment1; . Обращаясь к элементам структуры через указатель мы используем оператор -> (тире и знак >) . Это видно в строках 47 — 51.

В строке 62 показано, как можно инициализировать структуру. А именно, можно создать новый объект структуры и присвоить ему одним целым, уже созданный и заполненный данными, объект. В функцию show() передаем объект структуры, как параметр — строка 64. Результат:

Владелец квартиры: Денис
Квартира находится в городе: Симферополь
Количество комнат: 5
Стоимость: 150000 $
Дата постройки: январь 2013
Владелец квартиры: Игорь
Квартира находится в городе: Киев
Количество комнат: 4
Стоимость: 300000 $
Дата постройки: январь 2012
Для продолжения нажмите любую клавишу. . .

Разобрав этот пример, мы увидели на практике следующее:

  • структуру можно вкладывать в другую структуру;
  • увидели, как создаётся указатель на структуру;
  • как нужно обращаться к элементу структуры через указатель. А именно, используя оператор -> ; В примере это было так: apartment0->owner , но можно и так (*apartment0).owner . Круглые скобки, во втором случае, обязательны.
  • данные одной структуры можно присвоить другой структуре;
  • можно структуру передать в функцию, как параметр (кстати, элементы структуры так же можно передавать в функцию, как параметры).

В дополнение ко всему, следует отметить, что функции могут так же возвращать структуры в результате своей работы. Например:

Building Set() { building object; // формирование объекта //... код функции return object; }

Вот так, вкратце, мы познакомились со структурами в языке С++, попрактиковались на примерах и узнали основы. Это только начало!

Структуры

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

Для разрешения подобных затруднений в C# предусмотрена структура , которая подобна классу, но относится к типу значения, а не к ссылочному типу данных. Т.е. структуры отличаются от классов тем, как они сохраняются в памяти и как к ним осуществляется доступ (классы - это ссылочные типы, размещаемые в куче, структуры - типы значений, размещаемые в стеке), а также некоторыми свойствами (например, структуры не поддерживают наследование). Из соображений производительности вы будете использовать структуры для небольших типов данных. Однако в отношении синтаксиса структуры очень похожи на классы.

Главное отличие состоит в том, что при их объявлении используется ключевое слово struct вместо class. Ниже приведена общая форма объявления структуры:

struct имя: интерфейсы { // объявления членов }

где имя обозначает конкретное имя структуры.

Как и у классов, у каждой структуры имеются свои члены: методы, поля, индексаторы, свойства, операторные методы и события. В структурах допускается также определять конструкторы, но не деструкторы. В то же время для структуры нельзя определить конструктор, используемый по умолчанию (т.е. конструктор без параметров). Дело в том, что конструктор, вызываемый по умолчанию, определяется для всех структур автоматически и не подлежит изменению. Такой конструктор инициализирует поля структуры значениями, задаваемыми по умолчанию. А поскольку структуры не поддерживают наследование, то их члены нельзя указывать как abstract, virtual или protected.

Объект структуры может быть создан с помощью оператора new таким же образом, как и объект класса, но в этом нет особой необходимости. Ведь когда используется оператор new, то вызывается конструктор, используемый по умолчанию. А когда этот оператор не используется, объект по-прежнему создается, хотя и не инициализируется. В этом случае инициализацию любых членов структуры придется выполнить вручную.

Давайте рассмотрим пример использования структур:

Using System; namespace ConsoleApplication1 { // Создадим структуру struct UserInfo { public string Name; public byte Age; public UserInfo(string Name, byte Age) { this.Name = Name; this.Age = Age; } public void WriteUserInfo() { Console.WriteLine("Имя: {0}, возраст: {1}",Name,Age); } } class Program { static void Main() { UserInfo user1 = new UserInfo("Alexandr", 26); Console.Write("user1: "); user1.WriteUserInfo(); UserInfo user2 = new UserInfo("Elena",22); Console.Write("user2: "); user2.WriteUserInfo(); // Показать главное отличие структур от классов user1 = user2; user2.Name = "Natalya"; user2.Age = 25; Console.Write("\nuser1: "); user1.WriteUserInfo(); Console.Write("user2: "); user2.WriteUserInfo(); Console.ReadLine(); } } }

Обратите внимание, когда одна структура присваивается другой, создается копия ее объекта. В этом заключается одно из главных отличий структуры от класса. Когда ссылка на один класс присваивается ссылке на другой класс, в итоге ссылка в левой части оператора присваивания указывает на тот же самый объект, что и ссылка в правой его части. А когда переменная одной структуры присваивается переменной другой структуры, создается копия объекта структуры из правой части оператора присваивания.

Поэтому, если бы в предыдущем примере использовался класс UserInfo вместо структуры, получился бы следующий результат:

Назначение структур

В связи с изложенным выше возникает резонный вопрос: зачем в C# включена структура, если она обладает более скромными возможностями, чем класс? Ответ на этот вопрос заключается в повышении эффективности и производительности программ. Структуры относятся к типам значений, и поэтому ими можно оперировать непосредственно, а не по ссылке. Следовательно, для работы со структурой вообще не требуется переменная ссылочного типа, а это означает в ряде случаев существенную экономию оперативной памяти.



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: