You are on page 1of 23

Шта је програмирање?

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

Карактеристике програмског језика Ц

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

Језик опше намене, са посебним погодностима за системско програмирање

Императивни језик

Модуларни језик
Блок-структурни језик

Необјектни језик

Компактан језик (мали скуп резервисаних речи)


Ефикасан језик (мали хардверски захтеви, велика брзина)

Стандардизован и преносив језик


Case-sensitive и free-form језик

Верзије и стандарди програмског језика Ц

C – Пробитни Ц, Др Денис Ричи, Белове лабораторије, 1972.


K&R C – Керниганов и Ричијев Ц, заснован на Референтном приручнику из књиге: The C Programming
Language; прво издање 1978, друго издање 1988.
С89 – по националном стандарду ANSI X3.159:1989 (назван: ANSI C), усвојен је међународни стандард
ISO/IEC 9899:1990 + додатак (Normative Addendum I): ISI/IEC 9899/AMDI:1995.
С99 – међународни стандард ISO/IEC 9899:1999 + исправке и допуне (Тechnical Сorrigenda): TC1:2001
и TC2:2004.
С11 – међународни стандард ISO/IEC 9899:2011.

Елементи програмског језика Ц 1/5

Скуп знакова (character set) – мала и велика слова енглеске абецеде (a – z, A – Z), десет декадних
цифара (0 - 9), двадесет девет знаковa интерпункције: ! " # % & ' * ( ) + - / : ; ^ < > ~ , ? = [ ] _ { . \ | }
Диграфи:
Триграфи:
Диграф Еквивалент Триграф Еквивалент
<: [ ??( [
:> ] ??) ]
<% { ??< {
%> } ??> }
%: # ??= #
%:%: ## ??/ \
??! |
??' ^
??- ~
Лексички симбол = лексема = токен (token) – недељиви низ знакова, најмања програмска семантичка
јединица. Лексеме се деле на: идентификаторе, константе, резервисане речи, операторе и сепараторе

Бели знакови (white spaces) – размак, хоризонтална табулација, вертикална табулација, нови ред, нова
страна

Коментари (comments) –
Вишередни или блок коментар: /* */

Једноредни коментар: //

Искази (statements) – низови лексичких симбола. Деле се на:


Декларативне исказе (declarativ st.) којима се декларишу делови програма (подаци, потпрограми итд)
Извршне (егзекутивне) исказе (executive st.) = наредбе којима се одређују акције програма
Програм (program) – низови декларативних и извршних исказа којима се специфицира начин обраде
података
Директиве препроцесора (preprocessor directives) – упутства помоћу којих може да се утиче на ток
превођења програма. Оне нису део програма, па се зато не убрајају у исказе. Њих узима у обзир
претпроцесор, који врши припрему изворног кôда пре самог превођења. Једна директива – један ред:
свака директива пише се у засебном реду и мора да почиње знаком #. Не смеју да се мешају са исказима
програма

Идентификатори (identifiers) – служе за означавање (именовање) свих врста елемената програма:


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

Идентификатори могу да се састоје од слова, цифара и доње црте (_). Први знак не сме да буде цифра
Прави се разлика између великих и малих слова: procenat ≠ Procenat ≠ PROCENAT

Идентификатор може бити произвољне дужине, али се најмање првих 31 знакова користи за
идентификацију

Резервисане речи (keywords) – има их 37 и не смеју се користити као идентификатори:

auto double inline sizeof volatile


break else int static while
case enum long struct _Bool
char extern register switch _Complex
const float restrict typedef _Imaginary
continue for return union
default goto short unsigned
do if signed void

Структура програма 1/2

Функција (function) – основни градивни елемент програмског језика Ц; састоји се из секвенце исказа;
унутар функције се наредбе (тј. извршни искази) могу груписати у блокове (blocks)
Две врсте функција:

Готове функције из стадардне библиотеке - прототипови ф-ја из стандардне библиотеке налазе се у


датотекама заглавља (header files, *.h)
Програмерски креиране функције, налазе се у датотекама изворног кода (source code files, *.c); могу
да се налазе у програмерски креираним библиотекама (*.h + *.obj)
Сваки програм има једну обавезну функцију: main()
Ова ф-ја се прва позива; представља највиши ниво управљања током извршења програма
Дефиниције функција не могу се угнездити једна у другу, тј. не постоје подфункције
Функције се могу дефинисати произвољним редоследом
Функције могу међусобно да се позивају; функција може и саму себе да позива (рекурзија)
Декларација функције ≠ дефиниција функције
Пре позива функције мора да претходи њена или декларација или дефиниција

Изворне датотеке 1/2

У ПЈ Ц постоје две врсте изворних датотека:


1)*.c – изворне датотеке, садрже програмски кôд
2)*.h – датотеке заглавља, садрже прототипове функција, дефиниције константи и дефиниције макроа

Уобичајена структура *.c датотеке:


1)Претпроцесорске директиве
2)Глобалне декларације
3)Дефиниције функција

Начин укључивања *.h датотеке у изворни код остварује се употребом директиве #include
Укључивање *.h датотеке из системског
includе-директоријума:
#include <stdio.h>
Укључивање *.h датотеке из текућег директоријума:
#include "P02_krug.h"
Изворна датотека на језику Ц, заједно са свим датотекама заглавља које садржи, сачињава јединицу за
превођење (translation unit). Преводилац (compiler) преводи њен садржај секвенцијално, разлажући
изворни код на лексеме (токене)

