Указатели в C: Какво е указател в програмирането на C? Видове

⚡ Умно обобщение

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

  • 📌 Определение: Указателят съдържа адреса на паметта на друга променлива.
  • 🔧 Operaторове: Операторът & връща адрес; операторът * го разреференцира.
  • 🧷 Декларация: Напишете data_type *name, след което инициализирайте с адреса на променлива.
  • ???? ️ Видове: Нулевите, невалидните и уайлд указателите се държат различно и изискват внимание.
  • аритметика: Увеличаването на показалеца го премества с размера на базовия му тип.
  • 🤖 AI помощ: Инструментите с изкуствен интелект отстраняват грешки в сегментирането и маркират висящи указатели по време на преглед.

Указатели в 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

  • Указателите са малко сложни за разбиране.
  • Те могат да причинят грешки, като например грешки в сегментирането или достъп до нежелано място в паметта.
  • Неправилна стойност, зададена на указател, може да причини повреда на паметта.
  • Показателите също са отговорни за изтичане на памет, ако паметта не е освободена.
  • Отговорност на програмиста е да борави внимателно с указателя.

Въпроси и Отговори

Висящият указател сочи към памет, която е била освободена или е извън обхвата. Избягвайте го, като зададете указателя на NULL веднага след извикването на free и проверите за NULL преди употреба.

Разреференцирането на NULL указател причинява грешка при сегментиране и срива на програмата по време на изпълнение. Винаги проверявайте дали указателят не е NULL, преди да използвате оператора * за четене или запис.

Двоен указател, деклариран като int **pp, съхранява адреса на друг указател. Използва се за динамични 2D масиви и за модифициране на аргумент на указател вътре във функция.

Указателят съхранява адрес в паметта, а адресите са с еднаква ширина на дадена платформа, обикновено 4 байта на 32-битова и 8 байта на 64-битова, независимо от типа, към който сочи.

Указателят на функция съхранява адреса на функция, така че тя да може да бъде извикана динамично. Той се използва широко за обратни извиквания и за изграждане на таблици от функции, избрани по време на изпълнение.

Функции като malloc и calloc връщат указател към памет, разпределена в heap-а по време на изпълнение. Достъпвате до тази памет чрез указателя и я освобождавате с free, за да избегнете течове.

Да. Асистентите с изкуствен интелект прочитат грешка в сегментацията и съпътстващия я код, след което обясняват вероятната причина, като например неинициализиран или освободен указател, и предлагат решение, което да прегледате.

Анализаторите, задвижвани от изкуствен интелект, заедно с инструменти като Valgrind, маркират памет, която никога не се освобождава, и указатели, използвани след освобождаването ѝ. Те автоматизират прегледа и открояват рискови модели, преди кодът да бъде пуснат.

Обобщете тази публикация с: