** Дялове в оперативната памет
при изпълнение на програма на С++.
CODE транслираната програма (от exe файла) |
DATA глобални данни |
STACK локални променливи имена на извикани функции |
HEAP Динамична памет |
** Тип указател - съхранява адрес
от оперативната памет на компютъра.
* Дефиниране на променлива тип указател:
синтаксис: <име
на тип> * <име
на променлива>
Employee *boss;
int *pn;
new <име на тип>
- запазва място за една променлива от
зададения тип
new <име на
тип>[<число>]>
- запазва място за няколко променливи (колкото е числото) от
зададения тип
Пример 1:
-дефиниране на променлива тип указател (pn)
и задаване на начална стойност на указателя (операция new):
int *pn = new int;
Пример 2:
-дефиниране на масив (arr)
в динамичната памет с помощта на указател:
int *arr = new int[100];
Пример 3:
-дефиниране на променлива тип указател (boss), задаване на начална
стойност на указателя (операция new) и задаване на начална
стойност на сочения от него обект (Employ("John",
3200)):
Employee *boss = new Employ("John", 3200);
-конструиране на обект от тип int:
int *pn = new int(10);
STACK
|
Динамична памет
адрес XXX
адрес YYY
|
* Операция стойност на указател
(dereference) - унарна операция *:
синтаксис: *<указател>
Employee *boss = new Employ("John",
3200); // началник е John
Employee
harry("Harry", 1500);
*boss = harry; // началник вече
е Harry;
int *pn
= new int(10);
cout << *pn;
*pn = 12;
cout << *pn;
* Обекти и променливи без имена:
Employee
*boss = new Employ("John", 3200); // *boss е John
Еmployee *h;
h =
boss;
// *boss и *h е все John
boss = NULL;
// само *h е John, *boss е грешка!
* Освобождаване на памет
(унищожаване на обекта) - унарна операция delete.
синтаксис: delete <указател>
delete boss;
delete pn;
* Невалидни
указатели - опит за работа със стойност на указател след
освобождаване на заетата памет.
int *pk = new int(10);
cout << *pk;
delete pk;
*pk = 100; // невалиден
указател
Опасна грешка!
* Невалидни
указатели -
неопределена (незаредена) променлива.
int *pk;
*pk = 100; // невалиден
указател
Опасна грешка!
* Операция адрес на променлива
или обект &.
синтаксис: & <име на
променлива>
* Указатели в системния стек
(run-time stack).
Employee harry("Harry", 4300);
Employee *h = &harry;
int k = 10; int *pk = &k; cout << k; cout << (*pk); |
STACK Адрес XXX
|
STACK
|
* Параметри-псевдоними и
параметри указатели.
void swap1(int &a, int &b) //
разменя стойностите на променливите a и b
{
int w = a;
a = b;
b = w;
}
void swap2(int *pa, int *pb)
// разменя стойностите на променливите с
адреси указателите a и b
{
int w = *pa;
*pa = *pb;
*pb = w;
}
int main()
{
int x = 10, y = 12;
swap1(x, y); // параметрите са промелниви
от тип int
cout << x << " " << y
<< endl;
swap2(&x, &y); // параметрите са
адреси на променливи от тип int
cout << x << " " << y
<< endl;
return 0;
}
** Използване на указатели в класове
* Пример (optional attribute):
Класът Department представя департамент с име (string)
и администратор (Employee), като в някой департамент може
да няма администратор.
class Department {
. . .
private:
string name;
bool exists; // true ако има администратор
Employee recept; // обектът съществува само ако има администратор
};
Ако в департамента има администратор, то
указател ще сочи към този обект, ако не - указателят ще има
стойност NULL.
class Department {
. . .
private:
string name;
Employee* receptionist;
};
Пример (sharing):
Някои департаменти могат да имат администратор и/или секретар,
като някъде един и същи служител може да заема и двете длъжности.
class Department {
. . .
private:
string name;
Employee* receptionist;
Employee* secretary;
};
// department.cpp
#include <string> #include <iostream> using namespace std; #include "ccc_empl.h" /**
A department in an organization. */ class Department { public: Department(string n); void set_receptionist(Employee* e); void set_secretary(Employee* e); void print() const; private: string name; Employee* receptionist; Employee* secretary; }; /** Constructs a department with a given name. @param n the department name */ Department::Department(string n) { name = n; receptionist = NULL; secretary = NULL; } /** Sets the receptionist for this department. @param e the receptionist */ void Department::set_receptionist(Employee* e) { receptionist = e; } /** Sets the secretary for this department. @param e the secretary */ void Department::set_secretary(Employee* e) { secretary = e; } /** Prints a description of this department. */ void Department::print() const { cout << "Name: " << name << "\n" << "Receptionist: "; if (receptionist == NULL) cout << "None"; else cout << receptionist->get_name() << " " << receptionist->get_salary(); cout << "\nSecretary: "; if (secretary == NULL) cout << "None"; else if (secretary == receptionist) cout << "Same"; else cout << secretary->get_name() << " " << secretary->get_salary();
cout << "\n"; } int main() { Department shipping("Shipping"); Department qc("Quality Control"); Employee* harry = new Employee("Hacker, Harry", 45000); shipping.set_secretary(harry); Employee* tina = new Employee("Tester, Tina", 50000); qc.set_receptionist(tina); qc.set_secretary(tina); tina->set_salary(55000); shipping.print(); qc.print(); return 0; }
** Указатели и масиви, адресна
аритметика.
Името на масив е константен указател.
int a[3] = {10, 20, 30};
int *pa = a;
/* отпечатва 3 пъти стойността на
a[0] */
cout << a[0] <<"
"<< pa[0] <<" "<< *pa;
/* отпечатва 4 пъти стойността на
a[1] */
cout << a[1] <<"
"<< pa[1] <<" "<< *(pa+1) <<"
"<<(pa+1)[0];
Адрес | pa или a | pa+1 или a+1 | pa+2 или a+2 |
Стойност | 10 | 20 | 30 |
Индекс | 0 | 1 | 2 |
Достъп 1 | a[0] | a[1] | a[2] |
Достъп 2 | *pa | *(pa+1) | *(pa+2) |
Достъп 3 | pa[0] | (pa+1)[0] | (pa+1)[1] |
Достъп 4 | *a | *(a+1) | *(a+2) |
char s[] = "Harry";
/* is the same as */
char *s = "Harry";
*s | *(s+1) | *(s+2) | *(s+3) | *(s+4) | *(s+5) |
s[0] |
s[1] | s[2] | s[3] | s[4] | s[5] |
'H' | 'a' | 'r' | 'r' | 'y' | '\0' |
char* p = "Harry";Превръщане на обекти от тип string в тип char*.
string name(p); // or string name = p;
string num = "123";
const char* cnum = num.c_str();
int n = atoi(cnum);