Област важења идентификатора 1/2

Област важења (scope) идентификатора – део јединице за превођење у којем идентификатор има
значење. Другим речима, то је онај део програма у којем је идентификатор доступан („видљив“)
Врсту области важења увек одређује место на којем се идентификатор декларише.
Напомена: Изузетак су лабеле, јер је њихова област важења увек функција

Постоје четири врсте области важења:


1.Област датотеке (file scope) – ако се идентификатор декларише изван свих блокова и листа
параметара, његова област важења је датотека. Тада се може користити свуда унутар датотеке, почев од
места декларације па до њеног краја
2.Област блока (block scope) – сви идентификатори декларисани у блоку, изузев лабела, важећи су у
том блоку. Декларације се не морају налазити пре наредби у блоку. Нпр. тело дефиниције функције чини
један блок
3.Област прототипа функције (function prototype scope) – имена параметара у прототипу ф-је
припадају области важења тог прототипа. Пошто имена параметара немају значење ван прототипа,
корисна су само за подсећање, па се зато могу изоставити
4.Област функције (function scope) – област важења лабеле увек је блок ф-је у којој се појављује, чак и
када је блок угнежђен

Типови података у ПЈ Ц
Логички аспект: Формално, тип података је алгебарска структура и одређује се као:
(непразан) скуп вредности /домен/,
(непразан) скуп операција над датим скупом вредности /интерфејс/ и
(могуће празан) скуп константи.

ТИП ПОДАТАКА = СВ + СО + СК
Физички аспект: Maтеријално, тип података је одређен меморијском репрезентацијом:
величином меморије неопходном за меморисање вредности типа, исказана у By
начин кодирања вредности типа

На пример, скуп целих означених бројева int (синоними: signed, signed int) има:
Домен: [-2.147.483.648, 2.147.483.647]
Операторe: +, -, /, %, * итд.
Константе: INT_MIN и INT_MAX
Величину: 4 By
Типови података у ПЈ Ц

У ПЈ Ц, појам објекат означава место у меморији чији садржај може да представља вредност.
Објекти који имају имена називају се променљиве (variables)
Објекти који имају имена и додељену вредност која се не може мењати називају се константе
(constants)
Тип објекта одређује колико простора објекат заузима у меморији и како се кодирају његове могуће
вредности.

На пример, исти низ битова може представљати потпуно различите целе бројеве, зависно од тога да ли
се тумачи као означена (signed) или неозначена (unsigned) вредност
ПЈ Ц познаје само нумеричке типове података

Целобројни типови података у ПЈ Ц


Основни целобројни тип: int
Спецификатори дужине: short и long

Спецификатори знака: unsigned и signed

Уобичајена величина: 2By или 4By

Константе (у limits.h):
SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX

SHR_MIN, INT_MIN, LONG_MIN, LLONG_MIN

sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long)

Најмањи целобројни тип: char

Спецификатори: unsigned и signed

Уобичајена величина: 1By

Константе:
CHAR_MAX, SCHAR_MAX, UCHAR_MAX

CHAR_MIN, SCHAR_MIN
sizeof(unsigned char) = sizeof(char)
= sizeof(signed char)

Највећи целобројни тип: long long int

Спецификатори: unsigned и signed

Уобичајена величина: 8By

Константе:
LLONG_MAX, ULLONG_MAX

LLONG_MIN
sizeof(unsigned long long) = sizeof(signed long long)

Реални типови података у ПЈ Ц

Реални ТП = ТП у формату са покретним зарезом (floating-point data type)


Три врсте:
float (4 By, једнострука прецизност, 6 значајних цифара, опсег вредности: 1.17 х 10-38 до 3.40 х 10+38),
double (8 By, двострука прецизност, 15 значајних цифара, опсег вредности: 2.22 х 10-308 до 1.79 х
10+308) и
long double (10 By, проширена прецизност, 19 значајних цифара, опсег вредности: 3.4 х 10-4932 до 1.1
х 10+4932)

sizeof(float) < sizeof(double) < sizeof(long double)

Логички тип података у ПЈ Ц


У стандарду С99 уведен је неозначени целобројни тип _Bool за представљање логичких вредности
Нула је нетачно = false, а свака ненулта вредност је тачно = true
Уколико се у програм укључи заглавље stdbool.h могу се користити идентификатори:
bool (макро, синоним за _Bool),
true (симболичка константа, вредност 1) и
false (симболичка константа, вредност 0)
Комплексни тип података
Стандард С99 подржава математичке операције са комплексним бројевима

Комплекасан број је...

Три врсте:
float _Complex
double _Complex
long double _Complex
Пример:

#include <complex.h>
double complex cmpx = 2.1 + 3.2 * I;

Набројиви тип података у ПЈ Ц

Набројиви тип или енумерација (enumeration, enumerated type) je целобројни тип који програмер сам
дефинише у програму:

enum boja { CRVENA, BELA, PLAVA };


Енумерационе константе CRVENA, BELA, PLAVA имају вредности 0, 1 и 2, респективно. Могућа је и
додела сопствених вредности:

enum boja { CRVENA, BELA, PLAVA, SIVA = 8, BRAON};


или додељивање истих вредности:
enum boja {
OFF, ON,
STOP = 0, GO = 1,
CLOSED = 0, OPEN = 1 };

Тип података void у ПЈ Ц

Врло посебан тип. Зашто? Зато што нема познатих вредности тог типа. Зато се не може
декларисати променљива или констатна овога типа
Где се може користити тип void:
1)У декларацији функција:

int main (void){...}


int TekucaGodina(void);
2)За изразе типа void:

void PrikaziPozdrav(char * txt); // procedura


(void)printf(“Ne treba mi povratna vred. ove f-je\n“);
3)За генеричке показиваче (показивачи на тип void):

void * podatak;
void *malloc(size_t size);
void free(void *ptr);

Литерали
Литерал је лексема која означава непроменљиву вредност. Та вредност може бити број, знак или ниска
(низ знакова, знаковни низ). Тип литерала одређен је његовом вредношћу и начином записа
Разликују се:
Целобројни литерали:
Декадни,
Октални и
Хексадекадни.
Реални литерали:
Декадни и
Хексадекадни
Знаковни литерали:
ANSI (једнобајтни),
Вишебајтни и
Управљачки знаци
Ниске (стринг) литерали (литерали типа знаковних низова)

Целобројни литерали

Целобројни литерали - цели бројеви, чија се бројевна основа задаје префиксом


Основе:
Декадна - цели бројеви који почињу цифром другачијом од 0: 39, 255, -673...
Октална - цели бројеви који почињу цифром 0: 047 = (39)10, 0377 = (255)10, 0176537 = (-673)10 ...
Хексадекадна – цели бројеви који почињу префиксом 0х или 0Х: 0х27 = (39)10, 0хFF = (255)10, 0хFD5F
= (-673)10 ...
Целобројни литерали са суфиксом:
515U unsigned int
0L long
0xF0BUL unsigned long (основа хексадекадна)
0777LL long long (основа октална)
0хАААLLU unsigned long long (основа хексадекадна)

Реални литерали

Реални литерали: реални бројеви, чија се бројевна основа задаје префиксом


Основе:
Декадна - релни бројеви који почињу цифром другачијом од 0: 22.0, 3.45Е6, 67е-8, ...
Хексадекадна – реални бројеви који почињу префиксом 0х или 0Х
Може: .123 и 12. и .234Е5
Реални литерали са суфиксом – подразумевани тип реалних литерала (литерала у формату са
покретним зарезом) је double. Додавањем суфикса F или f, литералу се додељује тип float; a суфиксом L
или l, литералу се додељује тип long double. На пример:

float fltProm = 456.789F;


long double ldbProm = 7890.1L;

Знаковни литерали

Знаковни литерали се састоје од једног или више знакова под једноструким наводницима. На пример:
's', 'ASA', '9', '*', '=====', …
Изузетак у начину приказивању су знакови:
Апостроф '\'' је '
Обрнута коса црта '\\' је \
Управљачки знак за нови ред '\n' је нови ред
По величини, тј. по броју бајтова, постоје:
ANSI (једнобајтни) знакови и

Вишебајтни знакови

Знаковни литерали

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


Важнији упр.знаци:
\' полунаводник
\'' наводник
\? знак питања
\\ обрнута коса црта
\a упозорење (alert)
\b брисање уназад (backspace)
\f нова страна (form feed)
\n нови ред (new line)
\r почетак реда (carriage return)
\t хоризонтални табулатор
\v вертикални табулатор

Литерали типа знаковних низова

Ниске (стрингови) литерали или литерали типа знаковних низова су низови знакова под наводницима.
На пример: "Volim programiranje!\n"
Вишередни текст:

char *info = "Ovo je tekst\


napisan \n u tri\
reda, a bice prikazan u dva. Zasto\?\n

#include <stdio.h>

#define PI 3.1415926536

double pp[5] = {11.1, 12.2, 13.3, 14.4, 15.5};


double pv[5], ob[5];

void IzracunajPovrsinu(void);
void IzracunajObim(void);
void PrikazZaglavlja(void);
void PrikazRezultata(void);

int main(void)
{
printf(">>> P02_05_krug.c <<<\n\n");

IzracunajPovrsinu();
IzracunajObim();
PrikazZaglavlja();
PrikazRezultata();

return 0;
}//////////////////////////////////////////////////////////
double PovKruga(double pp) {
double pov;
pov = pp * pp * PI;
return pov;
}

void IzracunajPovrsinu(void) {
int i;
for (i = 0; i<=4; i = i+1)
pv[i] = PovKruga(pp[i]);
}
//////////////////////////////////////////////////////////

double ObKruga(double pp) {


return 2 * pp * PI;
}

void IzracunajObim(void) {
for (int i = 0; i<=4; i++)
ob[i] = ObKruga(pp[i]);
}
//////////////////////////////////////////////////////////

void PrikazZaglavlja(void) {
printf(" POVRSINE I OBIMI KRUGOVA\n\n");
printf(" Poluprecnik Povrsina Obim\n"
"===================================\n");
}

void PrikazRezultata(void) {
for (int i = 0; i<=4; i++)
printf("%12.1lf %12.3lf %8.3lf\n", pp[i], pv[i], ob[i]);
}
/*
** PROJEKAT : Osnove programiranja u programskom jeziku C
** DATOTEKA : P02_04_krug.c
** OPIS : Napisati program u programskom jeziku C koji na standardnom izlaznom uredjaju
** prikazuje površine i obime krugova ciji su poluprecnici zadati (11.1, 12.2, 13.3, 14.4, 15.5)
** upotrebom funkcija, funkcijskih prototipova i pomocnih funkcija za izracunavanje povrsine i obima.
** DATUM : 26.02.2016.
** AUTOR : S.D.L.
** PROMENE :
** xx.xx.xxxx. - <opis promene> (<programer>)
**
** Copyright (C) FON-LSI, 2016.
*/

