Бублик Володимир Васильович Процедурне програмування C/C++ Лекція 4. Базові поняття програмування. Указники і відсилки Лекції для студентів 2 курсу Nürnberg, Burg
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 2 (38) Призначення указників Указник (pointer) набуває значеннями адреси пам'яті, а також особливе нульове значення, з яким не зв'язана жодна адреса Динамічне виділення і звільнення пам'яті: створення масивів; створення динамічних структур даних (списків, дерев, тощо)
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 3 (38) Типізація указників Кожному указнику приписано його тип: указник цілого; указник символу; указник дійсного, тощо. З одним указником можна зв'язати цілий агрегат даних одного й того ж типу, розміщених одне за одним, починаючи з місця, позначеного указником
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 4 (38) Визначення указника 1.int *ptrI; 2.float *px, y, z; 3.float *px, *py, *pz; Визначення без ініціалізації приводять до заповнення пам'яті сміттям. Засмічені указники (dangling pointer) небезпечні! float x, *px; сміття некоректні данінекоректна адреса
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 5 (38) Pointer vs. goto Указники приводять до тих же проблем в структурах даних, до яких приводять оператори переходу в структурах керування. Скрізь, де можна, уникаємо указників. Якщо вживаємо, то дотримуємось суворої дисципліни! Якщо значення указника невідоме, ініціалізуємо його нулем float *px = 0; Якщо значення указника не нуль, то з ним зв'язані два елементи пам'яті!
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 6 (38) Операція адресування x=0.25; px = &x; & одномісна операція адресування lvalue(px) rvalue(px) == lvalue (x) == rvalue(&x)
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 7 (38) Операція розіменування cout<< *px; * одномісна операція розіменування rvalue(px) == lvalue(x) rvalue(*px) == rvalue(x)
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 8 (38) Адресування і розіменування Взаємна оберненість операцій над пам'яттю &(*px) == px px == *(&px)
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 9 (38) Динамічне виділення пам'яті float *p = new float; new операція виділення нового елемента пам'яті, його адреса зберігається в p, значення *p заповнено сміттям px = new float; if (px == 0)// вільної памяті немає сміття
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 10 (38) Нестача пам'яті Стандартна реакція: виникнення аварійної ситуації bad_alloc Обробка засобами системи програмування (аварійне припинення виконання програми) Програмна обробка переривання (оператор catch в блоці випробувань try – буде далі) Замовна реакція: повернення нульового указника Формат виклику new (nothrow) Приклад double *px = new (nothrow) double [bigAmount]; if (px==0) //Вільної пам'яті не вистачило
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 11 (38) Динамічне виділення і ініціалізація пам'яті float *p = new float ( ); Тепер значення *p коректне
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 12 (38) Правило гарного тону Якщо ви виділили динамічну память за допомогою команди new не забудьте своєчасно звільнити її командою delete та обнулити указник float *p = new float ( ); // робіть все, що вам потрібно delete p; // потурбуйтесь про захист від завислих указників p = 0;
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 13 (38) Звільнення памяті double *pd = new double (5.2); cout<<pd<<endl;// 0x004419B0 cout<<*pd<<endl;//5.2 delete pd; cout<<pd<<endl;// 0x004419B0 cout<<*pd<<endl;// e+144 double *new_pd = new double; cout<<new_pd<<endl;// 0x004419B0 cout<<*pd<<endl;// t+066 cout<<*new_pd<<endl;
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 14 (38) Звільнення памяті double *pd = new double (5.2); cout<<pd<<endl;// 0x004419B0 cout<<*pd<<endl;//5.2 delete pd; //Правило гарного тону pd = 0;
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 15 (38) Висновок про управління пам'яттю Кожному new свій delete Перевіряйте наявність вільної пам'яті Слідкуйте за тривалістю життя динамічних об'єктів у пам'яті
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 16 (38) Сталі величини і указники Указник сталої const float pi = ; const float *piPtr = &pi ; //*piPtr = 4; ERROR! // float *piNonConstPtr =π теж ERROR
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 17 (38) Права указника сталої float x = 1; const float* px = &x; x =3; cout<<*px<<endl; //*px = 4; як і раніше ERROR! Указнику сталої не надано права змінювати об'єкт, але безпосередня зміна об'єкту, якщо він не сталий, і надалі можлива
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 18 (38) Сталі величини і указники Сталий указник float x = 0.25; float *const px = &x; // Сталий указник не можна перемістити // px = &y; ERROR!
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 19 (38) Сталі величини і указники Сталий указник сталої const float pi = ; const float *const piPtr = π //*piPtr = 4; ERROR! //piPtr = &nAvogadro; ERROR!
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 20 (38) Безтипові указники void *voidPtr;//Що б це значило? 0A0A A000 voidPtr char * str \nabcdefghij
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 21 (38) Безтипові указники void *voidPtr;//Що б це значило? 0A0A A000 voidPtr Якби це був Бейсик abcdefghij
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 22 (38) Безтипові указники void *voidPtr;//Що б це значило? 0A0A A000 voidPtr short int * i 24842
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 23 (38) Безтипові указники void *voidPtr;//Що б це значило? 0A0A A000 voidPtr float * x e+021
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 24 (38) Безтипові указники void *voidPtr;//Що б це значило? 0A0A A000 voidPtr int * k
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 25 (38) Безтипові указники void *voidPtr;//Що б це значило? float *pf = new float (3.1); double *pd = new double (5.2); voidPtr = pf; cout<<voidPtr<<endl; // 0x004419F0 //cout<<*voidPtr<<endl; розіменування неможливе voidPtr = pd; cout<<voidPtr<<endl; // 0x004419B0
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 26 (38) Символьний указник Поганий указник char *c = new char; cout<<*c<<endl; Ініціалізований указник char *cc = new char ('a'); cout<<*cc<<endl; Особливість ініціалізації рядків //char *str = new char(String?); char *str = "Operation New is not needed"; cout<<str<<endl;
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 27 (38) Операцій над указниками float *p1= new float (1), *p2= new float (2); cout<<p2;//0x004418F0 1.Порівняння на рівність або нерівність p1 == p2; p1 > p2;… if(p2>p1) cout p1" p2"<<endl; 2.Присвоєння і ініціалізація p1 = p2; p1 =&x; p1 = new float (3); char *pc = new char [100]; 3.Збільшення, зменшення p1++; ++p1; p1--;--p1; p1+10; p1-10; cout<<p2+1;//0x004418F4
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 28 (38) Відсилка (псевдонім) (reference) Відсилка або псевдонім це альтернативне імя обєкта, яке позначає обєкт на рівних правах з його основним іменем. При створенні псевдонім зв'язується зі своїм об'єктом (відсилає до нього) і ця відсилка дійсна протягом усього життя псевдоніму. Для чого? Для того, щоб у різних частинах програми іменувати одну й ту ж область пам'яті зручним і зрозумілим для цієї частини іменем
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 29 (38) Відсилка (псевдонім) (reference) float x = 1.024;//визначення змінної х float &xRef = x;//визначення її псевдоніму xRef *= 2;// x == xRef == 2.048
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 30 (38) Копіювання float x = 1,024;//визначення змінної x float xCopy = x;//визначення її копії xCopy += x;//подвоєння xCopy, x незмінний
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 31 (38) Порівняння відсилок і указників Визначення указника float x = 1,024;//визначення змінної х float *px = &x;//визначення указника на неї
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 32 (38) Порівняння відсилок і указників Перенаправлення указника px = new float ( ); // x == 1,024; *px == //Звязок між px і x розірвано
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 33 (38) Порівняння відсилок і указників Указнику p відповідає два елементи пам'яті, кожен з яких має власне значення. Зміна значення p розриває наявний звязок між елементами пам'яті, наприклад, px = 0;
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 34 (38) Відсилка і сталий указник float x = 1.024;//визначення змінної х float *const px = &x;//сталий указник на неї //схожість до відсилки: звязок нерозривний //відмінність: наявність двох елементів пам'яті
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 35 (38) Стала відсилка const float pi = ; const float &piRef = pi; // float &piNonConstRef = pi; ERROR
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 36 (38) Стала відсилка Що б це значило? float x = 1; const float & rx = x; x =2; cout<<rx<<endl; Якщо псевдонім сталий, то він не має права змінити об'єкт, але безпосередня зміна об'єкту, якщо він не сталий можлива
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 37 (38) Указники указників double **ppd = new double*; *ppd = new double (5); cout<<ppd<<endl; cout<<*ppd<<endl; cout<<**ppd<<endl; Використання указників на указники розповсюджена техніка програмування у чистому С. Проблеми управління пам'яттю при цьому зростають, бо необхідно слідкувати за обома поверхами указника. Вживати ще обережніше, ніж звичайні.
© 2006 Бублик В.В. Процедурне програмування. Лекція 4. Указники і відсилки 38 (38) Висновки Крім безпосередніх операцій з пам'яттю указники використовуються для передачі змінних параметрів при програмуванні на чистому С, а указники другого рівня для передачі змінних указників В сучасному програмуванні на С++ замість передачі указників використовується передача змінних параметрів відсилками