Co to jest wskaźnik w C?
Wskaźnik w C, to zmienna, która przechowuje adres innej zmiennej. Wskaźnik może również służyć do odwoływania się do innej funkcji wskaźnika. Wskaźnik można zwiększać / zmniejszać, tj. Wskazywać na następną / poprzednią lokalizację pamięci. Celem wskaźnika jest oszczędność miejsca w pamięci i szybsze wykonanie.
Jak używać wskaźników w C
Jeśli zadeklarujemy zmienną v typu int, v faktycznie zapisze wartość.
v jest teraz równe zero.
Jednak każda zmienna oprócz wartości ma również swój adres (lub po prostu miejsce, w którym się znajduje w pamięci). Adres można pobrać, umieszczając znak ampersand (&) przed nazwą zmiennej.
Jeśli wydrukujesz adres zmiennej na ekranie, będzie on wyglądał jak całkowicie losowa liczba (ponadto może się różnić w zależności od uruchomienia).
Spróbujmy tego w praktyce ze wskaźnikiem w przykładzie C.
Wynik tego programu to -480613588.
Co to jest wskaźnik? Zamiast przechowywać wartość, wskaźnik zapisze y adres zmiennej.
Zmienna wskaźnika
Int * y = & v;
ZMIENNA |
WSKAŹNIK |
Wartość przechowywana w nazwie przechowywania / adres pamięci |
Zmienne , że wskazuje na adres pamięci / pamięci innej zmiennej |
Deklarowanie wskaźnika
Podobnie jak zmienne, wskaźniki w programowaniu w C muszą być zadeklarowane, zanim będą mogły być użyte w programie. Wskaźniki mogą mieć dowolne nazwy, o ile są zgodne z regułami nazewnictwa języka C. Deklaracja wskaźnika ma następującą postać.
data_type * pointer_variable_name;
Tutaj,
- typ_danych jest podstawowym typem wskaźnika dla typów zmiennych języka C i wskazuje typ zmiennej, na którą wskazuje wskaźnik.
- Gwiazdka (*: ta sama gwiazdka używana do mnożenia), która jest operatorem pośrednim, deklaruje wskaźnik.
Zobaczmy kilka prawidłowych deklaracji wskaźników w tym samouczku dotyczącym wskaźników w języku C:
int *ptr_thing; /* pointer to an integer */int *ptr1,thing;/* ptr1 is a pointer to type integer and thing is an integer variable */double *ptr2; /* pointer to a double */float *ptr3; /* pointer to a float */char *ch1 ; /* pointer to a character */float *ptr, variable;/*ptr is a pointer to type float and variable is an ordinary float variable */
Zainicjuj wskaźnik
Po zadeklarowaniu wskaźnika inicjalizujemy go jak standardowe zmienne z adresem zmiennej. Jeśli wskaźniki w programowaniu w C nie są niezainicjalizowane i używane w programie, wyniki są nieprzewidywalne i potencjalnie katastrofalne.
Aby uzyskać adres zmiennej, używamy operatora ampersand (&), umieszczonego przed nazwą zmiennej, której adresu potrzebujemy. Inicjalizacja wskaźnika odbywa się za pomocą następującej składni.
Składnia wskaźnika
pointer = &variable;
Poniżej przedstawiono prosty program do ilustracji wskaźników:
#includeint main(){int a=10; //variable declarationint *p; //pointer variable declarationp=&a; //store address of variable a in pointer pprintf("Address stored in a variable p is:%x\n",p); //accessing the addressprintf("Value stored in a variable p is:%d\n",*p); //accessing the valuereturn 0;}
Wynik:
Address stored in a variable p is:60ff08Value stored in a variable p is:10
Operator | Znaczenie |
* | Służy 2 celom
|
& | Służy tylko jednemu celowi
|
Rodzaje wskaźników w C
Poniżej przedstawiono różne typy wskaźników w języku C :
Wskaźnik zerowy
Możemy utworzyć wskaźnik zerowy, przypisując wartość null podczas deklaracji wskaźnika. Ta metoda jest przydatna, gdy nie masz przypisanego adresu do wskaźnika. Wskaźnik pusty zawsze zawiera wartość 0.
Poniższy program ilustruje użycie wskaźnika zerowego:
#includeint main(){int *p = NULL; //null pointerprintf(“The value inside variable p is:\n%x”,p);return 0;}
Wynik:
The value inside variable p is:0
Void Pointer
W programowaniu w C wskaźnik void jest również nazywany wskaźnikiem ogólnym. Nie ma żadnego standardowego typu danych. Wskaźnik void jest tworzony za pomocą słowa kluczowego void. Może służyć do przechowywania adresu dowolnej zmiennej.
Poniższy program ilustruje użycie wskaźnika void:
#includeint main(){void *p = NULL; //void pointerprintf("The size of pointer is:%d\n",sizeof(p));return 0;}
Wynik:
The size of pointer is:4
Dziki wskaźnik
Mówi się, że wskaźnik jest dzikim wskaźnikiem, jeśli nie jest do niczego inicjalizowany. Tego typu wskaźniki C nie są wydajne, ponieważ mogą wskazywać na nieznane miejsce w pamięci, co może powodować problemy w naszym programie i może prowadzić do awarii programu. Podczas pracy z dzikimi wskazówkami należy zawsze zachować ostrożność.
Poniższy program ilustruje użycie dzikiego wskaźnika:
#includeint main(){int *p; //wild pointerprintf("\n%d",*p);return 0;}
Wynik
timeout: the monitored command dumped coresh: line 1: 95298 Segmentation fault timeout 10s main
Inne typy wskaźników w „c” są następujące:
- Nieaktualny wskaźnik
- Złożony wskaźnik
- W pobliżu wskaźnika
- Daleki wskaźnik
- Ogromny wskaźnik
Bezpośrednie i pośrednie wskaźniki dostępu
W języku C istnieją dwa równoważne sposoby uzyskiwania dostępu do zmiennej zawartości i manipulowania nią
- Dostęp bezpośredni: używamy bezpośrednio nazwy zmiennej
- Dostęp pośredni: używamy wskaźnika do zmiennej
Zrozummy to za pomocą poniższego programu
#include/* Declare and initialize an int variable */int var = 1;/* Declare a pointer to int */int *ptr;int main( void ){/* Initialize ptr to point to var */ptr = &var;/* Access var directly and indirectly */printf("\nDirect access, var = %d", var);printf("\nIndirect access, var = %d", *ptr);/* Display the address of var two ways */printf("\n\nThe address of var = %d", &var);printf("\nThe address of var = %d\n", ptr);/*change the content of var through the pointer*/*ptr=48;printf("\nIndirect access, var = %d", *ptr);return 0;}
Po skompilowaniu programu bez błędów otrzymujemy:
Direct access, var = 1Indirect access, var = 1The address of var = 4202496The address of var = 4202496Indirect access, var = 48
Arytmetyka wskaźników w C
Operacje wskaźnikowe podsumowano na poniższym rysunku
Operacja priorytetowa (pierwszeństwo)
Podczas pracy ze wskaźnikami C musimy przestrzegać następujących zasad pierwszeństwa:
- Operatory * i & mają ten sam priorytet co operatory jednoargumentowe (negacja !, inkrementacja ++, dekrementacja--).
- W tym samym wyrażeniu operatory jednoargumentowe *, &,!, ++, - są obliczane od prawej do lewej.
Jeśli wskaźnik P wskazuje na zmienną X, wówczas * P można użyć wszędzie tam, gdzie można zapisać X.
Następujące wyrażenia są równoważne:
int X = 10 int * P = & Y; Dla powyższego kodu poniższe wyrażenia są prawdziwe | |
Wyrażenie | Wyrażenie równoważne |
Y = * P + 1 * P = * P + 10 * P + = 2 ++ * P (* P) ++ | Y = X + 1 X = X + 10 X + = 2 ++ X X ++ |
W tym drugim przypadku potrzebne są nawiasy: ponieważ operatory jednoargumentowe * i ++ są oceniane od prawej do lewej, bez nawiasów zwiększałby się wskaźnik P, a nie obiekt, na który wskazuje P.
Poniższa tabela przedstawia arytmetykę i podstawowe operacje, których można użyć w przypadku wskaźników C.
Operacja | Wyjaśnienie |
Zadanie | int * P1, * P2 P1 = P2; P1 i P2 wskazują na tę samą zmienną całkowitą |
Inkrementacja i dekrementacja | Int * P1; P1 ++; P1--; |
Dodawanie przesunięcia (Stałe) | Pozwala to wskaźnikowi na przesuwanie N elementów w tabeli. Wskaźnik zostanie zwiększony lub zmniejszony o N-krotność liczby bajtów typu zmiennej. P1 + 5; |
Wskaźniki i tablice C z przykładami
Tradycyjnie uzyskujemy dostęp do elementów tablicy za pomocą jej indeksu, ale tę metodę można wyeliminować za pomocą wskaźników. Wskaźniki ułatwiają dostęp do każdego elementu tablicy.
#includeint main(){int a[5]={1,2,3,4,5}; //array initializationint *p; //pointer declaration/*the ptr points to the first element of the array*/p=a; /*We can also type simply ptr==&a[0] */printf("Printing the array elements using pointer\n");for(int i=0;i<5;i++) //loop for traversing array elements{printf("\n%x",*p); //printing array elementsp++; //incrementing to the next element, you can also write p=p+1}return 0;}
Wynik
12345
Dodanie określonej liczby do wskaźnika spowoduje przesunięcie położenia wskaźnika do wartości uzyskanej w wyniku operacji dodawania. Załóżmy, że p jest wskaźnikiem, który aktualnie wskazuje na lokalizację pamięci 0, jeśli wykonamy następującą operację dodawania, p + 1, to zostanie wykonana w ten sposób:
Ponieważ p wskazuje obecnie lokalizację 0 po dodaniu 1, wartość wyniesie 1, a zatem wskaźnik będzie wskazywał na lokalizację pamięci 1.
Wskaźniki i ciągi znaków C z przykładami
Łańcuch to tablica obiektów typu char, zakończona znakiem null „\ 0”. Możemy manipulować łańcuchami za pomocą wskaźników. Ten wskaźnik w przykładzie C wyjaśnia tę sekcję
#include#include 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);printf("Printing all the characters in a string\n");p=str; //reset the pointerfor(int i=0;i Wynik
First character is:HNext character is:ePrinting all the characters in a stringHelloGuru99!Innym sposobem radzenia sobie z ciągami znaków jest tablica wskaźników, jak w poniższym programie:
#includeint main(){char *materials[ ] = { "iron", "copper", "gold"};printf("Please remember these materials :\n");int i ;for (i = 0; i < 3; i++) {printf("%s\n", materials[ i ]);}return 0;} Wynik:
Please remember these materials:ironcoppergoldZalety wskaźników w C
- Wskaźniki są przydatne do uzyskiwania dostępu do lokalizacji pamięci.
- Wskaźniki zapewniają skuteczny sposób uzyskiwania dostępu do elementów struktury tablicy.
- Wskaźniki są używane do dynamicznej alokacji pamięci, a także do jej zwalniania.
- Wskaźniki służą do tworzenia złożonych struktur danych, takich jak lista połączona, wykres, drzewo itp.
Wady wskaźników w C
- Wskazówki są trochę skomplikowane do zrozumienia.
- Wskaźniki mogą prowadzić do różnych błędów, takich jak błędy segmentacji, lub mogą uzyskać dostęp do lokalizacji pamięci, która nie jest w ogóle wymagana.
- Podanie niepoprawnej wartości do wskaźnika może spowodować uszkodzenie pamięci.
- Wskaźniki są również odpowiedzialne za wyciek pamięci.
- Wskaźniki są stosunkowo wolniejsze niż w przypadku zmiennych.
- Programiści mają duże trudności z pracą ze wskaźnikami; dlatego obowiązkiem programisty jest ostrożne posługiwanie się wskaźnikiem.
Podsumowanie
- Wskaźnik to nic innego jak miejsce w pamięci, w którym przechowywane są dane.
- Aby uzyskać dostęp do lokalizacji pamięci, używany jest wskaźnik.
- Istnieją różne typy wskaźników, takie jak wskaźnik zerowy, wskaźnik dziki, wskaźnik void i inne typy wskaźników.
- Wskaźniki mogą być używane z tablicą i ciągiem, aby wydajniej uzyskiwać dostęp do elementów.
- Możemy tworzyć wskaźniki funkcji, aby dynamicznie wywoływać funkcję.
- Operacje arytmetyczne można wykonywać na wskaźniku, który jest znany jako arytmetyka wskaźnika.
- Wskaźniki mogą również wskazywać na funkcję, która ułatwia wywoływanie różnych funkcji w przypadku definiowania tablicy wskaźników.
- Jeśli chcesz zajmować się różnymi zmiennymi typami danych, możesz użyć wskaźnika void z rzutowania typów.