#include <stdio.h>

#define PI 3.1415926536

double pp1 = 11.1, pp2 = 12.2, pp3 = 13.3, pp4 = 14.4, pp5 = 15.5;
double pv1, pv2, pv3, pv4, pv5,
ob1, ob2, ob3, ob4, ob5;

void IzracunajPovrsinu(void);
void IzracunajObim(void);
void PrikazZaglavlja(void);
void PrikazRezultata(void);

int main(void)
{
printf(">>> P02_04_krug.c <<<\n\n");

IzracunajPovrsinu();
IzracunajObim();

PrikazZaglavlja();
PrikazRezultata();

return 0;
}

//////////////////////////////////////////////////////////
double PovKruga(double pp) {
double pov;
pov = pp * pp * PI;
return pov;
}

void IzracunajPovrsinu(void) {
pv1 = PovKruga(pp1);
pv2 = PovKruga(pp2);
pv3 = PovKruga(pp3);
pv4 = PovKruga(pp4);
pv5 = PovKruga(pp5);
}
//////////////////////////////////////////////////////////

double ObKruga(double pp) {


return 2 * pp * PI;
}
void IzracunajObim(void) {
ob1 = ObKruga(pp1);
ob2 = ObKruga(pp2);
ob3 = ObKruga(pp3);
ob4 = ObKruga(pp4);
ob5 = ObKruga(pp5);
}
//////////////////////////////////////////////////////////

void PrikazZaglavlja(void) {
printf(" POVRSINE I OBIMI KRUGOVA\n\n");
printf(" Poluprecnik Povrsina Obim\n"
"===================================\n");
}

void PrikazRezultata(void) {
printf("%12.1lf %12.3lf %8.3lf\n", pp1, pv1, ob1);
printf("%12.1lf %12.3lf %8.3lf\n", pp2, pv2, ob2);
printf("%12.1lf %12.3lf %8.3lf\n", pp3, pv3, ob3);
printf("%12.1lf %12.3lf %8.3lf\n", pp4, pv4, ob4);
printf("%12.1lf %12.3lf %8.3lf\n", pp5, pv5, ob5);
}

Наредбе одређују акције које треба да се изврше.


На крају наредбе типа израз (expresion statement) налази се тачка-зарез: <izraz>;
Неколико типичних израза:
a = b; // dodela vrednosti
zbir = sab_1 + sab_2; // sabiranje i dodela
++x; // inkrementacija
printf("Zdravo!\n"); // poziv funkcije

Ако је наредба позив функције, а резултат функције није потребан, онда се он (резултат) може експлицитно одбацити на
следећи начин:
char ime[31];
(void) strcpy(ime, "Pavle");
Наредба се може састојати само од тачке-зареза; тада се она назива празна наредба (null statement). Hа пример, тело for-
циклуса може да буде празна наредба:

for (i = 0; ime[i] != '\0'; ++i);

Блок
Сложена наредба (compound statement) или блок (block) представља низ који се састоји од више наредби и/или
декларација који су смештени између великих (витичастих) заграда, тако да чине једну наредбу:

{ <niz deklaracija i naredbi> }


За разлику од простих наредби, блок се не завршава тачка-зарезом
Декларације се обично налазе на почетку блока, пре свих наредби. Међутим, од стандарда С99 дозвољено је да
декларација буде на произвољном месту у блоку
Идентификатори декларисани у блоку имају блоковску област важења (block scope), тј. доступни су само од њихове
декларације до краја блока

Избор: IF наредба

Синтакса (општи облик if-наредбе):


if ( <izraz> ) <naredba_1>
[ else <naredba_2> ]
Део else није обавезан
Семантика: Прво се проверава вредност израза <izraz>, да би се одредило која од две наредбе мора да се изврши. Израз
је увек скаларног типа. Ако је његова вредност TRUE (тј. различита од нуле) извршиће се <naredba_1>, иначе извршава се
<naredba_2> (ако је наведена)
Наредбе <naredba_1> и <naredba_2> могу бити сложене

Избор: SWITCH наредба 1/2


Синтакса (општи облик switch-наредбе):

switch ( <izraz> ) {
case <konstantna_vrednost_1>:
<naredba_1>
break;
case <konstantna_vrednost_2>:
<naredba_2>
break;
...
[ default:
<naredba_n> ]
}

Семантика: Израз <izraz> је целобројног типа и израчунава се једном. Затим се добијена вредност израза проверава са
константним вредностима у лабелама case. Ако се вредност израза подудара са неким од константних вредности лабела,
ток програма се премешта на наредбу која следи иза лабеле case. Уколико се не подудара ни са једним од наведених
константних вредности, програм наставља да се извршава од лабеле default (уколико постоји).

Понављање: итерација или циклична управљачка структура

Наредба понављања (iteration statement) омогућава вишестуко извршавање наредбе. Hаредба може бити проста или
сложена
У ПЈ Ц постоје три наредбе понављања:
while наредба
for наредба и
do-while наредба
Пример: Сумирати првих десет природних бројева.

int suma = 0, i = 1;
while (i <= 10)
{
suma = suma + i;
i = i + 1;
}
Постављање почетних вредности
Услов циклуса: контролна променљива Обрада података
Модификација контролне променљиве
Почетак и крај тела циклуса

Структура меморије која је додељена процесу


Процес = програм у извршењу
инструкције + меморија + процесор + У/И уређаји
Распоред меморије која је додељена процесу

Структура активационог записа


Process run-time stack

Memory allocation on the run-time stack

The items pushed onto the run-time stack:


the actual parametars, the return adress, the local variables.
The collection of all the items pushed onto the run-time stack:
a stack frame or activaction record

Показивач и показано

int i = 22, j;
int * pok;

pok = &i;
j = *pok;
*pok = 33;

pok – показивач
*pok – показано, оно на шта показује показивач
& – оператор референцирања
* – оператор дереференцирања

Дефинисање низова
Низ (array) је колекција података; садржи податке истога типа који се чувају у суседним меморијским локацијама. Ти
подаци се називају елементи низа.

Капацитет (димензија) низа = максималан број елемената које низ може да садржи

Број елемената низа = тренутни број (искоришћених) елемената низа

Величина низа = број бајтова (By) које заузима низ

Елементима низа се приступа преко индекса.

Елементи низа могу бити било ког типа, сем непотпуног типа.

И сам низ је неког типа; тај нови низ(овни) тип је одређен:


Бројем елемената који чине низ
Типом елемената који чине низ
На пример:
int nizInt[8]; // celobrojni niz od 8 elemenata ; float n[123]; // float niz od 123 elementa
У програмском језику Ц низови могу да буду и непотпуни, уколико се не одређује број елемената низа. На пример:
int n;
int nepIntNiz [2 * n]; // nepotpuni celobrojni niz
double nepDblNiz[n]; // nepotpuni double niz

Приступање елем. низа помоћу показивача


Други начин приступа елементима низа је помоћу показивача.
Преводилац име низа имплицитно конвертује у показивач на први елемент у свим изразима, изузев у операцијама са
оператором sizeof().
На пример:
додела вредности 8 свим елементима низа niz, може се остварити наредбом:

for (int * pok = niz; pok < (niz + DIM); ++pok)


*pok = 8;
додела вредности {10,12,14,16,18} елементима низа niz, може се остварити наредбом:

for (int * pok = niz, i = 0; pok < (niz + DIM); ++pok, ++i)
*pok = 2 * i + 10;
niz + i ::= адресa елемента са индексом i (тј. &niz[i])
*(niz + i) ::= вредност елемента са индексом i (тј. niz[i])

Иницијализација елемената низа


#define DIM 6
int niz[DIM] = {3, 4, 5, 6};
#define DIM 6
int niz[DIM] = {3, [DIM/2] = 4, 5};

Ниске
Ниска = низ знакова = знаковни низ = стринг (string)
Ниска је:
непрекидна секвенца знакова која се завршава NULL знаком

ИЛИ
низ чији су елементи типа char и последњи елемент има вредност ‘\0‘
NULL знак = ‘\0‘
Дужина ниске = број знакова, не рачунајући завршни NULL знак
Ниска не постоји као посебан тип у Ц-у, па је зато ниједан оператор не прихвата као операнд

Наредне две иницијализације су идентичне:


char str1[20] = "Dobar dan";
char str1[20] = {'D', 'o', 'b', 'a', 'r', ' ', 'd', 'a', 'n', '\0' };
У претходном случају, дужина ниске је 9 (NULL знак се не узима у обзир), а низа је 20
Ако се дефинише низ знакова не наводећи његову дужину, а потом се иницијализује, направиће се низ
за један елемент дужи од ниске:

char str2[ ] = ", kolege.";


У претходном случају, дужина ниске је 9, а низа је 10. Зашто?
Шта се исписује? strcat() – спаја ниске; puts() – приказује ниску на stdout

strcat(str1, str2); // Мора: sizeof(str1) >= strlen(str1)+strlen(str2)+1.Зашто?


puts(str1);

Низови као аргументи функција

Када се као аргумент функције појави име низа, преводилац га имплицитно конвертује у показивач на
први елемент низа. То значи да је параметар ф-је увек показивач на исити тип, као и тип елемента низа
На пример:
void prikazi(int niz[ ], int brElem);
биће конвертовано у:
void prikazi(int * niz, int brElem);

Савет: предност дефинисања параметара помоћу средњих заграда (тј. оператора адресирања) је у томе
што је тако очигледно да ф-ја аргументе третира као показиваче на низ, а не само на појединачну
променљиву која је типа елемента низа (int у примеру). Постоје и друге предности.

Низ низова
Вишедимензиони низ (multidimensional array) је низ чији су елементи такође низови.

Елементи н-димензионог низа су (н-1)-димензиони низови. На пример, сваки елемент 2-димензионог


(2Д) низа јесте 1-димензиони (1Д) низ. Елементи 1Д низа нису низови.

Приликом декларисања вишедимензионог низа, сваки пар средњих заграда означава једну димензију
низа.
Декларисање вишедимензионих низова

Тродимензиони низ: int 3DNiz [3] [10] [5];

Низ 3DNiz састоји се од три елемента; сваки од њих је 2Д низ који се састоји од 10 1Д низова са по пет
целобројних вредности.

У низу 3DNiz има 3 х 10 х 5 = 150 елемената. Први елемент је 3DNiz[0][0][0], а последњи елемент је
3DNiz[2][9][4].

Додела вредности: 3DNiz[1][2][3] = 49;


Иницијализација вишедимензионих низова

int n3d [2][2][3] = {


{
{1, 0, 0},
{4, 0, 0}
},
{
{7, 8, 0},
{0, 0, 0}
}
};

Пошто се свим елементима без иницијализатора додељује подразумевана вредност нула, наредна
иницијализација има исти ефекат као и претходна:

int n3d [ ][2][3] = { { { 1 }, { 4 } }, { { 7, 8 } } };


Следеће наредбе имају исти ефекат као и претходна:

int n3d [2][2][3] = { { 1, 0, 0, 4 }, { 7, 8 } };


int n3d [2][2][3] = { 1, 0, 0, 4, 0, 0, 7, 8 };

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


int n3d [2][2][3] = { 1, [0][1][0] = 4, [1][0][0] = 7, 8 };
Или овако:

int n3d [2][2][3] = { { 1 }, [0][1] = { 4 }, [0][1] = { 7, 8} };


Овакав начин иницијализације има смисла када треба иницијализовати само неколико елемената
матрице вредностима другачијим од нуле.

Матрице

Дводимензиони низ се назива матрица (matrix). Често се користи. Елементи матрице распоређени су у
редове (rows) и колоне (columns). На пример, матрица од три реда и пет колона:
int matrica[3][5];
Три елемента matrica[0], matrica[1] и matrica[2] су редови матрице matrica. Сваки ред представља низ
од пет елемената типа int.
Вредности наведени у примеру могу се доделити елементима матрице применом угнежђеног циклуса.
Индекс у првом циклусу означава ред матрице, а у другом циклусу колону матрице:
for (int red = 0; red < 3; ++red)
for (int kol = 0; kol < 5; ++ kol)
matrica[red][kol] = red + kol + 10;
Три елемента matrica[0], matrica[1] и matrica[2] се смештају на суседним меморијским локацијама.
Табеларна форма матрице се пресликава у линеарни меморијски простор. Пошто се развој обавља по
редовима, у мемориј ће се распоред елемената обавити на следећи начин: слика
*Развој по редовима значи да се прво смештају елементи првог реда (тј. првог низа), па потом другог
реда (тј. другог низа) и на крају трећег реда матрице (тј. трећег низa)
Низ низова

Вишедимензиони низ (multidimensional array) је низ чији су елементи такође низови.

Елементи н-димензионог низа су (н-1)-димензиони низови. На пример, сваки елемент 2-димензионог


(2Д) низа јесте 1-димензиони (1Д) низ. Елементи 1Д низа нису низови.

Приликом декларисања вишедимензионог низа, сваки пар средњих заграда означава једну димензију
низа.

Декларисање вишедимензионих низова

Тродимензиони низ: int 3DNiz [3] [10] [5];

Низ 3DNiz састоји се од три елемента; сваки од њих је 2Д низ који се састоји од 10 1Д низова са по
пет целобројних вредности.

У низу 3DNiz има 3 х 10 х 5 = 150 елемената. Први елемент је 3DNiz[0][0][0], а последњи елемент је
3DNiz[2][9][4].

Додела вредности: 3DNiz[1][2][3] = 49;

Иницијализација вишедимензионих низова

Пошто се свим елементима без иницијализатора додељује подразумевана вредност нула, наредна
иницијализација има исти ефекат као и претходна: int n3d [ ][2][3] = { { { 1 }, { 4 } }, { { 7, 8 } } };

Следеће наредбе имају исти ефекат као и претходна:


int n3d [2][2][3] = { { 1, 0, 0, 4 }, { 7, 8 } };
int n3d [2][2][3] = { 1, 0, 0, 4, 0, 0, 7, 8 };

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


int n3d [2][2][3] = { 1, [0][1][0] = 4, [1][0][0] = 7, 8 };

Или овако: int n3d [2][2][3] = { { 1 }, [0][1] = { 4 }, [0][1] = { 7, 8} };

Овакав начин иницијализације има смисла када треба иницијализовати само неколико елемената
матрице вредностима другачијим од нуле.

Матрице

Дводимензиони низ се назива матрица (matrix). Често се користи. Елементи матрице распоређени су у
редове (rows) и колоне (columns). На пример, матрица од три реда и пет колона: int matrica[3][5];

Три елемента matrica[0], matrica[1] и matrica[2] су редови матрице matrica. Сваки ред представља низ
од пет елемената типа int.

Вредности наведени у примеру могу се доделити елементима матрице применом угнежђеног циклуса.
Индекс у првом циклусу означава ред матрице, а у другом циклусу колону матрице:
for (int red = 0; red < 3; ++red)
for (int kol = 0; kol < 5; ++ kol)
matrica[red][kol] = red + kol + 10;
Табеларна форма матрице се пресликава у линеарни меморијски простор. Пошто се развој обавља по
редовима, у мемориј ће се распоред елемената обавити на следећи начин:
OPIS : Obrazovana je grupa od pet studenata koji polazu tri predmeta u tekucem
** ispitnom roku. Na kraju ispitnog roka svi studenti su polozili sva tri ispita.
** Implementirati:
** 1) f-ju za unos ocena;
** 2) f-ju za prikaz ocena:
** a) prikaz po studentima
** b) prikaz po predmetima
** c) tabelaran prikaz
** 3) f-ju koja odredjuje prosecnu ocenu svih studenata
** (prolaz kroz matricu element po element)
** 4) f-ju koja odredjuje prosek za svakog studenta pojedinacno
** (prolaz kroz matricu po redovima /vrstama/)
** 5) f-ju koja odredjuje prosek za svaki predmet pojedinacno
** (prolaz kroz matricu po kolonama)
** Ocene su date u matrici: ocene[5][3]
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define STUD 5
#define PRED 3
#define AND &&
#define OR ||

// Tipovi podataka
typedef unsigned short int USHORT;
typedef int OCENE[STUD][PRED];
typedef float PR_OC_PO_STUD[STUD];
typedef float PR_OC_PO_PRED[PRED];

// Prototipovi f-ja
void UnesiOcene(OCENE);
bool OcenaIzvanOpsega(int);

void PrikaziOcenePoStudentima(OCENE);
void PrikaziOcenePoPredmetima(OCENE);
void PrikaziOceneTabelarno(OCENE);
float ProsecnaOcenaSvihStudenata(OCENE);
void ProsecnaOcenaPoStudentu(OCENE, PR_OC_PO_STUD);
void ProsecnaOcenaPoPredmetu(OCENE, PR_OC_PO_PRED);

void PrikaziProsecnaOcenaSvihStudenata(float);
void PrikaziProsecnaOcenaPoStudentu(PR_OC_PO_STUD);
void PrikaziProsecnaOcenaPoPredmetu(PR_OC_PO_STUD);

int main(void){
OCENE ocene;

UnesiOcene(ocene);

PrikaziOcenePoStudentima(ocene);
PrikaziOcenePoPredmetima(ocene);
PrikaziOceneTabelarno(ocene);

//float pr_oc = ProsecnaOcenaStudenata(ocene);


//printf("\nProsecna ocena svih studenata je %.2f", pr_oc);
PrikaziProsecnaOcenaSvihStudenata(ProsecnaOcenaSvihStudenata(ocene));

PR_OC_PO_STUD pr_oc_po_st;
ProsecnaOcenaPoStudentu(ocene, pr_oc_po_st);
PrikaziProsecnaOcenaPoStudentu(pr_oc_po_st);

PR_OC_PO_PRED pr_oc_po_pr;
ProsecnaOcenaPoPredmetu(ocene, pr_oc_po_pr);
PrikaziProsecnaOcenaPoPredmetu(pr_oc_po_pr);

return EXIT_SUCCESS;
}

bool OcenaIzvanOpsega(int oc) {


if ((oc >= 6) AND (oc <= 10)) return false;
return true;
}

void UnesiOcene(OCENE ocene) {


printf("\nUNOS OCENA\n");
for (USHORT stud = 0; stud < STUD; ++stud) {
printf("\tUnesite ocene za %d. studenta:\n", stud+1);
for (USHORT pred = 0; pred < PRED; ++pred) {
int ocena;
do {
printf("\t\tUnesite ocenu za %d. predmet (6 - 10): ", pred+1);
scanf("%d", &ocena); fflush(stdin);
} while ((ocena < 6) OR (ocena > 10)); // ILI: while (OcenaIzvanOpsega(ocena));
ocene[stud][pred] = ocena;
}
}
}

void PrikaziOcenePoStudentima(OCENE ocene){


printf("\nPRIKAZ OCENA PO STUDENTIMA\n");
for (USHORT stud = 0; stud < STUD; ++stud) {
printf("\tOcene za %d. studenta:\n", stud+1);
for (USHORT pred = 0; pred < PRED; ++pred) {
printf("\t\tOcena za %d. predmet: %d\n", pred+1, ocene[stud][pred]);
}
}
}

void PrikaziOcenePoPredmetima(OCENE ocene){


printf("\nPRIKAZ OCENA PO PREDMETIMA\n");
for (USHORT pred = 0; pred < PRED; ++pred) {
printf("\tOcene za %d. predmet:\n", pred+1);
for (USHORT stud = 0; stud < STUD; ++stud) {
printf("\t\tOcena za %d. studenta: %d\n", stud+1, ocene[stud][pred]);
}
}
}

void PrikaziOceneTabelarno(OCENE ocene){


printf("\nTABELARAN PRIKAZ OCENA\n");
printf("\t\t\t1. predmet\t2. predmet\t3. predmet\n");
printf("\t\t --------------------------------------------\n");
for (USHORT stud = 0; stud < STUD; ++stud) {
printf("\t%d. student |", stud+1);
for (USHORT pred = 0; pred < PRED; ++pred)
printf("\t\t%2d", ocene[stud][pred]);
printf(" |\n");
}
printf("\t\t --------------------------------------------\n");
}

float ProsecnaOcenaSvihStudenata(OCENE ocene){


float suma = 0;
for (USHORT stud = 0; stud < STUD; stud++)
for (USHORT pred = 0; pred < PRED; pred++)
suma = suma + ocene[stud][pred];
return suma/(STUD * PRED);
}

void ProsecnaOcenaPoStudentu(OCENE ocene, PR_OC_PO_STUD pops) {


for (USHORT stud = 0; stud < STUD; stud++) {
float suma = 0;
for (USHORT pred = 0; pred < PRED; pred++)
suma = suma + ocene[stud][pred];
pops[stud] = suma / PRED;
}
}

void ProsecnaOcenaPoPredmetu(OCENE ocene, PR_OC_PO_PRED popp) {


for (USHORT pred = 0; pred < PRED; pred++) {
float suma = 0;
for (USHORT stud = 0; stud < STUD; stud++)
suma = suma + ocene[stud][pred];
popp[pred] = suma / STUD;
}
}

void PrikaziProsecnaOcenaSvihStudenata(float ocena) {


printf("\nProsecna ocena svih studenata je %.2f", ocena);
}

void PrikaziProsecnaOcenaPoStudentu(PR_OC_PO_STUD pr_oc_po_st) {


printf("\nProsecna ocena svakog studenta pojedinacno:");
for (USHORT stud = 0; stud < STUD; ++stud)
printf("\n\tProsecna ocena %d. studenta je %4.2f ", stud+1, pr_oc_po_st[stud]);
}

void PrikaziProsecnaOcenaPoPredmetu(PR_OC_PO_PRED pr_oc_po_pr){


printf("\nProsecna ocena za svaki predmet pojedinacno:");
for (USHORT pred = 0; pred < PRED; ++pred)
printf("\n\tProsecna ocena %d. predmeta je %4.2f ", pred+1, pr_oc_po_pr[pred]);
}
/*
**
** DATOTEKA : P4_pokazivaci_1.c
** OPIS : Napisati program u programskom jeziku C koji
** prikazuje upotrebu pokazivaca.
** DATUM : 24.03.2015.
**
** Copyright (C) FON-LSI, 2015.
*/
#include <stdio.h>

int main(void){

int x = 10;
int * p = NULL;

p = &x;
*p = 20;
x = 30;

//====================================================================
x = 10;
p = NULL;
printf("Adresa promenljive x je: &x = %p \n", &x);
printf("Vrednost promenljive x je ceo broj: x = %d \n\n", x);

printf("Adresa promenljive p je: &p = %p \n", &p);


printf("Vrednost promenljive p je NULL adresa: p = %p \n\n", p);

p = &x;
printf("Naredba: p = &x; \n");
printf("Posledica: *p = x; \n\n");

printf("Adresa promenljive p je: &p = %p \n", &p);


printf("Vrednost promenljive p je adresa: p = %p \n", p);
printf("Vrednost promenljive *p je ceo broj: *p = %d \n\n", *p);

printf("Vrednost promenljive p je adresa promenljive x:\n");


printf("\tp = &x <=> %p = %p \n\n", p, &x);

printf("Vrednost promenljive na koju pokazuje p (to jest: *p) je vrednost promenljive x:\n");
printf("\t*p = x <=> %d = %d\n\n", *p, x);

printf("Vrednost na adresi promenljive x je sama promenljiva x\n");


printf("*(&x) = x <=> %d = %d\n\n", *(&x), x);

*p = 20;
printf("Naredba: *p = 20; \n");
printf("Nova vrednost promenljive x je: %d \n", x);
printf("Nova vrednost promenljive *p je: %d \n", *p);

x = 30;
printf("Naredba: x = 30; \n");
printf("Nova vrednost promenljive x je: %d \n", x);
printf("Nova vrednost promenljive *p je: %d \n", *p);

return 0;
/*
** DATOTEKA : P4_pokazivaci_2.c
** OPIS : Napisati program u programskom jeziku C koji
** prikazuje pravljenje i uništavanje dinamickih
** promenljivih upotrebom pokazivaca.
** DATUM : 24.03.2015.
**
** Copyright (C) FON-LSI, 2015.
*/
#include <stdio.h>
#include <stdlib.h>

int main(void) {
int *p1, *p2;

p1 = malloc(sizeof(int));
*p1 = 10;

p2 = p1;
*p2 = *p2 + 5;
*p1 = *p1 + 2;

printf("*p1 = %d, *p2 = %d\n", *p1, *p2);

p2 = NULL;
free(p1);

return 0;
}

/*
** DATOTEKA : P5_pokazivaci_3.c
** OPIS : Napisati program u programskom jeziku C koji
** prikazuje upotrebu pokazivaca na funkcije.
** DATUM : 24.03.2015.
**
** Copyright (C) FON-LSI, 2015.
*/
#include <stdio.h>

typedef char * STRING;


typedef int (* OPERACIJA)(int, int);

int saberi(int, int);


int pomnozi(int, int);
int operacija(STRING, OPERACIJA, int, int);

int main(void){
int rezultat, // podatak
*pok = &rezultat; // pokazivač na podatak
OPERACIJA pf; // pokazivač na funkciju
// Prethodna deklaracija može da se zapiše i ovako:
// int (* pf)();
// Ili preciznije:
// int (* pf)(int, int);

pf = saberi;
rezultat = (*pf)(11, 7);
printf("\nZbir = %d", rezultat);

pf = pomnozi;
*pok = (*pf)(11, 7);
printf("\nProizvod = %d\n", *pok); // pristup pokazanoj promenljivi = vrednost promenljive

pf = saberi;
rezultat = operacija("saberi()", pf, 11, 7);
printf("\nZbir = %d\n\n", rezultat);

return 0;
}

int saberi(int s1, int s2) {


printf("\nFunkcija: saberi()" );
return s1 + s2;
}

int pomnozi(int p1, int p2){


printf("\n\nFunkcija: pomnozi()");
return p1 * p2;
}

int operacija(STRING txt, OPERACIJA pf, int i1, int i2) {


printf("\nOperacija: %s", txt);
return (*pf)(i1, i2); // pristup pokazanoj f-ji = izvršenje f-je
}

/*

========================
CONSOLE PROGRAM OUTPUT:
========================

Funkcija: saberi()
Zbir = 18

Funkcija: pomnozi()
Proizvod = 77

OPERACIJA: saberi()
Funkcija: saberi()
Zbir = 18

Press any key to continue...

*/

You might also like