logo

Покажчики C++

Покажчики є символічними представленнями адрес. Вони дозволяють програмам імітувати виклик за посиланням, а також створювати динамічні структури даних і керувати ними. Ітерація елементів у масивах або інших структурах даних є одним із основних видів використання покажчиків.

Адреса змінної, з якою ви працюєте, призначається змінній-вказівнику, яка вказує на той самий тип даних (наприклад, int або string).

javascript для циклу

Синтаксис:



datatype *var_name; int *ptr; // ptr can point to an address which holds int data>
Як працює покажчик у C++

Як користуватися покажчиком?

  • Визначте змінну-вказівник
  • Присвоєння адреси змінної покажчику за допомогою унарного оператора (&), який повертає адресу цієї змінної.
  • Доступ до значення, що зберігається в адресі, за допомогою унарного оператора (*), який повертає значення змінної, розташованої за адресою, визначеною її операндом.

Причина, по якій ми асоціюємо тип даних із вказівником що він знає, скільки байтів зберігаються дані . Коли ми збільшуємо покажчик, ми збільшуємо його на розмір типу даних, на який він вказує.

Покажчики в C++C++
// C++ program to illustrate Pointers #include  using namespace std; void geeks() {  int var = 20;  // declare pointer variable  int* ptr;  // note that data type of ptr and var must be same  ptr = &var;  // assign the address of a variable to a pointer  cout << 'Value at ptr = ' << ptr << '
';  cout << 'Value at var = ' << var << '
';  cout << 'Value at *ptr = ' << *ptr << '
'; } // Driver program int main()  {   geeks();   return 0; }>

Вихід
Value at ptr = 0x7ffe454c08cc Value at var = 20 Value at *ptr = 20>

Посилання та покажчики

Є 3 способи передати C++ аргументи функції:

  • Виклик за значенням
  • Виклик за посиланням з аргументом покажчика
  • Виклик за посиланням з аргументом посилання
C++
// C++ program to illustrate call-by-methods #include  using namespace std; // Pass-by-Value int square1(int n) {  // Address of n in square1() is not the same as n1 in  // main()  cout << 'address of n1 in square1(): ' << &n << '
';  // clone modified inside the function  n *= n;  return n; } // Pass-by-Reference with Pointer Arguments void square2(int* n) {  // Address of n in square2() is the same as n2 in main()  cout << 'address of n2 in square2(): ' << n << '
';  // Explicit de-referencing to get the value pointed-to  *n *= *n; } // Pass-by-Reference with Reference Arguments void square3(int& n) {  // Address of n in square3() is the same as n3 in main()  cout << 'address of n3 in square3(): ' << &n << '
';  // Implicit de-referencing (without '*')  n *= n; } void geeks() {  // Call-by-Value  int n1 = 8;  cout << 'address of n1 in main(): ' << &n1 << '
';  cout << 'Square of n1: ' << square1(n1) << '
';  cout << 'No change in n1: ' << n1 << '
';  // Call-by-Reference with Pointer Arguments  int n2 = 8;  cout << 'address of n2 in main(): ' << &n2 << '
';  square2(&n2);  cout << 'Square of n2: ' << n2 << '
';  cout << 'Change reflected in n2: ' << n2 << '
';  // Call-by-Reference with Reference Arguments  int n3 = 8;  cout << 'address of n3 in main(): ' << &n3 << '
';  square3(n3);  cout << 'Square of n3: ' << n3 << '
';  cout << 'Change reflected in n3: ' << n3 << '
'; } // Driver program int main() { geeks(); }>

Вихід
address of n1 in main(): 0x7fffa7e2de64 address of n1 in square1(): 0x7fffa7e2de4c Square of n1: 64 No change in n1: 8 address of n2 in main(): 0x7fffa7e2de68 address of n2 in square2(): 0x7fffa7e2de68 Square of n2: 64 Change reflected in n2: 64 address of n3 in main(): 0x7fffa7e2de6c address of n3 in square3(): 0x7fffa7e2de6c Square of n3: 64 Change reflected in n3: 64>

У C++ за умовчанням аргументи передаються за значенням, і зміни, внесені у викликану функцію, не відображатимуться в переданій змінній. Зміни вносяться в клон, зроблений викликаною функцією. Якщо ми бажаємо безпосередньо змінити оригінальну копію (особливо під час передачі величезного об’єкта чи масиву) та/або уникнути накладних витрат на клонування, ми використовуємо передачу за посиланням. Передача за посиланням з аргументами посилання не потребує будь-якого незграбного синтаксису для посилань і розіменувань.

Ім'я масиву як покажчики

Ан масив name містить адресу першого елемента масиву, який діє як постійний покажчик. Це означає, що адреса, яка зберігається в назві масиву, не може бути змінена. Наприклад, якщо у нас є масив з назвою val, тоді вал і &val[0] можна використовувати як взаємозамінні.

C++
// C++ program to illustrate Array Name as Pointers #include  using namespace std; void geeks() {  // Declare an array  int val[3] = { 5, 10, 20 };  // declare pointer variable  int* ptr;  // Assign the address of val[0] to ptr  // We can use ptr=&val[0];(both are same)  ptr = val;  cout << 'Elements of the array are: ';  cout << ptr[0] << ' ' << ptr[1] << ' ' << ptr[2]; } // Driver program int main() { geeks(); }>

Вихід
Elements of the array are: 5 10 20>
Представлення даних в пам'яті

Якщо вказівник ptr надсилається функції як аргумент, можна отримати доступ до масиву val подібним чином. Покажчик проти масиву

Вирази вказівника та арифметика вказівника

Обмежений набір арифметика операції можна виконувати над покажчиками, які є:

java в об’єкт json
  • збільшено (++)
  • зменшено ( — )
  • до вказівника можна додати ціле число (+ або +=)
  • ціле число можна відняти від покажчика ( – або -= )
  • різниця між двома покажчиками (p1-p2)

( Примітка: Арифметика вказівника не має сенсу, якщо не виконується над масивом.)

C++
// C++ program to illustrate Pointer Arithmetic #include  using namespace std; void geeks() {  // Declare an array  int v[3] = { 10, 100, 200 };  // declare pointer variable  int* ptr;  // Assign the address of v[0] to ptr  ptr = v;  for (int i = 0; i < 3; i++) {  cout << 'Value at ptr = ' << ptr << '
';  cout << 'Value at *ptr = ' << *ptr << '
';  // Increment pointer ptr by 1  ptr++;  } } // Driver program int main() { geeks(); }>

Вихід
Value at ptr = 0x7ffe5a2d8060 Value at *ptr = 10 Value at ptr = 0x7ffe5a2d8064 Value at *ptr = 100 Value at ptr = 0x7ffe5a2d8068 Value at *ptr = 200>
Представлення даних в пам'яті

Розширена нотація вказівника

Розглянемо вказівну нотацію для двовимірних числових масивів. розгляньте наступну декларацію

int nums[2][3] = { { 16, 18, 20 }, { 25, 26, 27 } };>

Загалом nums[ i ][ j ] еквівалентно *(*(nums+i)+j)

Позначення вказівника в C++

Покажчики та рядкові літерали

Рядкові літерали — це масиви, що містять послідовності символів із закінченням нулем. Рядкові літерали — це масиви символьного типу плюс кінцевий нульовий символ, при цьому кожен з елементів має тип const char (оскільки символи рядка не можна змінювати).

>

Це оголошує масив із літеральним представленням для geek, а потім покажчик на його перший елемент призначається ptr. Якщо ми уявимо, що geek зберігається в місцях пам’яті, які починаються з адреси 1800, ми можемо представити попередню декларацію як:

Покажчики та рядкові літерали

Оскільки вказівники та масиви поводяться однаково у виразах, ptr можна використовувати для доступу до символів рядкового літералу. Наприклад:

char ptr = 0; char x = *(ptr+3); char y = ptr[3];>

Тут як x, так і y містять k, збережений у 1803 (1800+3).

порівняння рядків java

Покажчики на покажчики

У C++ ми можемо створити вказівник на вказівник, який, у свою чергу, може вказувати на дані або інший вказівник. Синтаксис просто вимагає унарного оператора (*) для кожного рівня непрямості під час оголошення покажчика.

char a; char *b; char ** c; a = ’g’; b = &a; c = &b;>

Тут b вказує на char, який зберігає «g», а c вказує на вказівник b.

Покажчики пустот

Це особливий тип покажчика, доступний у C++, який представляє відсутність типу. Покажчики пустот це покажчики, які вказують на значення, яке не має типу (і, отже, також невизначеної довжини та невизначених властивостей розіменування). Це означає, що покажчики void мають велику гнучкість, оскільки вони можуть вказувати на будь-який тип даних. За цю гнучкість є виграш. Ці вказівники не можуть бути безпосередньо розіменовані. Вони повинні бути спочатку перетворені в якийсь інший тип покажчика, який вказує на конкретний тип даних, перш ніж розіменовуватися.

динамічний масив java
C++
// C++ program to illustrate Void Pointer #include  using namespace std; void increase(void* data, int ptrsize) {  if (ptrsize == sizeof(char)) {  char* ptrchar;  // Typecast data to a char pointer  ptrchar = (char*)data;  // Increase the char stored at *ptrchar by 1  (*ptrchar)++;  cout << '*data points to a char'  << '
';  }  else if (ptrsize == sizeof(int)) {  int* ptrint;  // Typecast data to a int pointer  ptrint = (int*)data;  // Increase the int stored at *ptrchar by 1  (*ptrint)++;  cout << '*data points to an int'  << '
';  } } void geek() {  // Declare a character  char c = 'x';  // Declare an integer  int i = 10;  // Call increase function using a char and int address  // respectively  increase(&c, sizeof(c));  cout << 'The new value of c is: ' << c << '
';  increase(&i, sizeof(i));  cout << 'The new value of i is: ' << i << '
'; } // Driver program int main() { geek(); }>

Вихід
*data points to a char The new value of c is: y *data points to an int The new value of i is: 11>

Недійсні покажчики

Покажчик має вказувати на дійсну адресу, але не обов’язково на дійсні елементи (як для масивів). Вони називаються недійсними покажчиками. Неініціалізовані покажчики також є недійсними покажчиками.

int *ptr1; int arr[10]; int *ptr2 = arr+20;>

Тут ptr1 неініціалізовано, тому він стає недійсним покажчиком, а ptr2 виходить за межі arr, тому він також стає недійсним покажчиком. (Примітка: недійсні покажчики не обов’язково викликають помилки компіляції)

Покажчики NULL

А нульовий покажчик це вказівник, який не вказує нікуди, а не просто недійсну адресу. Нижче наведено 2 методи призначення покажчика як NULL;

int *ptr1 = 0; int *ptr2 = NULL;>

Переваги покажчиків

  • Покажчики зменшують код і покращують продуктивність. Вони використовуються для отримання рядків, дерев, масивів, структур і функцій.
  • Покажчики дозволяють нам повертати кілька значень із функцій.
  • На додаток до цього покажчики дозволяють нам отримати доступ до місця пам’яті в пам’яті комп’ютера.

Пов'язані статті:

  • Непрозорий покажчик
  • Близький, Далекий і Величезний Покажчики

Вікторини:

  • Основи покажчика
  • Розширений покажчик