Wskaźniki dają duże możliwości funkcjom „C”, w przypadku których jesteśmy ograniczeni do zwracania jednej wartości. Dzięki parametrom wskaźnika nasze funkcje mogą teraz przetwarzać rzeczywiste dane zamiast kopii danych.
Aby zmodyfikować rzeczywiste wartości zmiennych, instrukcja wywołująca przekazuje adresy do parametrów wskaźnika w funkcji.
W tym samouczku nauczysz się:
- Funkcje Wskaźniki Przykład
- Funkcje z parametrami tablicy
- Funkcje, które zwracają tablicę
- Wskaźniki funkcji
- Tablica wskaźników funkcji
- Funkcje wykorzystujące wskaźniki void
- Wskaźniki funkcji jako argumenty
Funkcje Wskaźniki Przykład
Na przykład następny program zamienia dwie wartości z dwóch:
void swap (int *a, int *b);int main() {int m = 25;int n = 100;printf("m is %d, n is %d\n", m, n);swap(&m, &n);printf("m is %d, n is %d\n", m, n);return 0;}void swap (int *a, int *b) {int temp;temp = *a;*a = *b;*b = temp;}}
Wynik:
m is 25, n is 100m is 100, n is 25
Program zamienia rzeczywiste wartości zmiennych, ponieważ funkcja uzyskuje do nich dostęp poprzez adres za pomocą wskaźników. Tutaj omówimy proces programu:
- Deklarujemy funkcję odpowiedzialną za zamianę dwóch wartości zmiennych, która przyjmuje dwa wskaźniki całkowite jako parametry i zwraca dowolną wartość, gdy jest wywoływana.
- W funkcji głównej deklarujemy i inicjalizujemy dwie zmienne całkowite („m” i „n”), a następnie wypisujemy odpowiednio ich wartości.
- Funkcję swap () wywołujemy, przekazując adresy dwóch zmiennych jako argumenty za pomocą symbolu ampersand. Następnie drukujemy nowe zamienione wartości zmiennych.
- Tutaj definiujemy zawartość funkcji swap (), która przyjmuje dwa adresy zmiennych całkowitych jako parametry i deklarujemy tymczasową zmienną całkowitą używaną jako trzeci schowek do zapisania jednej ze zmiennych wartości, która zostanie umieszczona w drugiej zmiennej.
- Zapisz zawartość pierwszej zmiennej wskazywanej przez „a” w zmiennej tymczasowej.
- Przechowuj drugą zmienną wskazywaną przez b w pierwszej zmiennej wskazywanej przez a.
- Zaktualizuj drugą zmienną (wskazywaną przez b) o wartość pierwszej zmiennej zapisanej w zmiennej tymczasowej.
Funkcje z parametrami tablicy
W języku C nie możemy przekazać tablicy według wartości do funkcji. Podczas gdy nazwa tablicy jest wskaźnikiem (adresem), więc po prostu przekazujemy nazwę tablicy do funkcji, co oznacza przekazanie wskaźnika do tablicy.
Na przykład rozważymy następujący program:
int add_array (int *a, int num_elements);int main() {int Tab[5] = {100, 220, 37, 16, 98};printf("Total summation is %d\n", add_array(Tab, 5));return 0;}int add_array (int *p, int size) {int total = 0;int k;for (k = 0; k < size; k++) {total += p[k]; /* it is equivalent to total +=*p ;p++; */}return (total);}
Wynik:
Total summation is 471
Tutaj wyjaśnimy kod programu wraz ze szczegółami
- Deklarujemy i definiujemy funkcję add_array (), która przyjmuje jako parametry adres tablicy (wskaźnik) z liczbą jej elementów i zwraca sumaryczne sumowanie tych elementów. Wskaźnik służy do iteracji elementów tablicy (przy użyciu notacji p [k]), a sumowanie sumujemy w zmiennej lokalnej, która zostanie zwrócona po iteracji całej tablicy elementów.
- Deklarujemy i inicjujemy tablicę liczb całkowitych z pięcioma elementami całkowitymi. Sumę sumowania drukujemy, przekazując nazwę tablicy (która działa jak adres) i rozmiar tablicy do funkcji add_array () zwanej funkcją jako argumenty.
Funkcje, które zwracają tablicę
W C możemy zwrócić wskaźnik do tablicy, jak w poniższym programie:
#includeint * build_array();int main() {int *a;a = build_array(); /* get first 5 even numbers */for (k = 0; k < 5; k++)printf("%d\n", a[k]);return 0;}int * build_array() {static int Tab[5]={1,2,3,4,5};return (Tab);}
Wynik:
12345
Tutaj omówimy szczegóły programu
- Definiujemy i deklarujemy funkcję, która zwraca adres tablicy zawierający wartość całkowitą i nie pobiera żadnych argumentów.
- Deklarujemy wskaźnik całkowity, który otrzymuje pełną tablicę utworzoną po wywołaniu funkcji i drukujemy jej zawartość poprzez iterację całej tablicy składającej się z pięciu elementów.
Zauważ, że wskaźnik, a nie tablica, jest zdefiniowany do przechowywania adresu tablicy zwróconego przez funkcję. Zauważ również, że gdy funkcja zwraca zmienną lokalną, musimy zadeklarować ją jako statyczną w funkcji.
Wskaźniki funkcji
Jak wiemy z definicji, wskaźniki wskazują adres w dowolnej lokalizacji pamięci, mogą również wskazywać na początek kodu wykonywalnego jako funkcje w pamięci.
Wskaźnik do funkcji jest zadeklarowany za pomocą *, ogólna instrukcja jego deklaracji to:
return_type (*function_name)(arguments)
Musisz pamiętać, że nawiasy wokół (* nazwa_funkcji) są ważne, ponieważ bez nich kompilator pomyśli, że nazwa_funkcji zwraca wskaźnik typu return_type.
Po zdefiniowaniu wskaźnika funkcji musimy przypisać go do funkcji. Na przykład następny program deklaruje zwykłą funkcję, definiuje wskaźnik funkcji, przypisuje wskaźnik funkcji do zwykłej funkcji, a następnie wywołuje funkcję za pomocą wskaźnika:
#includevoid Hi_function (int times); /* function */int main() {void (*function_ptr)(int); /* function pointer Declaration */function_ptr = Hi_function; /* pointer assignment */function_ptr (3); /* function call */return 0;}void Hi_function (int times) {int k;for (k = 0; k < times; k++) printf("Hi\n");}
Wynik:
HiHiHi
- Definiujemy i deklarujemy standardową funkcję, która wypisuje tekst Hi k razy wskazany przez parametr razy, gdy funkcja jest wywoływana
- Definiujemy funkcję wskaźnikową (ze specjalną deklaracją), która przyjmuje parametr będący liczbą całkowitą i nic nie zwraca.
- Inicjalizujemy naszą funkcję wskaźnika Hi_function, co oznacza, że wskaźnik wskazuje na Hi_function ().
- Zamiast wywoływania funkcji standardowej przez nagrywanie nazwy funkcji z argumentami, wywołujemy tylko funkcję wskaźnika, przekazując liczbę 3 jako argumenty i to wszystko!
Należy pamiętać, że nazwa funkcji wskazuje na adres początkowy kodu wykonywalnego, podobnie jak nazwa tablicy, która wskazuje na jej pierwszy element. Dlatego instrukcje takie jak function_ptr = & Hi_function i (* funptr) (3) są poprawne.
UWAGA: Nie jest ważne, aby wstawiać operator adresu & i operator pośredni * podczas przypisywania funkcji i wywoływania funkcji.
Tablica wskaźników funkcji
Tablica wskaźników funkcji może odgrywać rolę przełącznika lub instrukcji if przy podejmowaniu decyzji, tak jak w następnym programie:
#includeint sum(int num1, int num2);int sub(int num1, int num2);int mult(int num1, int num2);int div(int num1, int num2);int main(){ int x, y, choice, result;int (*ope[4])(int, int);ope[0] = sum;ope[1] = sub;ope[2] = mult;ope[3] = div;printf("Enter two integer numbers: ");scanf("%d%d", &x, &y);printf("Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: ");scanf("%d", &choice);result = ope[choice](x, y);printf("%d", result);return 0;}int sum(int x, int y) {return(x + y);}int sub(int x, int y) {return(x - y);}int mult(int x, int y) {return(x * y);}int div(int x, int y) {if (y != 0) return (x / y); else return 0;}
Enter two integer numbers: 13 48Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2624
Tutaj omawiamy szczegóły programu:
- Deklarujemy i definiujemy cztery funkcje, które pobierają dwa argumenty w postaci liczb całkowitych i zwracają wartość całkowitą. Funkcje te dodają, odejmują, mnożą i dzielą dwa argumenty dotyczące tego, która funkcja jest wywoływana przez użytkownika.
- Deklarujemy 4 liczby całkowite do obsługi odpowiednio operandów, typu operacji i wyniku. Ponadto deklarujemy tablicę czterech wskaźników funkcji. Każdy wskaźnik funkcji elementu tablicy przyjmuje dwa parametry będące liczbami całkowitymi i zwraca wartość całkowitą.
- Przypisujemy i inicjalizujemy każdy element tablicy z już zadeklarowaną funkcją. Na przykład trzeci element, który jest trzecim wskaźnikiem funkcji, będzie wskazywał na funkcję operacji mnożenia.
- Szukamy operandów i rodzaju operacji od użytkownika wpisanego za pomocą klawiatury.
- Wywołaliśmy odpowiedni element tablicy (wskaźnik funkcji) z argumentami i przechowujemy wynik wygenerowany przez odpowiednią funkcję.
Instrukcja int (* ope [4]) (int, int); definiuje tablicę wskaźników funkcji. Każdy element tablicy musi mieć te same parametry i zwracany typ.
Wynik instrukcji = ope [wybór] (x, y); uruchamia odpowiednią funkcję zgodnie z wyborem dokonanym przez użytkownika. Dwie wprowadzone liczby całkowite to argumenty przekazywane do funkcji.
Funkcje wykorzystujące wskaźniki void
Puste wskaźniki są używane podczas deklaracji funkcji. Używamy void * return type zezwalających na zwracanie dowolnego typu. Jeśli założymy, że nasze parametry nie zmieniają się podczas przekazywania do funkcji, deklarujemy ją jako stałą.
Na przykład:
void * cube (const void *);
Rozważ następujący program:
#includevoid* cube (const void* num);int main() {int x, cube_int;x = 4;cube_int = cube (&x);printf("%d cubed is %d\n", x, cube_int);return 0;}void* cube (const void *num) {int result;result = (*(int *)num) * (*(int *)num) * (*(int *)num);return result;}
Wynik:
4 cubed is 64
Tutaj omówimy szczegóły programu:
- Definiujemy i deklarujemy funkcję, która zwraca wartość całkowitą i przyjmuje adres niezmiennej zmiennej bez określonego typu danych. Obliczamy wartość sześcianu zmiennej zawartości (x) wskazywanej przez wskaźnik num, a ponieważ jest to wskaźnik void, musimy wpisać rzut na typ danych całkowitoliczbowych przy użyciu określonego wskaźnika notacji (* typ danych) i zwracamy wartość kostki.
- Deklarujemy operand i zmienną wynikową. Ponadto inicjalizujemy nasz operand wartością „4”.
- Funkcję kostki wywołujemy, przekazując adres argumentu i obsługujemy zwracaną wartość w zmiennej wynikowej
Wskaźniki funkcji jako argumenty
Innym sposobem wykorzystania wskaźnika funkcji przez przekazanie go jako argumentu do innej funkcji, czasami nazywanej „funkcją zwrotną”, ponieważ funkcja odbierająca „wywołuje ją z powrotem”.
W pliku nagłówkowym stdlib.h funkcja Quicksort "qsort ()" wykorzystuje tę technikę, która jest algorytmem przeznaczonym do sortowania tablicy.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void * base: void wskaźnik do tablicy.
- size_t num: numer elementu tablicy.
- size_t width Rozmiar elementu.
- int (* compare (const void *, const void *): wskaźnik funkcji złożony z dwóch argumentów i zwraca 0, gdy argumenty mają tę samą wartość, <0, gdy arg1 występuje przed arg2 i> 0, gdy arg1 występuje po arg2.
Poniższy program sortuje tablicę liczb całkowitych od małej do dużej przy użyciu funkcji qsort ():
#include#include int compare (const void *, const void *);int main() {int arr[5] = {52, 14, 50, 48, 13};int num, width, i;num = sizeof(arr)/sizeof(arr[0]);width = sizeof(arr[0]);qsort((void *)arr, num, width, compare);for (i = 0; i < 5; i++)printf("%d ", arr[ i ]);return 0;}int compare (const void *elem1, const void *elem2) {if ((*(int *)elem1) == (*(int *)elem2)) return 0;else if ((*(int *)elem1) < (*(int *)elem2)) return -1;else return 1;}
Wynik:
13 14 48 50 52
Tutaj omówimy szczegóły programu:
- Definiujemy funkcję porównania złożoną z dwóch argumentów i zwraca 0, gdy argumenty mają tę samą wartość, <0, gdy arg1 występuje przed arg2 i> 0, gdy arg1 występuje po arg2 Parametry są typem wskaźników void rzutowanym na odpowiedni typ danych tablicy (liczba całkowita)
- Definiujemy i inicjalizujemy tablicę liczb całkowitych Rozmiar tablicy jest przechowywany w zmiennej num , a rozmiar każdego elementu tablicy jest przechowywany w zmiennej szerokości za pomocą predefiniowanego operatora C sizeof ().
- Nazywamy qsort funkcję i podać nazwę tablicy, rozmiar, szerokość i funkcji porównującej zdefiniowanej uprzednio przez użytkownika w celu uporządkować naszą tablicę w rosnąco order.The porównania będą wykonywane przez biorąc w każdej iteracji dwóch elementów tablicy do całej tablicy zostaną posortowane.
- Drukujemy elementy tablicy, aby upewnić się, że nasza tablica jest dobrze posortowana, wykonując iterację całej tablicy za pomocą pętli for.