Funktioner Pointere i C-programmering med eksempler

โšก Smart opsummering

Funktionspointere i C gemmer adressen pรฅ eksekverbar kode, hvilket lader programmer kalde funktioner indirekte, sende dem som argumenter, bygge forsendelsestabeller fra arrays og implementere tilbagekald sรฅsom qsort-sammenligningsrutinen for fleksible, genanvendelige designs.

  • ๐Ÿ”— Erklรฆring: En funktionspointer bruger formen return_type(*name)(arguments); parenteserne omkring navnet er obligatoriske.
  • ๐Ÿ”„ Byt efter adresse: Ved at sende variable adresser til pointerparametre kan en funktion รฆndre den, der kalder den,s oprindelige vรฆrdier, som i swap-eksemplet.
  • ๐Ÿ“ฆ Arrays: Et arraynavn er allerede en pointer, sรฅ funktioner kan modtage et array eller returnere en pointer til et statisk array.
  • ๐ŸŽ›๏ธ Forsendelsestabeller: En rรฆkke funktionspointere erstatter lange switch- eller if-kรฆder ved at indeksere direkte til den valgte operation.
  • ๐ŸงŠ tomrumspointere: En void * parameter eller returtype accepterer enhver type, som funktionen bruger som caster tilbage fรธr brug.
  • ๐Ÿ“ž Tilbagekald: At sende en funktionspointer som et argument driver callbacks som f.eks. qsort-sammenligningsfunktionen.
  • ๐Ÿค– AI assistance: GitHub Copilot og AI-assistenter scaffolder funktionspointersyntaks, typedefs og callback-signaturer og markerer derefter uoverensstemmende parametre.

Funktionspointere i C

Pointere giver store muligheder for 'C'-funktioner, som vi er begrรฆnset til at returnere รฉn vรฆrdi. Med pointerparametre kan vores funktioner nu behandle faktiske data i stedet for en kopi af data.

For at รฆndre de faktiske vรฆrdier af variabler, sender den kaldende sรฆtning adresser til pointerparametre i en funktion.

Funktioner Pointers Eksempel

For eksempel bytter det nรฆste program to vรฆrdier af to:

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;}
}

Output:

m is 25, n is 100
m is 100, n is 25

Funktioner Pointers Eksempel

Programmet bytter de faktiske variable vรฆrdier, fordi funktionen tilgรฅr dem ved at bruge adresse pointer. Her vil vi diskutere programprocessen:

  1. Vi erklรฆrer den funktion, der er ansvarlig for swapping de to variable vรฆrdier, som tager to heltalspegere som parametre og returnerer en hvilken som helst vรฆrdi, nรฅr den kaldes.
  2. I hovedfunktionen erklรฆrer og initialiserer vi to heltalsvariabler ('m' og 'n'), og derefter udskriver vi deres vรฆrdier.
  3. Vi kalder swap()-funktionen ved at sende adressen pรฅ de to variable som argumenter ved hjรฆlp af og-tegnet. Derefter udskriver vi de nye ombyttede vรฆrdier af variabler.
  4. Her definerer vi swap()-funktionens indhold, som tager to heltalsvariableadresser som parametre og erklรฆrer en midlertidig heltalsvariabel brugt som en tredje lagerboks for at gemme en af โ€‹โ€‹vรฆrdivariablerne, som vil blive sat til den anden variabel.
  5. Gem indholdet af den fรธrste variabel peget med 'a' i den midlertidige variabel.
  6. Gem den anden variabel, der peges af b, i den fรธrste variabel, der peges af a.
  7. Opdater den anden variabel (peget med b) med vรฆrdien af โ€‹โ€‹den fรธrste variabel gemt i den midlertidige variabel.

Funktioner med array-parametre

I C kan vi ikke videregive en matrix efter vรฆrdi til en funktion. Hvorimod et arraynavn er en pointer (adresse), sรฅ vi sender bare et arraynavn til en funktion, som betyder at sende en pointer til arrayet.

For eksempel overvejer vi fรธlgende 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);}

Output:

 Total summation is 471

Her vil vi forklare programkoden med dens detaljer

Funktioner med array-parametre

  1. Vi erklรฆrer og definerer add_array() funktion, som tager en array-adresse(pointer) med dens elementnummer som parametre og returnerer den samlede akkumulerede summering af disse elementer. Pointeren bruges til at iterere array-elementerne (ved hjรฆlp af p[k]-notationen), og vi akkumulerer summeringen i en lokal variabel, som vil blive returneret efter iteration af hele element-arrayet.
  2. Vi erklรฆrer og initialiserer et heltalsarray med fem heltalselementer. Vi udskriver den samlede summering ved at sende matrixnavnet (som fungerer som adresse) og matrixstรธrrelsen til add_array()kaldet funktion som argumenter.

Funktioner, der returnerer et array

I C kan vi returnere en pointer til et array, som i fรธlgende program:

#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);}

Output:

1
2
3
4
5

Og her vil vi diskutere programdetaljerne

