Указатели в C: Какво е указател в програмирането на C? Видове
⚡ Умно обобщение
Указателите в C са променливи, които съхраняват адреса на паметта на друга променлива. Те позволяват динамично разпределение на паметта, ефективна обработка на масиви и низове, както и сложни структури от данни, използвайки операторите за адресиране и дереференциране за четене или промяна на стойности.

Какво е указател в C?
A показалка В C е променлива, която съхранява адреса на друга променлива. Указателят може също да се отнася до друг указател или до функция. Указателят може да бъде увеличаван или намаляван, за да сочи към следващата или предишната позиция в паметта. Целта на указателя е да спести място в паметта и да постигне по-бързо време за изпълнение.
Как да използвате указатели в C
Ако декларираме променлива v от тип int, v съхранява стойност. Всяка променлива, освен стойността си, има и адрес, т.е. къде се намира в паметта. Адресът може да бъде извлечен чрез поставяне на амперсанд (&) пред името на променливата. Ако отпечатате адреса на променлива, той изглежда като случайно число, което може да се различава при различните изпълнения.
Вместо да съхранява стойност, указателят съхранява адреса на променлива. Например:
int *y = &v;
| Променлива | УКАЗАТЕЛ |
|---|---|
| A стойност съхранявани в 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
| OperaTor | Значение |
|---|---|
| * | Служи за две цели: декларира указател и връща стойността на цитираната променлива (дереференция). |
| & | Служи за една цел: връща адреса на променлива. |
Видове указатели в 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; }
Див пойнтер
Указателят се нарича wild указател, ако не е инициализиран с нищо. Тези указатели не са ефективни, защото могат да сочат към неизвестна област в паметта, което може да причини проблеми и да срине програмата. Винаги бъдете внимателни с wild указателите:
#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 | X = X + 10 |
| *P += 2 | X + = 2 |
| +++P | ++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
- Указателите са малко сложни за разбиране.
- Те могат да причинят грешки, като например грешки в сегментирането или достъп до нежелано място в паметта.
- Неправилна стойност, зададена на указател, може да причини повреда на паметта.
- Показателите също са отговорни за изтичане на памет, ако паметта не е освободена.
- Отговорност на програмиста е да борави внимателно с указателя.
