Toiminnot Osoittimet C-ohjelmointiin esimerkkien kanssa
⚡ Älykäs yhteenveto
C-kielen funktio-osoittimet tallentavat suoritettavan koodin osoitteen, jolloin ohjelmat voivat kutsua funktioita epäsuorasti, välittää niitä argumentteina, rakentaa lähetystaulukoita taulukoista ja toteuttaa takaisinkutsuja, kuten qsort-vertailurutiinin, joustavia ja uudelleenkäytettäviä malleja varten.
Osoittimet antavat suuria mahdollisuuksia 'C'-funktioille, jotka rajoitamme palauttamaan yhden arvon. Osoitinparametreilla funktiomme voivat nyt käsitellä todellisia tietoja tietojen kopion sijaan.
Muuttujien todellisten arvojen muokkaamiseksi kutsuva käsky välittää osoitteita funktion osoitinparametreille.
Toiminnot Osoittimet Esimerkki
Esimerkiksi seuraava ohjelma vaihtaa kaksi arvoa kahdesta:
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;} }
lähtö:
m is 25, n is 100 m is 100, n is 25
Ohjelma vaihtaa todelliset muuttujien arvot, koska funktio käyttää niitä osoitteen avulla osoitin. Täällä keskustelemme ohjelmaprosessista:
- Julistamme swapista vastaavan funktionping kaksi muuttujan arvoa, joka ottaa parametreina kaksi kokonaislukuosoitinta ja palauttaa minkä tahansa arvon kutsuttaessa.
- Pääfunktiossa julistamme ja alustamme kaksi kokonaislukumuuttujaa ('m' ja 'n') ja sitten tulostamme niiden arvot vastaavasti.
- Kutsumme swap()-funktiota välittämällä näiden kahden muuttujan osoitteet argumenteiksi et-symbolilla. Tämän jälkeen tulostetaan muuttujien uudet vaihdetut arvot.
- Tässä määritellään swap()-funktion sisältö, joka ottaa kaksi kokonaislukumuuttujan osoitetta parametreiksi ja ilmoittaa väliaikaisen kokonaislukumuuttujan, jota käytetään kolmantena tallennuslaatikkona tallentaakseen yhden arvomuuttujista, jotka asetetaan toiseen muuttujaan.
- Tallenna väliaikaismuuttujan ensimmäisen muuttujan sisältö, jota osoittaa 'a'.
- Tallenna toinen b:llä osoittama muuttuja ensimmäiseen a:lla osoittamaan muuttujaan.
- Päivitä toinen muuttuja (osoitti b:llä) väliaikaiseen muuttujaan tallennetun ensimmäisen muuttujan arvolla.
Toimii taulukkoparametreilla
C:ssä emme voi välittää taulukkoa funktiolle arvon mukaan. Sen sijaan taulukon nimi on osoitin (osoite), joten välitämme vain taulukon nimen funktiolle, joka tarkoittaa osoittimen välittämistä taulukkoon.
Tarkastellaan esimerkiksi seuraavaa ohjelmaa:
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);}
lähtö:
Total summation is 471
Tässä selitämme ohjelmakoodin ja sen yksityiskohdat
- Ilmoitamme ja määritämme add_array()-funktion, joka ottaa taulukon osoitteen (osoitin) elementtinumeroineen parametreina ja palauttaa näiden elementtien kokonaissumman. Osoitinta käytetään taulukon elementtien iterointiin (p[k]-merkinnällä), ja keräämme summauksen paikalliseen muuttujaan, joka palautetaan koko elementtitaulukon iteroinnin jälkeen.
- Ilmoitamme ja alustamme kokonaislukutaulukon, jossa on viisi kokonaislukuelementtiä. Tulostamme kokonaissumman välittämällä taulukon nimen (joka toimii osoitteena) ja taulukon koon add_array()kutsutaan funktioksi argumenteiksi.
Funktiot, jotka palauttavat taulukon
C:ssä voimme palauttaa osoittimen taulukkoon, kuten seuraavassa ohjelmassa:
#include <stdio.h> int * 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);}
lähtö:
1 2 3 4 5
Ja täällä keskustelemme ohjelman yksityiskohdista
- Määrittelemme ja ilmoittamme funktion, joka palauttaa taulukon osoitteen, joka sisältää kokonaisluvun arvon eikä ottanut argumentteja.
- Ilmoitamme kokonaislukuosoittimen, joka vastaanottaa funktion kutsumisen jälkeen rakennetun taulukon ja tulostamme sen sisällön iteroimalla koko viiden elementin taulukon.
Huomaa, että osoitin, ei taulukko, on määritetty tallentamaan funktion palauttama taulukko-osoite. Huomaa myös, että kun funktiosta palautetaan paikallinen muuttuja, meidän on ilmoitettava se funktiossa staattiseksi.
Toimintoosoittimet
Kuten määritelmän mukaan tiedämme, osoittimet osoittavat missä tahansa muistipaikassa olevaan osoitteeseen, ne voivat osoittaa myös suoritettavan koodin alkuun funktioina muistissa.
Osoitin toimintoon on ilmoitettu *:lla, sen julistuksen yleinen lauseke on:
return_type (*function_name)(arguments)
Sinun on muistettava, että sulut ympärillä (*funktion_nimi) ovat tärkeitä, koska ilman niitä kääntäjä luulee, että funktion_nimi palauttaa osoittimen paluutyypin.
Kun toimintoosoitin on määritetty, se on määritettävä funktiolle. Esimerkiksi seuraava ohjelma määrittelee tavallisen funktion, määrittelee funktioosoittimen, määrittää funktioosoittimen tavalliselle funktiolle ja sen jälkeen kutsuu funktiota osoittimen kautta:
#include <stdio.h> void 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");}
lähtö:
Hi Hi Hi
- Määrittelemme ja julistamme vakiofunktion, joka tulostaa Hi-tekstin k kertaa parametrien osoittaman kerran, kun funktiota kutsutaan
- Määrittelemme osoitinfunktion (erityisen ilmoituksensa kanssa), joka ottaa kokonaislukuparametrin eikä palauta mitään.
- Alustamme osoitinfunktiomme Hi_funktiolla, mikä tarkoittaa, että osoitin osoittaa Hi_function().
- Sen sijaan, että ta kutsuisi standardifunktiotaping funktion nimi argumentteineen, kutsumme vain osoitinfunktiota antamalla argumentteina luvun 3, ja siinä kaikki!
Muista, että funktion nimi osoittaa suoritettavan koodin aloitusosoitteeseen, kuten taulukon nimi, joka osoittaa sen ensimmäiseen elementtiin. Siksi ohjeet kuten function_ptr = &Hi_function ja (*funptr)(3) ovat oikein.
HUOMAA: Ei ole tärkeää syöttää osoiteoperaattoria & ja välioperaattoria * toimintomäärityksen ja toimintokutsun aikana.
Joukko funktioosoittimia
Joukko funktioosoittimia voi toimia kytkin- tai if-lauseroolina päätöksenteossa, kuten seuraavassa ohjelmassa:
#include <stdio.h> int 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 48
Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2
624
Täällä keskustelemme ohjelman yksityiskohdista:
- Ilmoitamme ja määrittelemme neljä tehtävät jotka ottavat kaksi kokonaislukuargumenttia ja palauttavat kokonaislukuarvon. Nämä funktiot summaavat, sub-argumentittract, kerro ja jaa kaksi argumenttia sen mukaan, mitä funktiota käyttäjä kutsuu.
- Ilmoitamme 4 kokonaislukua käsittelemään operandeja, operaatiotyyppiä ja tulosta vastaavasti. Ilmoitamme myös neljän funktion osoittimen taulukon. Jokainen taulukkoelementin funktioosoitin ottaa kaksi kokonaislukuparametria ja palauttaa kokonaisluvun arvon.
- Määritämme ja alustamme jokaisen taulukon elementin jo määritetyllä funktiolla. Esimerkiksi kolmas elementti, joka on kolmas funktioosoitin, osoittaa kertolaskutoimintoon.
- Haemme operandeja ja toimintotyyppiä käyttäjältä, joka on kirjoitettu näppäimistöllä.
- Kutsuimme sopivaa taulukkoelementtiä (Function pointer) argumenteilla ja tallennamme sopivan funktion luoman tuloksen.
Käsky int (*ope[4])(int, int); määrittää funktioosoittimien joukon. Jokaisella taulukon elementillä on oltava samat parametrit ja palautustyyppi.
Lausunnon tulos = ope[valinta](x, y); suorittaa oikean funktion käyttäjän valinnan mukaan. Kaksi syötettyä kokonaislukua ovat funktiolle välitettyjä argumentteja.
Toiminnot tyhjien osoittimien käyttäminen
Void-osoittimia käytetään funktion määrittelyissä. Käytämme void *-palautustyyppiä, joka sallii minkä tahansa tyypin palauttamisen. Jos oletetaan, että parametrimme eivät muutu siirryttäessä funktioon, julistetaan se const.
Esimerkiksi:
void * cube (const void *);
Harkitse seuraavaa ohjelmaa:
#include <stdio.h> void* 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;}
Tulos:
4 cubed is 64
Täällä keskustelemme ohjelman yksityiskohdista:
- Määrittelemme ja ilmoittamme funktion, joka palauttaa kokonaisluvun arvon ja ottaa muuttumattoman muuttujan osoitteen ilman tiettyä tietotyyppiä. Laskemme num-osoittimella osoittaman sisältömuuttujan (x) kuution arvon, ja koska se on tyhjä osoitin, meidän on kirjoitettava se kokonaislukutietotyyppiin käyttämällä tiettyä merkintä (* tietotyyppi) -osoitinta ja palautetaan kuution arvo.
- Ilmoitamme operandin ja tulosmuuttujan. Lisäksi alustamme operandimme arvolla "4".
- Kutsumme kuutiofunktiota välittämällä operandiosoitteen ja käsittelemme palautusarvon tulosmuuttujassa
Funktioosoittimet argumentteina
Toinen tapa hyödyntää funktioosoitinta välittämällä se argumenttina toiselle funktiolle, jota joskus kutsutaan "takaisinkutsufunktioksi", koska vastaanottava funktio "kutsuu sen takaisin".
Otsikkotiedostossa stdlib.h Quicksort "qsort()" -funktio käyttää tätä tekniikkaa, joka on taulukon lajitteluun tarkoitettu algoritmi.
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void *base: tyhjä osoitin taulukkoon.
- size_t num : Matriisielementin numero.
- size_t width Elementin koko.
- int (*vertaa (const void *, const void *) : funktioosoitin, joka koostuu kahdesta argumentista ja palauttaa arvon 0, kun argumenteilla on sama arvo, <0, kun arg1 tulee ennen arg2:ta ja >0, kun arg1 tulee arg2:n jälkeen.
Seuraava ohjelma lajittelee kokonaislukutaulukon pienestä suureen käyttämällä qsort()-funktiota:
#include <stdio.h> #include <stdlib.h> 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;}
Tulos:
13 14 48 50 52
Täällä keskustelemme ohjelman yksityiskohdista:
- Määrittelemme vertailufunktion, joka koostuu kahdesta argumentista ja palauttaa arvon 0, kun argumenteilla on sama arvo, <0, kun arg1 tulee ennen arg2:ta ja >0, kun arg1 tulee arg2:n jälkeen. Parametrit ovat tyhjiä osoittimia, jotka on heitetty sopivaan taulukon tietotyyppiin (kokonaisluku)
- Määrittelemme ja alustamme kokonaislukutaulukon Taulukon koko on tallennettu num muuttuja ja kunkin taulukon elementin koko tallennetaan leveysmuuttujaan käyttämällä sizeof() ennalta määritettyä C-operaattori.
- Kutsumme qsort-funktiota ja välitämme käyttäjän aiemmin määrittämän taulukon nimen, koon, leveyden ja vertailufunktion lajitellaksemme taulukon nousevaan järjestykseen. Vertailu suoritetaan ottamalla jokaisessa iteraatiossa kaksi taulukon alkiota, kunnes koko taulukko on lajiteltu.
- Tulostamme taulukon elementit varmistaaksemme, että taulukkomme on hyvin lajiteltu iteroimalla koko taulukko käyttämällä silmukalle.








