Чи можна ініціалізувати структурну змінну?

СТРУКТУРИ

Структура - тип даних, що задається користувачем. У загальному випадку при роботі зі структурами слід виділити чотири моменти:

- оголошення та визначення типу структури,

- оголошення структурної змінної,

- ініціалізація структурної змінної,

- використання структурної змінної.

Для представлення складних даних в мові С передбачений тип, який називається структурою. Структура дуже нагадує тип даних запис мови Pascal, але більш гнучкий і мобільний.

Визначення типу структури представляється у вигляді:

struct ID

{

<тип> <имя 1-го элемента>;

<тип> <имя 2-го элемента>;

…………

<тип> <имя последнего элемента>;

};

Визначення типу структури починається з ключового слова struct і містить список оголошень, укладених у фігурні дужки. За словом struct слідує ім'я типу, зване тегом структури (tag - ярлик, етикетка). Елементи списку оголошень називаються членами структури або полями. Кожен елемент списку має унікальне для даного структурного типу ім'я. Однак слід зауважити, що одні і ті ж імена полів можуть бути використані в різних структурних типах.

При розгляді структури в мові С треба пам'ятати про те, що термін "структура" є узагальнюючим і вбирає в себе два поняття структурний шаблон і структурна змінна.

Структурний шаблон є основною схемою, яка описує, як збирається структура. приклад:

srtuct book

{

char title [50];

char author [30];

float value;

};

Першим стоїть ключове слово struct. Воно визначає, що все, що стоїть за ним є структурним шаблоном. Далі слід необов'язкове ім'я типу структури. В даному випадку це book. Де-небудь пізніше в програмі може з'явитися опис, наприклад struct book libry;. Цей опис вводить структурну змінну типу book.

За ім'ям типу слідує список елементів структури, укладений в парні фігурні дужки. Кожен елемент визначається своїм власним описом. Наприклад, елемент title є символьним масивом. Елементи структури можуть бути даними будь-якого типу, включаючи інші структури.

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

Для того, щоб змусити структуру працювати, треба створити структурну змінну. Отже, це може виглядати наступним чином: struct book libry;. Створення структурної змінної libry відбувається згідно з планом, встановленим шаблоном book. Згідно з останнім, компілятор виділяє пам'ять для масиву title, масиву author і змінної value. Ця пам'ять виділяється під ім'ям libry.

В описі struct book libry; struct book відіграє ту ж роль, що і int або float в звичних нам описах.

Завдання структурної змінної можна здійснювати двояко:

1) одночасно з описом структурного шаблону:

struct book

{

char title [50];

char author [30];

float value;

} libry;

2) окремо від опису структурного шаблону:

struct book {

char title [50];

char author [30];

float value;

};

...

struct book libry;

...

Перший випадок є саме тим випадком, коли дозволяється не використовувати ім'я типу структури:

struct

{

char title [50];

char author [30];

float value;

} libry;

Вибір форми опису структурного шаблону і структурної змінної є справою смаку програміста. Жорстких рекомендацій тут немає. Вважається, що форма з ім'ям типу структури є гарним стилем програмування.

Чи можна ініціалізувати структурну змінну?

Так. Але знову таки, якщо структурна змінна буде зовнішньої або статичною. Тут треба мати на увазі, що приналежність структурної змінної до зовнішнього типу залежить від того, де визначена змінна, а не де визначений шаблон. Наприклад, шаблон може бути описаний, як зовнішній, а змінна визначена усередині функції, тоді змінна розташовується в автоматичному класі пам'яті і є локальною по відношенню до цієї функції.

Припустимо, що створили структурну змінну:

static struct book libry;

тут використовується статичний клас пам'яті і можна ініціалізувати структурну змінну, що і зробимо:

static struct book libry = {"Три мушкетери" "Олександр Дюма" 3.95};

Для доступу до елементів структури використовується символ ".", Який позначає операцію отримання елемента структури. Наприклад, libry.value, libry.title, libry.author. На підставі цього справедливі записи:

scanf ("% f", & libry.value);

Розглянемо приклад:

# include <stdio.h>

# include <windows.h>

#include <locale.h>

# define MAXTIT 50 // Команда # define використовується для організації заміни рядка по всьому файлу, де вона вказана.

# define MAXAUT 30

struct book

{

char title [MAXTIT];

char author [MAXAUT];

float value;

};

void main (void)

{

setlocale(LC_CTYPE, "Russian");

struct book libry;

printf ("Введiть назву книги : \n ");

gets (libry.title);

printf (" Введiть прiзвище автора: \n ");

gets (libry.author);

printf (" Введiть цiну: \n ");

scanf ("%f", &libry.value);

printf ("Вашi введенi данi стосовно книги: \n");

printf ("%s %s %f \n", libry.author, libry.title, libry.value);

system("pause");

}

чи можна ініціалізувати структурну змінну? - student2.ru

Приклад опису структури:

struct student

{

char name [50];

int kurs;

int age;

};

Ми визначили структуру в яку входять змінні kurs, age і масив name. У цьому описі student є шаблоном структури, struct student є типом даних. Після опису структури потрібно ставити крапку з коми. Щоб використовувати структуру необхідно оголосити змінні типу struct student.

Наприклад,

struct student s1, s2;

Змінні s1 і s2 є змінними типу struct student.

Компілятор автоматично виділить пам'ять під ці змінні. Під кожну з змінних типу структури виділяється безперервний ділянку пам'яті.

Для отримання доступу до полів структури використовується операція точка. Наприклад,

strcpy (s1.name, "Бардін Павло");

s1.kurs = 3;

s1.age = 20;

У мові С є можливість оголошувати змінні структури при описі структури:

struct student

{

char name [50];

int kurs;

int age;

} s1, s2;

Змінні s1 і s2 є змінними типу struct student.

Елементами або полями структури можуть бути змінні, масиви, раніше певні структури. Функції не можуть бути полями структури (В мові Сі). У мові С + + функції можуть бути полями структури і такі структури називаються класами. Вони визначаються за допомогою ключового слова class.

Для змінних s1 і s2 можливо присвоювання

s1 = s2

так як ці змінні створені на базі одного шаблону. Після такого присвоювання поля структури s1 будуть містити ту ж інформацію, що і поля s2. Якщо ми опишемо дві структури з одними і тими ж полями, але перша структура матиме шаблон student1, а друга student2, то присвоювання s1 = s2 неприпустимо.

Приклад програми.

# include <stdio.h>

# include <windows.h>

#include <locale.h>

// Визначення структури

struct student

{

char name [30];

int kurs;

int age;

};

void main ()

{

setlocale(LC_CTYPE, "Russian");

// Оголошення змінних stud1 і stud2 типу struct student

struct student stud1, stud2;

printf ("Введiть iм'я: ");

// Введення імені

gets (stud1.name);

printf ("Введiть вiк: ");

// Введення віку

scanf ("%d", &stud1.age);

printf ("Введiть номер курсу: ");

// Введення номери курсу

scanf ("%d", &stud1.kurs);

// Присвоювання stud2 = stud1 можливо, так як один і той самий шаблон

stud2 = stud1;

// Вивід

printf ("Студент %s \n", stud2.name);

printf ("Курс %d \n", stud2.kurs);

printf ("Вiк %d \n", stud2.age);

system("pause");

}

чи можна ініціалізувати структурну змінну? - student2.ru

Зауважте, що коли ми робимо виклик scanf ("%d", &stud1.age); та scanf ("%d", &stud1.kurs); ми ставимо знак & перед ім'ям структури, а не перед ім'ям поля (елемента структури).

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

Структури можуть бути об'єднані в масиви структур. Оголошення масиву структур робиться аналогічно оголошенню масиву змінних. Наприклад, якщо потрібно зберігати інформацію про 10 студентах, то оголошення масиву буде наступним

struct student stud1 [10];

Тут stud1 - ім'я масиву структур, а stud1 [0] - це перша структура, stud1 [1] - друга ... stud1 [9] - десята структура. Щоб отримати доступ до поля age п'ятий структури потрібно написати stud1 [4]. age

Щоб отримати доступ до поля kurs першої структури потрібно написати stud1 [0]. kurs

Приклад програми.

# include <stdio.h>

# include <windows.h>

#include <locale.h>

// Визначення структури

struct student

{

char name [30];

int kurs;

int age;

};

void main ()

{

setlocale(LC_CTYPE, "Russian");

// Оголошення масиву на 10 структур

struct student stud [10];

int i, n;

printf ("Кiлькiсть студентiв:");

// Введення n (число студентів)

scanf ("%d", &n);

for (i = 0; i <n; i ++)

{

printf ("Введiть iм'я: ");

// Введення імені

scanf ("%s", &stud[i].name);

printf ("Введiть вiк: ");

// Введення віку

scanf ("%d", &stud[i].age);

printf ("Введiть номер курсу: ");

// Введення номера курсу

scanf ("%d", &stud[i].kurs);

}

// Вивід

for (i = 0; i <n; i ++)

{

printf ("Студент %s\n",stud[i].name);

printf ("Курс %d \n", stud [i].kurs);

printf ("Вiк %d \n", stud[i].age);

}

system("pause");

}

чи можна ініціалізувати структурну змінну? - student2.ru

Структури і функції

Структури, як і звичайні типи даних, можна передавати функції в якості аргументу. Наступний приклад демонструє роботу функції відображення полів структури на екран.

Передача структур через аргументи функції.

# include <stdio.h>

# include <windows.h>

#include <locale.h>

// Визначення структури

struct people

{

char name [100];

char job [100];

int old;

};

void show (struct people man);

void main ()

{

setlocale(LC_CTYPE, "Russian");

struct people person = {"Ivanov", "Electric", 30};

show (person);

system("pause");

}

void show (struct people man)

{

printf ("Iм'я: %s \n", man.name);

printf ("Професiя: %s \n", man.job);

printf ("Вiк: %d \n", man.old);

}

чи можна ініціалізувати структурну змінну? - student2.ru

У наведеному прикладі використовується функція з ім'ям show, яка має тип аргументу struct people і змінну-структуру man. При передачі структури функції створюється її копія, яка доступна в тілі функції show під ім'ям man. Отже, будь-які зміни полів структури з ім'ям man ніяк не вплинуть на зміст структури з ім'ям person. Разом з тим іноді необхідно виконувати зміна полів структури функції і повертати змінені дані викликає програмі. Для цього можна задати функцію, яка буде повертати структуру, як показано в програмі.

Функції, які приймають і повертають структура.

# include <stdio.h>

# include <windows.h>

#include <locale.h>

// Визначення структури

struct people

{

char name [100];

char job [100];

int old;

};

void show (struct people man);

struct people get ();

void main ()

{

setlocale(LC_CTYPE, "Russian");

struct people person;

person = get ();

show (person);

system("pause");

}

void show (struct people man)

{

printf ("Iм'я: %s \n", man.name);

printf ("Професiя: %s \n", man.job);

printf ("Вiк: %d \n", man.old);

}

struct people get ()

{

struct people man;

printf ("Iм'я: ");

scanf ("%s", &man.name);

printf ("Професiя: ");

scanf ("%s", &man.job);

printf ("Вiк: ");

scanf ("%d", &man.old);

return man;

}

чи можна ініціалізувати структурну змінну? - student2.ru

У даному прикладі використовується функція get (), яка ініціалізує структуру з ім'ям man, запитує у користувача введення значень її полів і повертає введену інформацію головній програмі. В результаті виконання оператора присвоювання структури man структурі person, відбувається копіювання інформації відповідних полів і автоматичне вилучення структури man.

Функцій в якості аргументу можна також передавати масиви структур. Для цього використовується наступне визначення:

void show (struct people mans [], int size);

Тут size - кількість елементів масиву, яке необхідно для коректного зчитування інформації масиву mans. Наступний приклад показує принцип роботи з масивами структур.

Передача масив структур функції.

# include <stdio.h>

# include <windows.h>

# include <locale.h>

/* Директива #define визначає ідентифікатор і послідовність символів,

яка буде підставлятися замість ідентифікатора кожен раз, коли він зустрінеться

у вихідному файлі.*/

#define N 2

// Визначення структури

struct people

{

char name [100];

char job [100];

int old;

};

void show (struct people mans [], int size);

int main ()

{

setlocale(LC_CTYPE, "Russian");

struct people persons [N] = {{"Ivanov", "Elektrik", 35}, {"Petrov", "Vikladach", 50}};

show (persons, N);

system("pause");

}

void show (struct people mans [], int size)

{

for (int i = 0; i <size; i ++)

{

printf ("Iм'я:%s \n", mans [i].name);

printf ("Професiя:%s \n", mans [i].job);

printf ("Вiк:%d \n", mans [i].old);

}

}

чи можна ініціалізувати структурну змінну? - student2.ru

При передачі аргументу persons виконується копіювання інформації в масив mans і вказується додатковий параметр size, для визначення числа елементів масиву mans. Потім у функції show () реалізується цикл, в якому виконується відображення інформації масиву структури на екран монітора.

Вказівники на структуру

Вказівники на структури використовуються головним чином в двох випадках: коли структура передається функції за допомогою виклику за посиланням, і коли створюються пов'язані один з одним списки та інші структури з динамічними даними, що працюють на основі динамічного розміщення. У цій главі розглядається перший випадок.

У такого способу, як передача будь-яких (окрім найпростіших) структур функціям, є один великий недолік: при виконанні виклику функції, щоб помістити структуру в стек, необхідні істотні ресурси. (Згадайте, що аргументи передаються функцій через стек). Втім, для простих структур з кількома членами ці ресурси є не такими вже великими. Але якщо в структурі є велика кількість членів або деякі члени самі є масивами, то при передачі структур функціям продуктивність може впасти до неприпустимо низького рівня. Як же вирішити цю проблему? Треба передавати не саму структуру, а вказівник на неї.

Коли функції передається вказівник на структуру, то в стек потрапляє тільки адреса структури. В результаті виклики функції виконуються дуже швидко. У деяких випадках цей спосіб має ще і другу перевагу: передача вказівника дозволяє функції модифікувати вміст структури, використовуваної в якості аргументу.

Щоб отримати адресу змінної-структури, необхідно перед її ім'ям помістити оператор &. Наприклад, в наступному фрагменті коду

struct bal {

float balance;

char name [80];

} Person;

struct bal * p; / * оголошення вказівника на структуру * /

адреса структури person можна привласнити вказівнику p:

p = &person;

Щоб за допомогою вказівника на структуру отримати доступ до її членів, необхідно використовувати оператор стрілка ->. Ось, наприклад, як можна послатися на поле balance:

p-> balance

Оператор ->, який зазвичай називають оператором стрілки, складається зі знаку "мінус", за яким слідує знак "більше". Стрілка застосовується замість оператора точки тоді, коли для доступу до члена структури використовується вказівник на структуру.

Щоб побачити, як можна використовувати вказівник на структуру, проаналізуйте наступну просту програму, яка імітує таймер, що виводить значення годин, хвилин і секунд:

/* Програма-імітатор таймера. */

# include <stdio.h>

# include <windows.h>

# include <locale.h>

# define DELAY 12800000

struct my_time {

int hours;

int minutes;

int seconds;

};

void display (struct my_time*);

void update (struct my_time*);

void delay (void);

void main ()

{

setlocale(LC_CTYPE, "Russian");

struct my_time systime;

systime.hours = 0;

systime.minutes = 0;

systime.seconds = 0;

for (; ;)

{

update (& systime);

display (& systime);

}

system("pause");

}

void update (struct my_time * t)

