You are on page 1of 29

ТЕМА: ПОКАЖУВАЧИ

ДЕКЛАРАЦИЈА И ИНИЦИЈАЛИЗАЦИЈА НА ПОКАЖУВАЧКА ПРОМЕНЛИВА ОД


ОДРЕДЕН ТИП

Вовед

Големината на меморијата која им се доделува на променливите при нивното


сместување во меморијата зависи од нивниот тип.

Пример: int x;

При сместување на променливата x во меморијата, и се доделува меморија во


која ќе може да се запише најголемиот цел број од дефинираниот опсег на целите
броеви [-215,+215-1] бидејќи знаеме дека со int се означува 4 бајтен цел број.

Пример: float y; или double y;

Слично со декларацијата на променливата y како реален број , неа и се доделува


меморија во која ќе може да се смести најголемиот реален број од дефинираниот
опсег за реални броеви од типот float т.е. double.

Променливите можат да се сместуваат во меморијата на два начина:

- статички
- динамички

Типовите на податоци што се користат во програмирањето можат да бидат:


 статички - се оние чија големина е однапред дефинирана (најчесто на почетокот
на програмата). Тие се сместени на фиксни локации во меморијата
 динамички - се оние чија големина и/или структура се менува во текот на
извршувањето на програмата. Тие не се сместуваат на фиксна локација во
меморијата, туку на локација која во моментот на нивното креирање е слободна.

Динамичките типови на податоци можат да бидат:

 со променлива големина (низа битови, низа знаци, општа низа, множество,


куп, ред и датотека)
 со променлива структура (листа, дрво, покажувач и објект).

Прашање:
-Каков тип променливи досега сме користеле во програмите? Одговор: Статички

1
Главен дел
ДИНАМИЧКИ ПРОМЕНЛИВИ
ПОКАЖУВАЧ
При преведувањето на програмата потребно е преведувачот да ги знае
сите променливи и нивниот тип. Променливите кои се создаваат за време на
извршување на програмата, а потоа се бришат се нарекуваат динамички
променливи. Динамичките променливи кои добиваат податоци од тип покажувач
се наречени променливи од тип покажувач или само покажувачи. При
креирањето, динамичките променливи се сместуваат во слободната внатрешна
(динамичка) меморија, наречена heap-меморија.

Користењето на променливи од тип покажувач нуди две битни погодности


во однос на меморијата:

1. Се проширува меморискиот простор што може да се користи за податоци во


една програма;

2. Со користење на покажувачките променливи во динамичката меморија,


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

Декларација на покажувачи

Покажувачите се променливи чии вредности се мемориски адреси и се


викаат покажувачки променливи или променливи од тип покажувач.
Покажувачот наместо податок содржи локација т.е. адреса на податокот што се
наоѓа во динамичката меморија. Покажувачите се декларираат на следниот начин:

тип *име_на_покажувач;

каде што: тип- е типот на променлива на кои ќе покажува покажувачот, а “ * “ е


знак за декларација на покажувач т.е покажувачка променлива.

Пример: int *pok;

Со ова се декларира покажувачот (покажувачката променлива) pok, кој може да


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

Забелешка: важно е да се каже дека, при креирање на покажувачи (int *pok),


позицијата на која се наоѓа знакот '*' нема никакво влијание на извршувањето на
програмата. Имено, знакот '*' може да се наоѓа веднаш по податочниот тип (int*
pok), помеѓу податочниот тип и името на покажувачот.

2
(int * pok) или до името на покажувачот (int *pok) - сите наредби ќе имаат ист
ефект.

Aдресен оператор &

Операторот & се нарекува адресен оператор. Тој е унарен оператор, кој ја враќа
адресата на операндот по него.

Пример:

int y=5;
int *ypok;
ypok=&y; // на покажувачот ypok му се доделува адресата на променливата у

Оператор за дереференцирање *
Променливата ypok (од предходниот пример) може да се означи и преку
покажувач ypok со *ypok. Во овој случај операторот * се нарекува индиректен
оператор или оператор за дереференцирање – тогаш тој ја враќа вредноста
на променливата на која покажува неговиот операнд.

Операторите * и & се комплементни т.е. важи следното: &*pok=*&pok

Иницијализација на покажувачи

Покажувачите треба да се иницијализираат или при нивна декларација или


во некоја наредба за доделување.

Пример со наредбата: poka=&a;

се иницијализира покажувачот poka – што значи дека покажувачот веќе има


некаква вредност, во овој случај адресата каде што е сместена променливата а.

Еден покажувач може да се искористи повеќе пати (во една иста програма) и
притоа (во различни моменти) да покажува кон различни променливи од ист
тип и мемориски локации.

Доколку сакаме експлицитно да изразиме дека одреден покажувач не


покажува кон ништо, тој може да биде иницијализиран на 0 (NULL).
Стандардот гарантира дека не постои податок во компјутерската меморија
со адреса 0.

NULL покажувач не е исто што и неиницијализиран покажувач!

3
Примери за користење на операторите & и *

Прашање:
1. Кон што покажуваат покажувачите p и q во следниот програмски сегмент?
    int a = 100, b = 200;
    int *p = &a, *q = &b;
    p = q;
Одговор:
(т.е. и p и q ќе покажуваат кон променливата b).

Пример 1 :
#include <iostream>
using namespace std;
int main()
{
int a=40;
int *pok; //pokazuvac pokazuva na adresata na a
cout<<a<<endl;
pok=&a; //ipa ja sodrzi adresata na a
cout<<pok<<endl; //ja pecati adresata na a
cout<<*pok<<endl; // se pecati 40 bidejki vrednosta na taa adresa e 40

*pok=120 ; //vrednosta na adresata na koja pokazuva pokazuvacot ipa e 120


cout<<a<<endl; // se pecati 120 , bidejki vrednosta na a e promeneta preku pokazuvacot ipa
cout<<pok<<endl; //se pecati istata adresa ipa
return 0;
}

Резултат од програмата:
40
0x22fe44
40
120
0x22fe44

Пример 2:
#include <iostream>
using namespace std;
int main()
{
int a = 5, b = 2;
int *pa = &a, *pb; // иницијализација на покажувач pa, и декларација на покажувач pb
pb = &b; //иницијализација на покажувач рb
*pa = 3;
cout << a << " " << *pa << " " << *pb << endl; // печати 3 3 2
*pb = -1;
cout << b << " " << *pb << endl; // печати -1 -1
*pa = *pb;
cout << a << " " << b << endl; // печати -1 -1
4
return 0;
}

Резултат од програмата:
332
-1 -1
-1 -1

Пример 3:
Што ќе се печати со следната програма?
#include <iostream>
using namespace std;
int main()
{
int x;
int *pok;
x=7;
pok=&x;
cout<<" Adresata na x e" << &x << "\n Vrednosta na pok e " << pok;
cout<<"Vrednosta na x e "<< x << "\n Vrednosta na *pok e "<< *pok;
return 0;
}
Заклучок:
Разликата помеѓу операторите '&' и '*' може да се дефинира како:
 Со & се чита и ја враќа адресата на одреден податок.
На пример, &x ја враќа адресата на x.
 Со * се чита вредноста покажувана од покажувачот и ја враќа вредноста
која се чува на одредена адреса.
На пример, *p служи за пристап до вредноста покажувана од покажувачот p.

Забелешка:
Големината на еден покажувач зависи од архитектурата на компјутерскиот систем
на кој се извршува програмата и од оперативниот систем: 32-битен компјутерски
систем ќе користи 32-битни мемориски адреси (и, соодветно, покажувачите ќе
зафаќаат 4 бајти податочен простор), додека 64-битен компјутерски систем ќе
користи 64-битни мемориски адреси (и, соодветно, покажувачите ќе зафаќаат 8
бајти податочен простор). Ова на никој начин не влијае на однесувањето на
покажувачите: тие и понатаму можат да се искористат за пристап до податокот на
кој покажуваат - без разлика на неговата големина.

Домашна работа:
Прашања:
1. Одговори на кој тип податоци припаѓаат покажувачите во С++?
1 . Динамички тип. *

2 . Статички тип.


3 . Класен тип.

5
4 . Структурен тип.

2. Кој знак треба да се постави пред името на променливата за да ја дознаеме


нејзината мемориска локација (адреса)?
1 . $
2 .  & *
3 .  *
4 .  #

3. Каков израз треба да се напише ако е потребно да се декларираат два


покажувачи  а1 и а2 кои ќе покажуваат кон int вредности?
1 .  int  *a1, *a2; *

2 .  int* a1, a2;


3 . *int a1, a2;
4 .  int & a1, a2;

4. Определи со кој од наведените изрази правилно е напишана декларација на


покажувач.
1 . int x;
2 . int *x; *
3 . int &x;
4 . ptr x;

5. Одговори што е дефинирано со следниот израз: string *x, y;


1 .  x е покажувач на стринг, y е стринг. *
2 .  y е покажувач на стринг, x е стринг.
3 .  x и y се покажувач на стринг.
4 .  погрешно деклариран покажувач.

6. Со кој од наведените изрази е неправилно дефиниран покажувач?


1 . int i; double* dp = &i; *
2 . int *ip;
3 . string s, *sp = 0;
4 . int *pi = 0;

7. Со кој од наведените изрази правилно е напишана декларација на покажувач?


1 . int x;

6
2 . int *x; *
3 . int &x;
4 . ptr x;

РЕЗЕРВИРАЊЕ МЕМОРИЈА(АЛОКАЦИЈА) СО ПОМОШ НА ПОКАЖУВАЧ (NEW)

Вовед
Прашања:

1. Од каков тип може да бидат променливите?


2. Како се нарекуваат променливите кои содржат мемориски адреси како
нивни вредности?
3. Како се декларира динамичка променлива од тип покажувач?
4. Одговори кој од наведените изрази означува мемориска адреса на
целобројна променлива a.
а) &a б) *a в) а г) address(a)

Главен дел
Алокација(резервирање) на меморија
и делокација(празнење) на маморија

Наредбите new и delete


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

Во C++, тоа се прави со користење на операторите new (доколку сакаме да


алоцираме простор за само еден елемент) или new[N] (доколку сакаме да
алоцираме простор за N елементи).
Резултатот од овие операции е покажувач до блокот меморија кој бил резервиран.

Многу е важно, по користењето на резервираната меморија (откако истата повеќе


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

Во C++, ова се прави со користење на операторите delete pok (за еден елемент) и
delete[ ] pok (за повеќе елементи).

Наредбата new има форма :

покажувач = new тип на податок;

7
Со неа во меморијата се креира променлива од соодветен тип и на покажувач му
се доделува адресата на креираната променлива. Во спротивно покажувачот
добива вредност NULL.
Пример со наредбите:
int *ip;
ip=new int;

прво се декларира покажувач ip , а потоа во меморијата се креира неименувана


променлива и нејзината адреса му се доделува на покажувачот ip.

Вредноста на неименуваната променлива може да се додели на некој од


следните начини:

int *ip=new int(25); int *ip; int *ip;


ip=new int(25); ip=new int;
*ip=25;

при што се добива следната сoстојба во меморијата:

Со наредбата:
delete ip;
се ослободува меморијата на променливата на која покажувал покажувачот ip,
при што тој останува недефиниран.
При бришење на низи се користи наредбата:
delete [ ] pok;

Пример:
#include <iostream> #include <iostream>
using namespace std; using namespace std;
int main() int main()
{ {
int *ip; int N = 100;
ip = new int; parr = new int[N]; //niza od 100
*ip = 2; elementi
cout << *ip << endl; //pecati 2 pок[5] = 3;
delete ip; //se osloboduva memorijata na adresata ip cout << pок[5] << endl; //pecati 3
cout << *ip << endl; delete [] pок;
return 0; return 0;
} }

8
Поради фактот што секој компјутерски систем има ограничено количество на
меморија, понекогаш е можно да не успее динамичкото алоцирање на меморија
(new int[N]). Притоа, доколку системот не успее да резервира доволно количество
меморија, програмата ќе прекине со извршување и ќе јави грешка (runtime error).
Доколку сакаме самите да го решиме проблемот со евентуалниот недостаток на
меморија, тогаш треба да го искористиме специјалниот параметар (nothrow) -
дефиниран во датотеката <new>, и самите да провериме дали алокацијата на
меморија завршила успешно - доколку се случил проблем, покажувачот ќе има
вредност 0 (NULL).
Пример:
#include <iostream>
#include <new>
using namespace std;
int main()
{
int N = 2000000000;
int *pок = new (nothrow) int[N];
if (pокr == 0)
{
cout << "Greshka: Nema dovolno memorija!" << endl;
}
else
{
naredbi so nizata;
}
delete [] pok;
return 0;
}
Домашна работа
1. Кој од наведените резервирани зборови се користи за алоцирање (алокација)
на меморија?
1 . new *
2 . malloc
3 . create
4 . value

2. Кој од наведените  резервирани зборови се користи за делокација на меморија?


1 . delete *
2 . free

9
3 . clear
4 . remove

3. Што ќе се печати со следниот програмски сегмент?


#include <iostream>
using namespace std;
int main()
{
int *a=new int;
int *b=new int;
*a=5;
*b=*a;
b=a;
*b=10;
cout<<*a;
return 0;
}

ОПЕРАТОРИ ЗА ПОКАЖУВАЧИ

Вовед
Веќе кажавме како се користат операторите * и &.

Прашања:
1. Одговори кој е резултатот од извршување на следниот програмски код во
програмскиот јазик С++.
    int a = 100, b = 200;
    int *p = &a, *q = &b;
    p = q;
1 . Покажувачот p покажува кон променливата b *
2 . Вредноста на променливата b се доделува на променливата a.
3 . Вредноста на променливата а се доделувана променливата b.
4 .  Покажувачот q покажува конпроменливата а.

2. Определи кој е резултатот од извршување на следниот програмски сегмент во


програмскиот јазик С++.
float  pr = 2.25;  
float  *pok;       
pok = &pr;      
cout << *pok << endl;
1 . 0
2 . Адресата на променливата  pok.

10
3 . 2.25 *
4 . Адресата на променливата pr.

Главен дел

Операторите за покажувачи се дадени во следната табела:

Оператор Асоцијативност Тип

[ ] () Од лево на десно Највисок приоритет


Од лево на десно
, Запирка
Од лево на десно
*,/,% Мултипликативен
Од лево на десно
+ - Адитивен
Од лево на десно
< <= > >= Релационен
Од лево на десно
== , != Еднаквост, нееднаквост
Од лево на десно
&& Логичко И
Од лево на десно
|| Логичко ИЛИ
Од десно на лево
?: Условен
Од десно на лево
= , += , -= , *= , /= , %= За доделување
Од десно на лево
++ , -- , + - , ! , * , & (tip) Унарен

Задачи за вежбање:
Пример 1:
Во следниот пример покажувачот pok се користи да покажува кон различни
променливи од ист тип прво кон c, а потоа кон d:
#include <iostream>
using namespace std;
int main()
{
float c = 8.0123, d = 1.12345;
float *pok;
pok = &c;
(*pok) += 2.0; //vrednosta na promenlivata c e zgolemena za 2.0
cout << *pok << endl; //pecati 10.0123
pok = &d; //sega pok ja prima adresata na promenlivata d
(*pok) --; // d se namaluva za 1
cout<< *pok <<endl; // pecati 0.12345
return 0;
}
11
Пример 2:
Определи кој е резултатот од извршување на следната програмa.
#include <iostream>
using namespace std;
int main()
{
double  a = 6.125, b = 5.125;
double *p1, *p2;
p1 = &a;
p2 = &b;
(*p1) += 3.0;
*p2 = *p1;
cout <<*p1 << "   " << *p2;
return 0;

Пример 3:
Определи што ќе се отпечати по извршување на следната програма.
#include<iostream>
using namespace std;
int main()
{
  int x[5]={1,2,3,4,5};
  int *p=x;
  int i;
  for(i=0;i<2;i++)
   {
     int temp=*(p+i);
     *(p+i)=*(p+4-i);
     *(p+4-i)=temp;
    } 
  for(i=0;i<5;i++) cout<<x[i]<<"\t";
  return 0;
}

Пример 4:
Одговори што ќе се прикаже на екранот по извршување на следната програмa.
#include<iostream>
using namespace std;
int main ()
{
int m=10, n=20;
int *p1, *p2;
p1=&m;
p2=&n;
12
*p1+=5;
cout<<"*p1= "<<*p1;
return 0;
}

Пример 5:
Одговори што ќе се прикаже на екранот по извршување на следната програмa.
#include<iostream>
using namespace std;
int main ()
{
   int  var = 20; 
   int  *ip;        
   ip = &var;       
   cout << *ip << endl;
   return 0;
}

Пример 6:
Одговори што ќе се прикаже на екранот по извршување на следната програма.
#include<iostream>
using namespace std;
int main ()
{
int m=10, n=20;
int * p1, * p2;
p1=&m;
p2=&n;
*p1+=5; 
cout<<"*p1="<<*p1;
return 0;
}

Пример 7:
Определи кој е резултатот по извршување на следнaтa програмa.
#include <iostream>
using namespace std;
int main()
{
int a = 15, b = 2;
int *pa, *pb;
pa = &a;
pb = &b;
*pa = 23;
cout << a << "  " << *pa << "  " << *pb;
return 0;
}

13
КРЕИРАЊЕ НИЗА ВО ДИНАМИЧКА МЕМОРИЈА СО ПОМОШ
НА ПОКАЖУВАЧИ НА НИЗИ
Вовед
Веќе кажавме дека употребата на покажувачите овозможува флексибилност во
програмирањето, бидејќи покажувачката променлива која ја содржи адресата на
еден динамички податок може да се пренасочи да покажува на друг динамички
податок од ист тип. Не може да покажува на друг тип податок.

Познато е дека декларацијата на покажувач се врши на пример со наредбите:

int a;
int *pок;

Додека со наредбата:

p=new int;

се резервира нова мемориска локација(адреса) во која ќе биде сместена


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

Главен дел
ПОКАЖУВАЧИ И НИЗИ

Прашања:

1. Како се декларира низа?


2. Како се иницијализира низа?
3. Како се внесува низа преку тастатура?
4. Како се декларира динамичка променлива од тип покажувач?

Доколку е декларирана и иницијализирана една низа со име niza, и покажувач pok


со наредбите:
int niza[4]={5,2,6,8};
int *pok;
pok=niza;

- На покажувачот pok му се доделува вредноста на адресата на почетниот


елемент на низата т.е. адресата на niza[0].

14
- Вредноста на почетниот елемент од низата може да се добие со:
*niza или niza[0].

- Адресата на i-иот елемент од низата се добива со :


&niza[i] или со (pok+i)

- Вредноста на i-иот елемент од низата се добива со:


niza[i] или со *(pok+i)

Пример 1:
Пренесување на адресите од една низа во низа со покажувачи и нивно
печатење.

#include <iostream>
using namespace std;
int main ()
{
const int m = 3;
int niza[m] = {10, 100, 200};
int *pok[m];
for (int i = 0; i < m; i++)
pok[i]=&niza[i]; // pok[i] se adresite na elementite od nizata

cout<<"ADRESI VREDNOSTI"<<endl;
cout<<"__________________________"<<endl;
for (int i = 0; i < m; i++)
cout << pok[i]<<" "<<*pok[i] << endl; //pecatenje na adresite i na vrednostite na elementite od nizata
return 0;
}

Пример 1 на друг начин


#include <iostream>
using namespace std;
const int m = 3;
int main ()
{
int niza[m]={10,100,200};
int *pok;
pok=niza;
cout<<"ADRESI VREDNOSTI"<<endl;
cout<<"__________________________"<<endl;
for(int i = 0; i < m; i++)
cout<<pok+i<<" "<<*(pok+i) << endl; //pok pokazuva na pok+i -tata adresa i pecatenje na
vrednostite
return 0;
15
}

Пример 2:
Определи што ќе се прикаже на екранот по извршување на следната програма .
#include <iostream>
using namespace std;
int main ()
{
double niza[4] = {1000.0, 2.0, 3.4, 17.0};
double *pok;
pok = niza;
for ( int i = 0; i < 4; i++ )
cout<<*(pok+i)<<endl; //se pecatat elementite od niza
return 0;
}

Пример 3:
Определи што ќе се прикаже на екранот по извршување на следната програма .
#include <iostream>
#include <cstring>
using namespace std;
const int MAX = 4;
int main ()
{
string *ime[MAX] = {“Petar”, “Nikola”, “Tamara”, “Stefan”};
for (int i = 0; i < MAX; i++)
{
cout <<&ime[i]<<” ”<< ime[i] << endl;
}
return 0;
}

Пример 4:
Определи што ќе се прикаже на екранот по извршување на следната програма .
#include <iostream>
using namespace std;
int main ()
{
int number[5];
int * p, n;
p = number; *p = 10;
p++; *p = 20;
p = &number[2]; *p = 30;
16
p = number + 3; *p = 40;
p = number; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << number[n] << ", "; // Се печати 10, 20, 30, 40, 50,
return 0;
}

Пример 5:
Определи што ќе се прикаже на екранот по извршување на следната програма .
#include <iostream>
using namespace std;
int main ()
{
int niza[5] = {10, 100, 200, 3000, 5000};
int i, *pok;
pok = niza;
for ( i = 0; i < 5; i++)
{
cout<<”Adresata na niza [“<<i<<”]=”<< pok;
cout<<”Vrednosta na niza [“<<i<<”]=”<< *pok;
pok++; // придвижување на покажувачот на следна локација
}
return 0;
}

Пример 6:
Определи што ќе се прикаже на екранот по извршување на следната програма .
#include <iostream>
using namespace std;
int main ()
{
int a[5]={1,2,3,4,5};
int *p;
p=a;
cout<<*p<<endl;
return 0;
}

Што треба да се поправи во програмата за да се печати целата низа?

Пример 7:
Определи кој е резултатот по извршување на  следната програма. 
#include <iostream>
using namespace std;
int main()
{
int a [] = {10, 20, 30, 40, 50, 60, 70};
17
int *pok = a;
for (int i=0; i<5; i++)
{
pok++;
cout << *pok << ", ";
}
return 0;
}

Пример 8.

#include <iostream>
using namespace std;
int main ()
{
int number[5];
int * p, n;
p = number; *p = 10;
p++; *p = 20;
p = &number[2]; *p = 30;
p = number + 3; *p = 40;
p = number; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << number[n] << ", ";
return 0;
}

Пример 9:

    #include <iostream>    #include<iostream>


   using namespace std; using namespace std;
    int main() int main()
    { {
        int a = 5, b = 10, c = 15;   int x[5]={1,2,3,4,5};
        int *arr[ ] = {&a, &b, &c};   int *p=x;
        cout << arr[1];   int i;
        return 0;   for(i=0;i<2;i++)
    }    {
     int temp=*(p+i);
     *(p+i)=*(p+4-i);
А. 15      *(p+4-i)=temp;
Б. 10     } 
В. 5   for(i=0;i<5;i++) cout<<x[i]<<"\t";
Г. Адресата на a[0]   return 0;
}

А. 5
Б. 1
В. 54321
Г. 345
18
АДРЕСНА АРИТМЕТИКА (АРИТМЕТИКА СО ПОКАЖУВАЧИ)

Вовед

1.Колкава меморија зафаќа променлива од тип int?


2.Колкава меморија зафаќа променлива од тип float, а колкава меморија зафаќа
променлива од тип double?
3. Колкава меморија зафаќа променлива од тип char?

Напомена: Колкав мемориски простор зафаќаат различните типови на податоци е битно


да се знае при извршување на аритметичките операции со покажувачи.

ШЕМАТСКИ ПРИКАЗ НА ОСНОВНИТЕ ТИПОВИ ПРОМЕНЛИВИ


ЗАФАТЕНОСТ ОПСЕГ НА БРОЕВИ
ТИП ЗАПИС ВО C++ НА
МЕМОРИЈА
int 4B (32b) -2147483648 до 2147483647
long int или
4B (32b) -2147483648 до 2147483647
long
-9223372036854775808 до
ЦЕЛИ БРОЕВИ long long int или 9223372036854775807
4B (32b)
long long
short int или -32768 до 32767
2B (16b)
short
РЕАЛНИ БРОЕВИ
(ДЕЦИМАЛНИ
float 4B (32b)
БРОЕВИ СО 7
ДЕЦИМАЛИ)
РЕАЛНИ БРОЕВИ
(ДЕЦИМАЛНИ
double 8B (64b)
БРОЕВИ СО 15
ДЕЦИМАЛИ)
ЗНАЦИ char 1B (8b) -128 до 127
две вредности - точно (true) и
ЛОГИЧКИ ТИП bool 1B (8b) погрешно (false)

Најчесто користени оператори се следните аритметички оператори за


покажувачи: ++, --, +, -, +=, -=

Ако на покажувачот се употреби операторот pok++, тој ќе се зголеми за 4


адреси, ако тој покажува на целобројна променлива, затоа што целите
броеви од тип int зафаќаат 4B.

19
Според дадената слика имаме:

int v[5]; //декларација на низа v од цели броеви


int *vPtr ; //декларација на покажувач vPtr на низа v од цели броеви
vPtr = v; //vPtr покажува на локација 3000
vPtr += 2; //ќе се оди на локација 3008 бидејќи кај int адресите се зголемуваат за 4 т.е.
//3000 + 2 * 4

Ако покажувачот е на локација 3016 со наредбата vPtr -= 4; тогаш покажувачот го


враќаме на локација 3000.
Со изразите ++vPtr и vPtr++ се носи покажувачот до следниот елемент во низата.
Со изразите --vPtr и vPtr-- се носи покажувачот до предходниот елемент во низата.

Ако се дефинираат два покажувачи кон низата од цели броеви т.е. vPtr1 и vPtr2,
при што vPtr1 е на локација 3000, а vPtr2 е на локација 3008 тогаш со наредбата
vPtr2-vPtr1 ќе се добие 2.
Тоа се добива со формулата (3008-3000)/4 =2 затоа што целите броеви зафаќаат
по 4B.

Забелешка: Адресите каде се зачувуваат податоците во динамичка меморија се


претставени со хексадекаден број пр: bff5a400 , bff5a3f6 и за колку ќе се зголемува
(намалува) вредноста на адресата зависи од типот на податокот т.е.: кај тип на
податок char – адресите се зголемуваат за 1, кај тип на податок short int –
адресите се зголемуваат за 2, кај тип на податок int – адресите се зголемуваат за
4, кај тип на податок float – адресите се зголемуваат за 4, кај тип на податок double
– адресите се зголемуваат за 8 и.т.н.

Пример 1:
Во програмата се печатат адресите и вредностите на низата
#include <iostream>
using namespace std;
int main ()
{
int niza[5];
int n, i, *pok;
cin>>n;
for(i=0;i<n;i++)
cin>>niza[i];

pok = niza;
i=0;
20
while ( pok <= &niza[n-1] ) // sporeduvanje na pokazuvac
{
cout<<"Adresata na niza["<<i<<"]="<< pok<<endl;
cout<<"Vrednosta na niza["<<i<<"]="<< *pok<<endl;
pok++; // pridvizuvanje na pokazuvac na sledna adresa
i++;
}
return 0;
}

Пример 2:
Во програмата се наоѓа најголемиот елемент на една низа цели броеви со помош
на покажувач на низа pok.
#include <iostream>
using namespace std;
int main()
{
int niza[5];
int n, i, *pok, max;
cin>>n;
for(i=0;i<n;i++)
cin>>niza[i];

pok = niza; //pok ja prima adresata na pocetniot element na nizata


max=niza[0];

while (pok <= &niza[n-1] ) // sporeduvanje na pokazuvac


{
if(*pok>max) max=*pok;
pok++;
}
cout<<"Najgolem e "<<max<<endl;
return 0;
}

Покажувач на покажувач
Покажувач на покажувач е форма на повеќекратно покажување кон некоја
променлива. Кога ќе дефинираме покажувач на покажувачот, првиот покажувачот
ја содржи адреса на вториот покажувач, што ја кажува локацијата која ја содржи
вистинската вредност на променливата како што е прикажано на сликата:

Пример 2:

#include <iostream>
using namespace std;
int main ()
{
int v;
int *pок;
int **ppок;
21
v = 3000;
pок = &v;
ppок= &pок;
cout << "Vrednosta na promenlivata e :" << v << endl;
cout << "Vrednosta na pok :" << pok << endl;
cout << "Vrednosta na *pok :" << *pok << endl;
cout << "Vrednosta na ppok :" << ppok << endl;
cout << "Vrednosta na **ppok :" << **ppok << endl;
return 0;
}

ПОКАЖУВАЧИ И ФУНКЦИИ

Изработка на едноставни програми кои вклучуваат адресна аритметика

1. Која вредност ќе ја има променливата y по извршувањето на следниот


програмски сегмент?
    int x = 10; Одговор:
int *px = &x, y;
*px = 3;
y = x;

2. Ако важи следната декларација

int a[100], *pa, *qa;

Кои од дадените наредби се точни?


pa=a;  qa=pa; 
a=pa; *qa=*pa; 
pa++;  pa=&a;
a++; pa=*qa;

3. Овие две програми даваат ист резултат n=240

#include <iostream> #include <iostream>


using namespace std; using namespace std;
void funcOne(int &n) void funcOne(int *n)
{ {
n = 240; *n = 240;
} }
int main() int main()
{ {
int n = 310; int n = 310;
funcOne(n); funcOne(&n);
cout << "n = " << n << endl; cout << "n = " << n << endl;
return 0; return 0;
} }

22
4. Размена на местата на две променливи без покажувач и со покажувач
#include <iostream> #include <iostream>
using namespace std; using namespace std;
void swap(int a,int b) void swap(int *a,int *b)
{ {
int tmp; int tmp;

tmp=a; tmp=*a;
a=b; *a=*b;
b=tmp; *b=tmp;
} }

int main() int main()


{ {
int x,y; int x,y;

x=5; x=5;
y=6; y=6;
swap(x,y); swap(&x,&y);
cout<<"x="<<x<<" y="<<y<<endl; cout<<"x="<<x<<" y="<<y<<endl;
return 0; return 0;
} }
6 y=5

5. Дали овие две програми даваат ист резултат?


Повикување на функција со аргументи Повикување на функција преку
(вредности референца со покажувач аргумент
#include <iostream> #include <iostream>
using namespace std; using namespace std;
int cub(int n) void cub( int *n )
{ {
return n * n * n; *n=(*n) * (*n) * (*n);
} }
int main() int main()
{ {
int br; int br;
cout<<"Vnesi broj "; cout<<"Vnesi broj ";
cin>>br; cin>>br;
cout<<br<<" na kub= "<<cub(br)<<endl; cub(&br);
return 0; cout<< br<<" na kub= "<<br<<endl;
} return 0;
}
23
6. Што ќе се отпечати со следната програма?
//niza I funkcija so argument pokazuvac Одговор:
#include <iostream>
using namespace std;
float Average(float *arr)
{
int i;
float avg, sum=0;
for (i = 0; i < 5; i++)
{
sum += arr[i];
}
avg = sum / 5;
return avg;
}
int main ()
{
float niza[5] = {10.5, 2.7, 3.1, 17.4, 50.23};
float av;
av = Average( niza ) ;
cout << "Srednata vrednost e: " << av << endl;
return 0;
}

Вежби со покажувачи , низи и функции

При преносот како аргумент на функција int a[ ] и int *a се однесуваат потполно


исто.

Следните функции извршуваат иста работа


int clear1(int a[], int size) int clear2(int *a,int size)
{ {
int i; int *p;
for(i=0;i<size;i++) for(p=&a[0];p<&a[size];p++)
a[i]=0; *p=0;
return 0; return 0;
} }

int clear3(int *a, int size) int clear4(int a[], int size)
{ {
int i; int* p;
for(i=0;i<size;i++) for(p=&a[0];p<&a[size];p++)
a[i]=0; *p=0;
24
return 0; return 0;
} }

Што ќе се отпечати со следната програма?


#include <iostream> Одговор:
using namespace std;
int main()
{
char *c, recenica[50]="Recenica od tri
zbora";
c=recenica;
cout<<*(c+16)<<endl;
return 0;
}
z

Домашна работа

1. Креирајте програма во која се внесува низа a[i]n од целобројни елементи,


а потоа да се печати вредноста на секој елемент заедно со неговата
адреса.

2. Креирајте програма во која се внесува низа a[i]n од double елементи, а


потоа да се печати вредноста на секој елемент заедно со неговата
адреса.

Која разлика ја забележуваш во излезот на овие две програми?

Повторување и утврдување на темата


„ПОКАЖУВАЧИ“

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


адреса на целобројна променлива a.
1 .   a;
2 .  *a;
3 .  &a;
4 .   address(a);

2.  Како се нарекуваат променливите кои содржат мемориски


адреси како нивни вредности?
1 . Класи

25
2 . Адреси
3 . Покажувачи
4 . Графови

3.  Одговори кој од наведените изрази означува вредност


зачувана во адреса на која покажува покажувачот a.
1 . &a;
2 .  a;
3 .  val(a);
4 .  *a;

4. Каков израз треба да се напише ако е потребно да се


декларираат два покажувачи  а1 и а2 кои ќе покажуваат кон int
вредности?
1 .  int  &a1, &a2;
2 .  int* a1, a2;
3 . *int a1, a2;
4 .  int *a1, *a2;

5. Определи што е дефинирано со следниот израз.


    int (*fp)(char*)
Покажувач на функција која има аргумент од типот char* и
1 .
враќа int вредност.
2 . Покажувач на покажувач.
3 . Покажувач на низа од знаци.
Функција која има аргумент од типот char* и враќа
4 .
покажувач на податок од типот int.

6.   Одговори што е дефинирано со следниот израз. 


    string *x, y;
1 .  x и y се покажувачи на стринг.
2 .  y е покажувач на стринг, x е стринг.
3 .  x е покажувач на стринг, y е стринг.
4 .  погрешно деклариран покажувач.

7. Како треба да се дефинира покажувачот р,  како повратна

26
вредност да ја има адресата на променливата х?
1 . p=&x
2 .  p=*x
3 .  *p=&x
4 . p=**x

8. Определи на кој од наведените изрази соодветствуваат


наредбите  
ptr=&x; и y=*ptr;
во следниот програмскиот сегмент.
int *ptr;
int x,y;
ptr=&x;
y=*ptr;
1 . x=y;
2 . y=x;
3 . y=ptr;
4 . ptr=y;

9. Ако  x=3, y=4, определи колкава ќе биде вредноста на x и y по


извршување на следниот функциски повик  swap(&x,&y).
void swap(int*a, int*b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
1 . x=4 y=4
2 . x=3 y=4
3 . x=3 y=3
4 . x=4 y=3

10. Определи која вредност ќе ја има променливата y по


извршувањето на следниот програмски сегмент.
int x = 10;
int *px = &x, y;
*px = 3;
y = x;
1 . 0
2 . 10
3 . 7
4 . 3

27
11. Која вредност ќе се печати по извршување на следниот
програмски сегмент?
int a = 5;     
 int *p;   
 p = &a;  
 *p = 3;  
  cout << a << endl; 

1 . 0
2 . 5
3 . 8
4 . 3

12. Определи во кој од наведените програмски сегменти има Во број


погрешно дефинирани изрази во програмскиот јазик С++. 1
int a = 5;
int *b; double
1 . b = &a; *k;
double *k;
k = &a; треба да
се
double a = 5; замени
double *b; со
2 . b = &a;
double *k; int *k;
k = &a;
int a = 5;
int *b;
b = &a;
3 .
double c = 2.5;
double *k;
k = &c;
int a = 5;
int *b;
4 . b = &a;
int *k;
k = &a;

13. Состојбата на покажувачот е како на прикажаната слика. Која


вредност ќе ја содржи променливата pokazuvac  по
извршувањето на наредбата:
pokazuvac=&broj;

28
1 . 0
2 . 56
3 . 4325
4 . 564325

14. Даден е програмски сегмент: 


int *a = 5;
int *fun_int = NULL;

---------------------------
Која наредба треба да се допише за да покажувачот fun_int
покажува на адресата на променивата а.
1 . fun_int = *a;
2 . fun_int = &a;
3 . *fun_int = &a;
4 . *fun_int = *a;

15. Елена ја напишала следната програма за да се отпечати


бројот 240. Наместо тоа програмата отпечатила 310. Одговори
каде погрешила Елена.
void funcOne(int n)
{
n = 240;
}
int main()
{
int n = 310;
funcOne(n);
cout << “n = “ << n << endl;
return 0;
}
 При дефинирање на функција не е наведен покажувач
1 .
(референца).
 При повикување на функција не е наведен тип на
2 .
променлива
3 .  Во наредба за печатење не е наведен покажувач
4 . Погрешен тип на променливата n.

Дополнителна литература од Интернет

http://mendo.mk/Lecture.do?id=15
https://www.mk.w3ki.com/cplusplus/pointer_operators.html

29

You might also like