Wskaźniki w C: Co to jest wskaźnik w programowaniu C? Typy
⚡ Inteligentne podsumowanie
Wskaźniki w języku C to zmienne przechowujące adres pamięci innej zmiennej. Umożliwiają one dynamiczną alokację pamięci, efektywne przetwarzanie tablic i ciągów znaków oraz tworzenie złożonych struktur danych, wykorzystując operatory adresu i dereferencji do odczytu lub modyfikacji wartości.

Czym jest wskaźnik w języku C?
A wskaźnik W języku C zmienna przechowuje adres innej zmiennej. Wskaźnik może również odnosić się do innego wskaźnika lub do funkcji. Wskaźnik można zwiększać lub zmniejszać, aby wskazywał na następną lub poprzednią lokalizację w pamięci. Celem wskaźnika jest oszczędność miejsca w pamięci i skrócenie czasu wykonywania.
Jak używać wskaźników w C
Jeśli zadeklarujemy zmienną v typu int, v przechowuje wartość. Każda zmienna, oprócz wartości, ma również adres, czyli miejsce, w którym się znajduje w pamięci. Adres można uzyskać, umieszczając znak ampersand (&) przed nazwą zmiennej. Jeśli wydrukujesz adres zmiennej, będzie on wyglądał jak liczba losowa, która może się różnić w zależności od uruchomienia.
Zamiast przechowywać wartość, wskaźnik przechowuje adres zmiennej. Na przykład:
int *y = &v;
| ZMIENNA | WSKAŹNIK |
|---|---|
| A wartość przechowywane w o imieniu adres pamięci masowej/magazynowej. | A zmienna że wskazuje na adres przechowywania/pamięci inne zmienna. |
Deklarowanie wskaźnika
Podobnie jak zmienne, wskaźniki w Programowanie C muszą zostać zadeklarowane przed użyciem. Deklaracja wskaźnika ma następującą postać:
data_type *pointer_variable_name;
Tutaj, typ danych jest typem bazowym wskaźnika i wskazuje typ zmiennej, na którą wskazuje wskaźnik. Gwiazdka (*), ten sam symbol, który jest używany do mnożenia, jest operatorem pośrednim deklarującym wskaźnik. Oto kilka prawidłowych deklaracji wskaźnika:
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 */
Zainicjuj wskaźnik
Po zadeklarowaniu wskaźnika inicjalizujemy go adresem zmiennej. Jeśli wskaźnik nie zostanie zainicjowany i użyty, skutki mogą być nieprzewidywalne i potencjalnie katastrofalne. Aby uzyskać adres zmiennej, należy użyć operatora ampersand (&) przed nazwą zmiennej:
pointer = &variable;
Poniżej przedstawiono prosty program ilustrujący wskaźnik:
#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; }
Wyjście:
Address stored in p is: 60ff08 Value stored in p is: 10
| OperaTor | Znaczenie |
|---|---|
| * | Pełni dwa cele: deklaruje wskaźnik i zwraca wartość zmiennej, do której się odwołuje (dereferencja). |
| & | Służy jednemu celowi: zwraca adres zmiennej. |
Rodzaje wskaźników w C
Wskaźnik zerowy
Wskaźnik null tworzymy, przypisując wartość NULL podczas deklaracji. Jest to przydatne, gdy do wskaźnika nie przypisano jeszcze żadnego adresu. Wskaźnik null zawsze zawiera wartość 0:
#include <stdio.h> int main() { int *p = NULL; // null pointer printf("The value inside variable p is: %x", p); return 0; }
Wskaźnik pustki
Wskaźnik typu void, zwany również wskaźnikiem generycznym, nie ma żadnego standardowego typu danych. Jest tworzony za pomocą słowa kluczowego void i może przechowywać adres dowolnej zmiennej:
#include <stdio.h> int main() { void *p = NULL; // void pointer printf("The size of pointer is: %d\n", sizeof(p)); return 0; }
Dziki wskaźnik
Wskaźnik nazywany jest wskaźnikiem dzikim, jeśli nie jest zainicjowany niczym. Takie wskaźniki nie są wydajne, ponieważ mogą wskazywać na nieznaną lokalizację w pamięci, co może powodować problemy i awarie programu. Zawsze należy zachować ostrożność ze wskaźnikami dzikimi:
#include <stdio.h> int main() { int *p; // wild pointer printf("%d", *p); return 0; }
Inne typy wskaźników w języku C obejmują wskaźnik wiszący, wskaźnik złożony, wskaźnik bliski, wskaźnik daleki i wskaźnik ogromny.
Bezpośrednie i pośrednie wskaźniki dostępu
W języku C istnieją dwa równoważne sposoby dostępu do zawartości zmiennej i manipulowania nią. Dostęp bezpośredni wykorzystuje nazwę zmiennej bezpośrednio, natomiast dostęp pośredni używa wskaźnika do zmiennej:
#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; }
Arytmetyka wskaźników w C
Pracując ze wskaźnikami, należy przestrzegać następujących zasad priorytetyzacji. Operatory * i & mają taki sam priorytet jak operatory unarne (negacja !, inkrementacja ++, dekrementacja –). W tym samym wyrażeniu operatory unarne *, &, !, ++ i — są obliczane od prawej do lewej. Jeśli wskaźnik P wskazuje na zmienną X, to *P można użyć wszędzie tam, gdzie można zapisać X. Poniższe wyrażenia są równoważne:
| Wyrażenie | Wyrażenie równoważne |
|---|---|
| Y = *P + 1 | Y = X + 1 |
| *P = *P + 10 | X = X + 10 |
| *P += 2 | X += 2 |
| +***P | ++X |
| (*P)++ | X++ |
W ostatnim przypadku wymagane są nawiasy: ponieważ operatory jednoargumentowe * i ++ są obliczane od prawej do lewej, bez nawiasów inkrementowany byłby wskaźnik P, a nie obiekt, na który wskazuje. Operacje arytmetyczne dostępne na wskaźnikach to przypisanie, inkrementacja i dekrementacja oraz dodawanie lub podpisywanie.tracokreślając przesunięcie całkowite, które przesuwa wskaźnik o liczbę elementów (każdy krok jest równy rozmiarowi typu bazowego w bajtach).
Wskaźniki i tablice w języku C z przykładami
Tradycyjnie dostęp do elementów tablicy uzyskujemy za pomocą indeksu, ale wskaźniki również to ułatwiają. Wskaźnik ustawiony na nazwę tablicy wskazuje na pierwszy element:
#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; }
Dodanie liczby do wskaźnika przesuwa go o wskazaną liczbę elementów do przodu. Jeśli p wskazuje na komórkę pamięci 0, to p + 1 powoduje, że wskaźnik wskazuje na komórkę pamięci 1.
Wskaźniki i ciągi C z przykładami
Ciąg to tablica obiektów char kończąca się znakiem null „\0”. Na ciągach możemy manipulować za pomocą wskaźników:
#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; }
Innym sposobem radzenia sobie z ciągami znaków jest użycie tablicy wskaźników:
#include <stdio.h> int main() { char *materials[] = {"iron", "copper", "gold"}; for (int i = 0; i < 3; i++) printf("%s\n", materials[i]); return 0; }
Zalety wskaźników w C
- Wskaźniki są przydatne do bezpośredniego dostępu do komórek pamięci.
- Umożliwiają efektywny dostęp do elementów tablicy.
- Służą do dynamicznego przydzielania i zwalniania pamięci.
- Służą do tworzenia złożonych struktur danych, takich jak listy powiązane, grafy i drzewa.
Wady wskaźników w C
- Wskaźniki są nieco skomplikowane do zrozumienia.
- Mogą one powodować błędy, takie jak błędy segmentacji lub dostęp do nieprzewidzianego miejsca w pamięci.
- Podanie nieprawidłowej wartości wskaźnikowi może spowodować uszkodzenie pamięci.
- Wskaźniki są również odpowiedzialne za wycieki pamięci, jeśli pamięć nie zostanie zwolniona.
- Obowiązkiem programisty jest ostrożne obchodzenie się ze wskaźnikiem.