{

t-> seconds++;

if (t-> seconds == 60)

{

t-> seconds = 0;

t-> minutes++;

}

if (t-> minutes == 60)

{

t-> minutes = 0;

t-> hours++;

}

if (t-> hours == 24) t-> hours = 0;

delay ();

}

void display (struct my_time * t)

{

printf ("% 02d:", t-> hours);

printf ("% 02d:", t-> minutes);

printf ("% 02d \n", t-> seconds);

}

void delay (void)

{

long int t;

/* Якщо треба, можна змінювати константу DELAY (затримка) */

for (t = 1; t <DELAY; ++t);

}

чи можна ініціалізувати структурну змінну? - student2.ru

Цю програму можна налаштовувати, змінюючи визначення DELAY.

У цій програмі оголошена глобальна структура my_time, але при цьому не оголошені ніякі інші змінні програми. Усередині ж main () оголошена структура systime і вона ініціалізується значенням 00:00:00. Це означає, що systime безпосередньо видна тільки у функції main ().

Функціям update () (яка змінює значення часу) і display () (яка виводить ці значення) передається адреса структури systime. Аргументи в обох функціях оголошуються як вказівник на структуру my_time.

Усередині update () і display () доступ до кожного члена systime здійснюється за допомогою покажчика. Так як функція update () приймає покажчик на структуру systime, то вона в стані оновлювати значення цієї структури. Наприклад, необхідно "опівночі", коли значення змінної, в якій зберігається кількість годин, стане рівним 24, скинути відлік і знову зробити значення цієї змінної рівним 0. Для цього в update () є наступна рядок:

if (t-> hours == 24) t-> hours = 0;

Таким чином, компілятору дається вказівка взяти адресу t (ця адреса вказує на змінну systime з main ()) і скинути значення hours в нуль.

Пам'ятайте, що оператор точка використовується для доступу до елементів структури при роботі з самою структурою. А коли використовується вказівник на структуру, то треба застосовувати оператор стрілка.

# include <stdio.h>

# include <windows.h>

# include <locale.h>

# include <string.h>

# include <iostream>

struct student

{

char name [10];

char surname [15];

int age;

} Stud;

void main ()

{

setlocale(LC_CTYPE, "Russian");

// змінна stud оголошена як структура типу student

struct student *s; // вказівник на структуру student

s = &Stud; // ініціалізація вказівника

strcpy (s-> name, "Larry"); // Функція strcpy () використовується для копіювання вмісту str2 в str1

// звернення як до вказівника на структуру

strcpy (s-> surname, "Johnson");

(*s).age = 34; // звернення як до змінної

printf ("\n Iм'я: %s \n Прiзвище: %s \n Вiк = %i \n", s-> name, s-> surname, s-> age);

system ("pause");

}

чи можна ініціалізувати структурну змінну? - student2.ru

Вкладені структури

Полем структурної змінної може бути змінна будь-якого типу, в тому числі інша структурна змінна. Поле, яке представляє собою структуру, називається вкладеною структурою.

Тип вкладеної структури повинен бути оголошений раніше. Крім того, структура не може бути вкладена в структуру того ж типу.

Коли структура є членом іншої структури, то вона називається укладеною. Наприклад, в наступному прикладі структура address вкладена в emp:

struct emp {

struct addr address; /* вкладена структура */

float wage;

} Worker;

Тут структура була визначена як така, що має два члени. Першим є структура типу addr, в якій знаходиться адреса працівника. Другий член - це wage, де знаходяться дані по його зарплаті. У наступному фрагменті коду елементу zip з address присвоюється значення 93456.

worker.address.zip = 93456;

Як ви бачите, в кожній структурі будь-який член позначають за допомогою тих структур, в які він вкладений - починаючи від самих загальних і закінчуючи тією, безпосередньо в якій він знаходиться. У відповідності зі стандартом С89 структури можуть бути вкладеними аж до 15-го рівня. А стандарт С99 допускає рівень вкладеності до 63-го включно.

Наши рекомендации