Покажчики в C: Що таке покажчик у програмуванні на C? Типи

⚡ Розумний підсумок

Вказівники в C – це змінні, які зберігають адресу пам'яті іншої змінної. Вони дозволяють динамічне виділення пам'яті, ефективну обробку масивів і рядків, а також складні структури даних, використовуючи оператори адреси та розіменування для читання або зміни значень.

  • 📌 Визначення: Вказівник містить адресу пам'яті іншої змінної.
  • 🔧 Operaторс: Оператор & повертає адресу; оператор * розіменовує її.
  • 🧷 Декларація: Запишіть data_type *name, а потім ініціалізуйте адресою змінної.
  • 🏷️ типи: Вказівники Null, void та wild поводяться по-різному та потребують обережності.
  • Арифметика: Збільшення вказівника переміщує його на розмір його базового типу.
  • 🤖 Допомога AI: Інструменти штучного інтелекту налагоджують помилки сегментації та позначають завислі вказівники під час перевірки.

Вказівники в C

Що таке покажчик у C?

A покажчик У мові C — це змінна, яка зберігає адресу іншої змінної. Вказівник також може посилатися на інший вказівник або на функцію. Вказівник можна збільшувати або зменшувати, щоб вказувати на наступну або попередню комірку пам'яті. Мета вказівника — заощадити місце в пам'яті та досягти швидшого часу виконання.

Як використовувати покажчики в C

Якщо ми оголошуємо змінну v типу int, v зберігає значення. Кожна змінна, окрім свого значення, також має адресу, тобто місце, де вона знаходиться в пам'яті. Адресу можна отримати, поставивши амперсанд (&) перед іменем змінної. Якщо вивести адресу змінної, вона виглядатиме як випадкове число, яке може відрізнятися від запуску до запуску.

Замість зберігання значення, вказівник зберігає адресу змінної. Наприклад:

int *y = &v;
ЗМІННИЙ Вказівник
A значення зберігається в названий адреса сховища/пам'яті. A змінна Що вказує на адресу зберігання/пам’яті інший змінна.

Оголошення покажчика

Як і змінні, покажчики в Програмування на C їх необхідно оголосити, перш ніж їх можна буде використовувати. Оголошення вказівника має таку форму:

data_type *pointer_variable_name;

Тут, тип даних — це базовий тип вказівника та вказує тип змінної, на яку вказує вказівник. Зірочка (*), той самий символ, що використовується для множення, — це оператор непрямості, який оголошує вказівник. Деякі коректні оголошення вказівників:

int    *ptr_thing;       /* pointer to an integer */
int    *ptr1, thing;     /* ptr1 points to an int; thing is an int */
double *ptr2;           /* pointer to a double */
float  *ptr3;           /* pointer to a float */
char   *ch1;            /* pointer to a character */

Ініціалізація вказівника

Після оголошення вказівника ми ініціалізуємо його адресою змінної. Якщо вказівник неініціалізований та використовується, результати можуть бути непередбачуваними та потенційно катастрофічними. Щоб отримати адресу змінної, використовуйте оператор амперсанд (&) перед іменем змінної:

pointer = &variable;

Проста програма, яка ілюструє вказівник, наведена нижче:

#include <stdio.h>
int main()
{
   int a = 10;     // variable declaration
   int *p;         // pointer variable declaration
   p = &a;        // store address of a in pointer p
   printf("Address stored in p is: %x\n", p);  // access the address
   printf("Value stored in p is: %d\n", *p);    // access the value
   return 0;
}

вихід:

Address stored in p is: 60ff08
Value stored in p is: 10
Operaтор Сенс
* Виконує дві функції: оголошує вказівник та повертає значення змінної, на яку посилаються (розіменування).
& Виконує одну мету: повертає адресу змінної.

Типи покажчиків у C

Нульовий покажчик

Ми створюємо нульовий покажчик, присвоївши йому значення NULL під час оголошення. Це корисно, коли покажчику ще не призначено адресу. Нульовий покажчик завжди містить значення 0:

#include <stdio.h>
int main()
{
   int *p = NULL;     // null pointer
   printf("The value inside variable p is: %x", p);
   return 0;
}

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

Вказівник типу void, який також називають узагальненим вказівником, не має жодного стандартного типу даних. Він створюється за допомогою ключового слова void і може зберігати адресу будь-якої змінної:

#include <stdio.h>
int main()
{
   void *p = NULL;    // void pointer
   printf("The size of pointer is: %d\n", sizeof(p));
   return 0;
}

Дикий пойнтер

Вказівник називається диким вказівником, якщо він не ініціалізований нічим. Ці вказівники неефективні, оскільки вони можуть вказувати на невідому область пам'яті, що може спричинити проблеми та аварійне завершення роботи програми. Завжди будьте обережні з дикими вказівниками:

#include <stdio.h>
int main()
{
   int *p;          // wild pointer
   printf("%d", *p);
   return 0;
}

Інші типи вказівників у C включають висячий вказівник, комплексний вказівник, ближній вказівник, далекий вказівник та величезний вказівник.

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

У мові C існує два еквівалентні способи доступу та маніпулювання вмістом змінної. Прямий доступ використовує ім'я змінної безпосередньо, тоді як непрямий доступ використовує вказівник на змінну:

#include <stdio.h>
int var = 1;        /* declare and initialize an int variable */
int *ptr;           /* declare a pointer to int */
int main(void)
{
   ptr = &var;       /* point ptr to var */
   printf("\nDirect access, var = %d", var);
   printf("\nIndirect access, var = %d", *ptr);
   *ptr = 48;        /* change var through the pointer */
   printf("\nIndirect access, var = %d", *ptr);
   return 0;
}

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

Під час роботи з покажчиками дотримуйтесь цих правил пріоритету. Оператори * та & мають такий самий пріоритет, як і унарні оператори (заперечення !, інкремент ++, декремент –). В одному й тому ж виразі унарні оператори *, &, !, ++ та — обчислюються справа наліво. Якщо покажчик P вказує на змінну X, то *P можна використовувати скрізь, де можна записати X. Наступні вирази еквівалентні:

вираз Еквівалентний вираз
Y = *P + 1 Y = X + 1
*P = *P + 10 Х = Х + 10
*P += 2 X + = 2
+++П ++X
(*P)++ X++

В останньому випадку дужки потрібні: оскільки унарні оператори * та ++ обчислюються справа наліво, без дужок збільшуватиметься вказівник P, а не об'єкт, на який він вказує. Арифметичні операції, доступні над вказівниками, - це присвоєння, збільшення та зменшення, а також додавання або віднімання.tracвстановлюючи цілочисельне зміщення, яке переміщує вказівник на таку кількість елементів (кожен крок дорівнює розміру базового типу в байтах).

Вказівники та масиви в C з прикладами

Традиційно ми звертаємося до елементів масиву за допомогою індексу, але вказівники також спрощують цей процес. Вказівник, встановлений на ім'я масиву, вказує на перший елемент:

#include <stdio.h>
int main()
{
   int a[5] = {1, 2, 3, 4, 5};   // array initialization
   int *p;                       // pointer declaration
   p = a;                       // p points to the first element; same as &a[0]
   for (int i = 0; i < 5; i++)
   {
      printf("%d\n", *p);            // print element
      p++;                      // move to the next element
   }
   return 0;
}

Додавання числа до вказівника переміщує його на певну кількість елементів вперед. Якщо p вказує на комірку пам'яті 0, то p + 1 змушує вказівник вказувати на комірку пам'яті 1.

C Покажчики та рядки з прикладами

Рядок — це масив об'єктів типу char, що закінчуються нульовим символом '\0'. Ми можемо маніпулювати рядками за допомогою вказівників:

#include <stdio.h>
#include <string.h>
int main()
{
   char str[] = "Hello Guru99!";
   char *p;
   p = str;
   printf("First character is: %c\n", *p);
   p = p + 1;
   printf("Next character is: %c\n", *p);
   p = str;                     // reset the pointer
   for (int i = 0; i < strlen(str); i++)
   {
      printf("%c\n", *p);
      p++;
   }
   return 0;
}

Інший спосіб роботи з рядками – це використання масиву вказівників:

#include <stdio.h>
int main()
{
   char *materials[] = {"iron", "copper", "gold"};
   for (int i = 0; i < 3; i++)
      printf("%s\n", materials[i]);
   return 0;
}

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

  • Вказівники корисні для безпосереднього доступу до місць пам'яті.
  • Вони забезпечують ефективний спосіб доступу до елементів масиву.
  • Вони використовуються для динамічного розподілу та звільнення пам'яті.
  • Вони використовуються для формування складних структур даних, таких як зв'язані списки, графіки та дерева.

Недоліки покажчиків у C

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

Поширені запитання

Висячий вказівник вказує на пам'ять, яка була звільнена або знаходиться поза областю видимості. Уникайте цього, встановлюючи вказівник на NULL одразу після виклику free та перевіряючи наявність NULL перед використанням.

Розіменування вказівника NULL призводить до помилки сегментації та аварійного завершення програми під час виконання. Завжди перевіряйте, чи вказівник не має значення NULL, перш ніж використовувати оператор * для читання або запису.

Подвійний вказівник, оголошений як int **pp, зберігає адресу іншого вказівника. Він використовується для динамічних двовимірних масивів та для зміни аргументу вказівника всередині функції.

Вказівник зберігає адресу пам'яті, а адреси мають однакову ширину на даній платформі, зазвичай 4 байти на 32-бітній системі та 8 байтів на 64-бітній, незалежно від типу, на який він вказує.

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

Такі функції, як malloc та calloc, повертають вказівник на пам'ять, виділену в купі під час виконання. Ви отримуєте доступ до цієї пам'яті через вказівник та звільняєте її за допомогою free, щоб уникнути витоків.

Так. Помічники ШІ зчитують помилку сегментації та навколишній код, потім пояснюють ймовірну причину, таку як неініціалізований або звільнений вказівник, і пропонують вам виправлення для ознайомлення.

Аналізатори на базі штучного інтелекту, поряд з такими інструментами, як Valgrind, позначають пам'ять, яка ніколи не звільняється, та вказівники, що використовуються після звільнення. Вони автоматизують перевірку та виділяють ризиковані шаблони перед публікацією коду.

Підсумуйте цей пост за допомогою: