Напредак се не прати јер нисте улоговани.
Садржај

Структуре

Структуре су још један врло значајан тип који корисник сам дефинише. Оне представљају начин да од више података, који у датом контексту чине смисаону целину, направимо један „групни” податак. Груписањем података у структуру наглашавамо и на нивоу писања кода смисаону повезаност података и тиме програм чинимо јаснијим. Осим тога, поједностављујемо прослеђивање такве групе података као параметра методу, враћање групе података као резултата рада метода и додељивање групе података другој групи.

Поља структуре

Податке од којих се структура састоји зовемо поља структуре. Поља могу, али не морају да буду међусобно истог типа. Такође, поља могу да буду и сложеног типа, укључујући друге структуре, низове итд.

У свом најпростијем облику, структурни тип се дефинише писањем кључне речи struct, иза које следи име типа, а затим у витичастим заградама списак поља. На пример, структура Knjiga, која описује једну књигу, може да буде задата овако:

struct Knjiga {
    public string autor;
    public string naslov;
    public string oblast;
    public int brStrana;
};

Променљиве чији је тип нека структура такође зовемо структуре. Када је потребно да разликујемо тип и променљиву, користимо термине структурни тип и структурна променљива.

У програму се пољима структуре приступа помоћу имена структурне променљиве и тачке. На пример, након дате дефиниције структуре Knjiga, њена поља autor i brStrana би могла да се употребе овако:

Knjiga k;

// ...

if (k.autor.Contains(upit))
    Console.WriteLine(k.brStrana);

Напоменимо још да, за разлику од низова, листи, стрингова и матрица, структуре нису референцирани, него вредносни тип података. По томе су структуре сличније простим типовима као што су целобројни и реални типови. То значи да се приликом додељивања једне структурне променљиве другој врши копирање садржаја свих поља. На пример, извршавањем (иначе бесмисленог) кода

Knjiga k1, k2;

// ...

k2 = k1;
k1.brStrana += 1;
Console.WriteLine(k1.brStrana);
Console.WriteLine(k2.brStrana);

била би исписана два различита броја, чиме само потврђујемо да свака променљива задржава свој простор у меморији, тј. не долази до коришћења истог простора као што је то случај код референцираних типова података.

Структуре и класе:

У овом курсу класе користимо прећутно и без детаљнијих објашњења од самог почетка (сваки програм има бар једну класу). Класама се не бавимо детаљније у овом курсу јер су оне пре свега начин да се већи програми организују у функционалне целине, а та тема је ван оквира курса. Међутим, пошто класе могу да се користе и као тип података врло сличан структури, овде желимо да истакнемо једну важну разлику између класа и структура: класе су референцирани тип података, а структуре нису. Последице ове чињенице су да се класе и структуре различито понашају као параметри метода, као и при додељивању вредности:

  • инстанце (објекти) класе се креирају у динамичкој меморији, искључиво позивом оператора new.

  • објекат класе прослеђен методу се може трајно изменити у методу (као и други референцирани типови)

  • Додељивање вредности објекту класе је промена референце (као и код других референцираних типова), након чега имамо само још једно име (референцу) за од раније постојећи објекат.

  • Поређење објеката неке класе помоћу оператора == је поређење референци, а не поређење садржаја.

Пример - претрага књига

Написати програм који најпре учитава број n и податке о n књига, за сваку књигу у једном реду. Подаци о једној књизи су име аутора, наслов, област и број страна, раздвојени запетом. Редови са подацима о књигама могу да изгледају, на пример, овако:

3
J. J. Zmaj, Riznica pesama za decu, poezija za decu, 156
W. Shakespeare, Romeo i Julija, drama tragdija, 190
W. Shakespeare, Otelo, drama tragdija, 144

Након тога, програм треба да учита број m и m упита, сваки упит у посебном реду. Упит се састоји од имена или дела имена аутора (нпр. Zmaj). На сваки упит програм треба да одговори исписивањем података о свим књигама чијем аутору се упит садржи у имену и (након списка) укупним бројем страна тих књига.

Користићемо листу структура да запамтимо податке о књигама. За сваки упит ћемо проћи кроз цео низ књига и проверити да ли се упит садржи у имену аутора. Напомињемо да постоје и ефикаснији начини да се овај задатак реши (у смислу времена потребног за извршавање програма), али смо изабрали овај као једноставнији за разумевање и илустровање употребе структура.

Приметимо да приликом додавања књиге у листу (метод Add) долази до копирања садржаја у нови елемент листе, исто као и при додељивању вредности структури (ово и јесте додељивање вредности новој структури у листи).

Својства структуре

Поред поља са подацима, структуре могу да садрже и друге делове, као што су својства, индексери, методи, операторски методи и догађаји. Овде се нећемо упуштати у описивање свега набројаног, већ ћемо употребљавати само поља (о којима је већ било речи) и својства.

Својство је члан структуре који користи исту синтаксу као поље. То значи да својства структура у програмима користимо као да су то поља (гледајући кôд који само користи поља и својства структура, не можемо да видимо разлику између поља и својства). Међутим, за својства структуре се не одваја простор у меморији. Уместо тога, приликом очитавања и додељивања вредности својству, извршавају се наредбе које напишемо у такозваним приступницима (енгл. accessor) датом својству. Свако својство може да има приступник за очитавање вредности који се зове get, и приступник за постављање вредности који се зове set.

Један од ова два приступника може и да се изостави и тада се својство користи само за читање или само за упис вредности (у зависности од тога који приступник је изостављен). На пример, у дефиницији структуре Prozor датој испод (која описује положај прозора на екрану), поред четири поља постоје и два својства: poslednjiRed и poslednjaKolona.

struct Prozor
{
    public int prviRed;
    public int prvaKolona;
    public int visina;
    public int sirina;
    public int poslednjiRed { get { return prviRed + visina - 1; } }
    public int poslednjaKolona { get { return prvaKolona + sirina - 1; } }
};

Оба ова својства имају само приступник get, што значи да могу да се користе само за читање вредности. На пример, можемо да пишемо:

Prozor a = new Prozor { prviRed = 20, prvaKolona = 10, visina = 100, sirina = 200 };
Console.WriteLine(a.poslednjiRed);

али не и

a.poslednjiRed = 200;

јер својство poslednjiRed нема приступник set.

Када постоји веза између неких величина које описују структуру, као што је случај са структуром Prozor и величинама prviRed, visina и poslednjiRed, није добро за сваку од тих величина користити поље. Да смо у претходном примеру уместо својства додали поље poslednjiRed, било би компликовано обезбеђивати конзистентност вредности структурне променљиве (могло би се догодити да веза између ових величина грешком буде нарушена). Боље је да се поља користе само за подгрупу тих величина, у којој све величине могу да се мењају независно једна од друге. У нашем примеру независно се мењају prviRed и visina, а величина poslednjiRed се само израчунава и не мења се директно, већ искључиво имплицитно, као последица промене неке од величина које се мењају директно и независно.

Још једна (мање битна) предност својстава над додатним пољима је употреба мање меморије.

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

У претходном примеру смо уједно видели и један начин иницијализације структурне променљиве када су познате почетне вредности свих поља:

Prozor a = new Prozor { prviRed = 20, prvaKolona = 10, visina = 100, sirina = 200 };

Могуће је иницијализовати структурну променљиву и када нису познате вредности свих поља, или чак ниједног поља:

Prozor b = new Prozor { prviRed = 50, prvaKolona = 60};
Prozor c = new Prozor();

Када користимо оператор new у коме не иницијализујемо сва поља структуре, поља која нису експлицитно иницијализована биће иницијализована имплицитно на подразумевану вредност за свој тип (нула за бројчане типове, празан стринг за стрингове, false за логички тип, null за референциране типове). Тако су иницијализације дате горе равноправне са

Prozor b = new Prozor { prviRed = 50, prvaKolona = 60, visina = 0, sirina = 0 };
Prozor c = new Prozor { prviRed = 0, prvaKolona = 0, visina = 0, sirina = 0 };

Уколико не иницијализујемо структурну променљиву помоћу оператора new, неопходно је да сваком пољу експлицитно доделимо вредност пре него што га употребимо. На пример, после

Prozor b;
b.prviRed = 3;

можемо да користимо b.prviRed, али не и b.visina.

Пример - температуре

У овом примеру је илустрована употреба својстава у структури. Структура представља температуру и може се задавати и очитавати у разним јединицама (Келвини, степени Целзијуса, Фаренхајта и Реомира). Међутим, све ове величине су међусобно зависне, тј. ако је позната једна (било која) могу да се израчунају све остале. Зато користимо само једно поље, које памти температуру у степенима Целзијуса, а и то поље је означено као приватно. То значи да корисници структуре не могу да приступају овом пољу. Температуре у свим јединицама су реализоване помоћу својстава.

Алтернативно решење је да имамо једно јавно (public) поље коме може да се приступа и које служи да представи температуру нпр. у степенима Целзијуса, а само за преостале јединице да користимо својства. Решење у коме је свака јединица представљена својством је изабрано само због симетрије - у њему су све јединице равноправне.

Извршавањем програма добијамо следећи излаз:

Voda kljuca na 100.00°C = 212.00°F = 373.15K
Papir se pali na 232.78°C = 451.00°F = 505.93K
Razlika ovih temperatura je 132.78°C, ili 239.00°F, ili 132.78K

Пример - посетиоци

У једној згради за сваког посетиоца се бележи време почетка и завршетка посете у сатима, минутима и секундама.

Написати програм који учитава број n и податке о n посета и исписује податке о посетиоцу (име и времена доласка и одласка) који се најдуже задржао у посети.

Подаци о свакој посети су у једном реду, и то име посетиоца, сат, минут и секунд доласка и сат, минут и секунд одласка, раздвојени по једним размаком. На пример, ако је Марко био у згради од 9:15:27 до 9:59:38, ред са подацима би изгледао овако:

Marko 9 15 27 9 59 38

Унос података о једном посетиоцу смо издвојили у посебан метод UnosPosetioca, да бисмо једноставно (без понављања кода) могли да учитамо податке о првом посетиоцу пре петље, а о осталима у петљи. У овом методу можемо још једном да видимо како се иницијализује структурна променљива.

Структура Posetilac има и својство TrajanjePosete које може само да се чита, тако да је увек ажурно и не оптерећује структуру додатном меморијом (нема редунданце у подацима).

Остатак програма је једноставан и своди се на тражење максимума у серији података.

Тема

Prijavi problem


Obeleži sve kategorije koje odgovaraju problemu

Još detalja - opišite nam problem


Uspešno ste prijavili problem!
Status problema i sve dodatne informacije možete pratiti klikom na link.
Nažalost nismo trenutno u mogućnosti da obradimo vaš zahtev.
Molimo vas da pokušate kasnije.