Funktioner, der returnerer et array

  1. Vi definerer og erklรฆrer en funktion, som returnerer en matrixadresse, der indeholder en heltalsvรฆrdi, og som ikke tog nogen argumenter.
  2. Vi erklรฆrer en heltalsmarkรธr, som modtager det komplette array, der er bygget efter funktionen kaldes, og vi udskriver dets indhold ved at iterere hele arrayet med fem elementer.

Bemรฆrk, at en pointer, ikke et array, er defineret til at gemme arrayadressen, der returneres af funktionen. Bemรฆrk ogsรฅ, at nรฅr en lokal variabel returneres fra en funktion, skal vi erklรฆre den som statisk i funktionen.

Funktionsvisere

Som vi per definition ved, at pointere peger pรฅ en adresse i enhver hukommelsesplacering, kan de ogsรฅ pege pรฅ i begyndelsen af โ€‹โ€‹eksekverbar kode som funktioner i hukommelsen.
En pointer til funktion erklรฆres med *, den generelle erklรฆring i dens erklรฆring er:

return_type (*function_name)(arguments)

Du skal huske, at parenteserne omkring (*funktionsnavn) er vigtige, for uden dem vil compileren tro, at funktionsnavnet returnerer en pointer af returtype.
Efter at have defineret funktionsmarkรธren, skal vi tildele den til en funktion. For eksempel erklรฆrer det nรฆste program en almindelig funktion, definerer en funktionsmarkรธr, tildeler funktionsmarkรธren til den almindelige funktion og kalder derefter funktionen gennem markรธren:

#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");}

Output:

Hi
Hi
Hi

Funktioner pointere i C

  1. Vi definerer og erklรฆrer en standardfunktion, som udskriver en Hi-tekst k gange angivet med parameteren gange, nรฅr funktionen kaldes
  2. Vi definerer en pointerfunktion (med dens specielle erklรฆring), som tager en heltalsparameter og ikke returnerer noget.
  3. Vi initialiserer vores pointerfunktion med Hi_function, hvilket betyder at pointer peger pรฅ Hi_function().
  4. I stedet for standardfunktionskaldet fra taping funktionsnavnet med argumenter, vi kalder kun pointerfunktionen ved at sende tallet 3 som argumenter, og det er det!

Husk, at funktionsnavnet peger pรฅ startadressen for den eksekverbare kode som et arraynavn, der peger pรฅ dets fรธrste element. Derfor er instruktioner som function_ptr = &Hi_function og (*funptr)(3) korrekte.
BEMร†RK: Det er ikke vigtigt at indsรฆtte adresseoperatรธren & og indirektionsoperatรธren * under funktionstildelingen og funktionskaldet.

Array af funktionspointere

En rรฆkke funktionspointere kan spille en switch eller en if-sรฆtningsrolle for at trรฆffe en beslutning, som i det nรฆste program:

#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

Her diskuterer vi programdetaljerne:

Array af funktionspointere

  1. Vi erklรฆrer og definerer fire funktioner som tager to heltalsargumenter og returnerer en heltalsvรฆrdi. Disse funktioner lรฆgger til, subderertract, gang og divider de to argumenter vedrรธrende hvilken funktion der kaldes af brugeren.
  2. Vi erklรฆrer 4 heltal til at hรฅndtere henholdsvis operander, operationstype og resultat. Vi erklรฆrer ogsรฅ en matrix med fire funktionsmarkรธrer. Hver funktionsmarkรธr af array-element tager to heltalsparametre og returnerer en heltalsvรฆrdi.
  3. Vi tildeler og initialiserer hvert array-element med den funktion, der allerede er erklรฆret. For eksempel vil det tredje element, som er den tredje funktionsmarkรธr, pege pรฅ multiplikationsoperationsfunktionen.
  4. Vi sรธger operander og operationstype fra brugeren, der indtastes med tastaturet.
  5. Vi kaldte det passende array-element (Function pointer) med argumenter, og vi gemmer resultatet genereret af den relevante funktion.

Instruktionen int (*ope[4])(int, int); definerer rรฆkken af โ€‹โ€‹funktionspointere. Hvert array-element skal have samme parametre og returtype.
Udsagnsresultatet = ope[valg](x, y); kรธrer den passende funktion i henhold til brugerens valg. De to indtastede heltal er de argumenter, der sendes til funktionen.

Funktioner Brug af void pointers

Ugyldige pointere bruges under funktionserklรฆringer. Vi bruger en void * returtype tillader at returnere enhver type. Hvis vi antager, at vores parametre ikke รฆndrer sig, nรฅr de overfรธres til en funktion, erklรฆrer vi den som const.
For eksempel:

 void * cube (const void *);

Overvej fรธlgende program:

#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;}

Resultat:

 4 cubed is 64

Her vil vi diskutere programdetaljerne:

Funktioner Brug af void pointers

  1. Vi definerer og erklรฆrer en funktion, der returnerer en heltalvรฆrdi og tager en adresse med en uforanderlig variabel uden en specifik datatype. Vi beregner kubevรฆrdien af โ€‹โ€‹indholdsvariablen (x) peget af num-markรธren, og da det er en void-pointer, skal vi skrive cast den til en heltalsdatatype ved hjรฆlp af en specifik notation (* datatype) pointer, og vi returnerer terningvรฆrdien.
  2. Vi erklรฆrer operanden og resultatvariablen. Vi initialiserer ogsรฅ vores operand med vรฆrdien "4."
  3. Vi kalder kubefunktionen ved at sende operandadressen, og vi hรฅndterer den returnerende vรฆrdi i resultatvariablen

Fungerer pointere som argumenter

En anden mรฅde at udnytte en funktionsmarkรธr pรฅ ved at overfรธre den som et argument til en anden funktion, nogle gange kaldet "tilbagekaldsfunktion", fordi den modtagende funktion "kalder den tilbage."
I stdlib.h header-filen bruger Quicksort "qsort()"-funktionen denne teknik, som er en algoritme dedikeret til at sortere et array.

void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
  • void *base: void pointer til arrayet.
  • size_t num : Array-elementnummeret.
  • size_t width Elementstรธrrelsen.
  • int (*compare (const void *, const void *): funktionsmarkรธr sammensat af to argumenter og returnerer 0, nรฅr argumenterne har samme vรฆrdi, <0, nรฅr arg1 kommer fรธr arg2, og >0, nรฅr arg1 kommer efter arg2.

Fรธlgende program sorterer et heltalsmatrix fra lille til stort tal ved hjรฆlp af qsort()-funktionen:

#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;}

Resultat:

 13 14 48 50 52

Her vil vi diskutere programdetaljerne:

Fungerer pointere som argumenter

  1. Vi definerer en sammenligningsfunktion sammensat af to argumenter og returnerer 0, nรฅr argumenterne har samme vรฆrdi, <0, nรฅr arg1 kommer fรธr arg2, og >0, nรฅr arg1 kommer efter arg2. (heltal)
  2. Vi definerer og initialiserer et heltalsarray Matrixstรธrrelsen er gemt i num variabel og stรธrrelsen af โ€‹โ€‹hvert array-element gemmes i breddevariabel ved hjรฆlp af sizeof() foruddefineret C operatรธr.
  3. Vi kalder qsort-funktionen og sender arraynavnet, stรธrrelsen, bredden og den sammenligningsfunktion, som brugeren tidligere har defineret, for at sortere vores array i stigende rรฆkkefรธlge. Sammenligningen udfรธres ved at inkludere to array-elementer i hver iteration, indtil hele arrayet er sorteret.
  4. Vi udskriver array-elementerne for at vรฆre sikre pรฅ, at vores array er godt sorteret ved at iterere hele arrayet vha. til lรธkke.

Ofte Stillede Spรธrgsmรฅl

Ja. En funktionspointer skal matche mรฅlfunktionens returtype og parameterliste nรธjagtigt. At tildele en funktion med en anden signatur er udefineret adfรฆrd, selvom den kompilerer, fordi kaldet ville pushe og lรฆse argumenter forkert under kรธrsel.

typedef giver en kompleks funktionspointertype et kort navn. Skrivning af typedef int (*Operation)(int, int); lader dig deklarere Operation add; i stedet for at gentage den fulde pointer-syntaks, hvilket gรธr arrays, parametre og struct-medlemmer langt nemmere at lรฆse.

Funktionspointere driver callbacks, jump- eller dispatch-tabeller, plugin- og event-driven systemer, tilstandsmaskiner og biblioteksrutiner som qsort og bsearch. OperaTing-systemer og indlejret firmware er afhรฆngige af dem til at vรฆlge adfรฆrd under kรธrsel uden lange betingede kรฆder.

En datapointer indeholder adressen pรฅ en variabel i hukommelsen, mens en funktionspointer indeholder indgangsadressen for eksekverbar kode. Du kalder funktionen via en funktionspointer i stedet for at dereferere den for at lรฆse eller skrive data.

Ja. En funktionspointer kan sรฆttes til NULL, hvilket betyder, at der ikke er tildelt nogen funktion. Kald af en NULL-funktionspointer forรฅrsager udefineret adfรฆrd, sรฅ beskyt kaldet med if (ptr != NULL), fรธr det kaldes, isรฆr for valgfrie tilbagekald.

Ja. Ved at placere funktionspointere som strukturmedlemmer kan en struktur bundte data med relaterede operationer, imitere objekter og virtuelle metodetabeller. Dette mรธnster ligger til grund for mange C-biblioteker og enhedsdrivere, hvor hver instans vรฆlger sine egne funktionsimplementeringer.

Ja. En AI-kodningsassistent kan generere funktionspointerdeklarationer, typedefineringer og callback-signaturer fra en prompt i et letforstรฅeligt sprog, forklare forvirrende syntaks og finde uoverensstemmelser i parametre eller returtyper. Kompilรฉr og test altid den foreslรฅede kode, fรธr du stoler pรฅ den.

GitHub Copilot foreslรฅr funktionspointersyntaks, fuldfรธrer callback-indhold fra en kommentar eller signatur og foreslรฅr qsort-sammenligningsfunktioner. ร…bn de relevante header-filer, sรฅ deres fuldfรธrelser matcher dine deklarerede prototyper, og gennemgรฅ derefter logikken.

Opsummer dette indlรฆg med: