Zeiger auf Funktion in C

Von: , Frage gestellt am Di, 10. Nov 2009

Hallo zusammen.

Im folgenden C-Programm verstehe ich einige Sachen nicht. Kann mir das jemand verdeutlichen?

#include "stdio.h"
#include "conio.h"
main()
{
int iarr[10]={2,3,8,1,43,13,22,32,11,7};
float farr[10]={...};
char sarr[10][20]={"Zeus\0","Hera\0","Athena\0","Artemis\0"....};
int i;
int iswap(),fswap(),sswap();
clrscr();
for(i=0;i<10;i++) printf("%3d %8.2f %s\n",iarr[i],farr[i],sarr[i];
printf("\n");
sort(iarr,iswap);
sort(farr, fswap);
sort(sarr,sswap);
....
getch();
}


1) Die Zeile int iswap(),fswap(),sswap() war mit "Declaration der Funktionspointer" kommentiert. Diese müssen aber doch nach dem Schema *iswap()... deklariert werden. Oder?

2) Der Aufruf sort(iarr,iswap) . Das ist eine Funktion oder Unterprogramm. Und dieser muss vorher bekannt gegeben worden sein. Ist er aber nicht. Kann das so funktionieren?

3) Generelle Frage. In der Zeile char sarr[10][20]={"Zeus\0".. wird ein mehrdimens. Array beschrieben. Wie werden Elemente beim schreiben in ein solches Adressiert? Passiert das hier überhaupt?

Nach dem Hauptprogramm kommt die sort Routine.

sort(void *v, int (*swp)())
{
int i,m;
...}


4) Es werden hier 2 Zeiger *v und *swp verwendet die aber vorher nirgendwo deklariert sind. Und mir ist nicht klar wohin die zeigen.


Danke an alle

3 Antworten zu dieser Frage

  1. Antwort von nach 3 Stunden 0 hilfreich
    Re: Zeiger auf Funktion in C

    Hossa :)

    #include "stdio.h"
    #include "conio.h"
    :main()
    {
    int iarr[10]={2,3,8,1,43,13,22,32,11,7};
    float farr[10]={...};
    char sarr[10][20]={"Zeus\0","Hera\0","Athena\0","Artemis\0"....};
    int i;
    int iswap(),fswap(),sswap();
    clrscr();
    for(i=0;i<10;i++) printf("%3d %8.2f%s\n",iarr[i],farr[i],sarr[i];
    printf("\n");
    sort(iarr,iswap);
    sort(farr, fswap);
    sort(sarr,sswap);
    ....
    getch();
    }
    
    1) Die Zeile int iswap(),fswap(),sswap() war mit
    "Declaration der Funktionspointer" kommentiert. Diese müssen
    aber doch nach dem Schema *iswap()... deklariert
    werden. Oder?
    Was da im Quelltext steht sind Funktions-Prototypen, also Deklarationen von Funktionen, die anderswo definiert werden. Mit Zeigern auf Funktionen hat das nichts zu tun. Ich vermute mal, dass weiter unten im Quelltext die swap-Funktionen definiert sind. Durch die Prototypen werden die Funktionen dem Compiler schon vor ihrer Definition bekannt gemacht, so dass sie innerhalb der main-Funktion verwendet werden können. 2) Der Aufruf sort(iarr,iswap) . Das ist eine Funktion
    oder Unterprogramm. Und dieser muss vorher bekannt gegeben
    worden sein. Ist er aber nicht. Kann das so funktionieren?
    Ähnlich wie die Funktion "iswap" ist auch die Funktion "sort" nirgendwo sichtbar definiert. Daher muss zumindest die Deklaration mittels #include in den Quelltext eingebunden werden. Daher kann das so nicht funktionieren, weder die Swap-Funktionen noch die Funktion sort sind in <stdio.h> oder in <conio.h> deklariert. 3) Generelle Frage. In der Zeile char
    sarr[10][20]={"Zeus\0"..
    wird ein mehrdimens. Array
    beschrieben. Wie werden Elemente beim schreiben in ein solches
    Adressiert? Passiert das hier überhaupt?
    In C wird sarr als lineares Array mit 231 Elementen behandelt. Der Compiler nummeriert sie sozusagen linear durch und verwandelt einen Ausdruck der Form sarr[i][k] intern in sarr[21*i+k]. Beim Befüllen läuft sozusagen der rechte Index von 0 bis 20 hoch. Dann springt der linke Index um 1 nach oben und der rechte beginnt wieder bei 0. Nach dem Hauptprogramm kommt die sort Routine.
    Das Problem ist, dass die sort-Routine aufgerufen wird, bevor der Compiler weiß, was der Bezeichner sort bedeutet. Entweder muss die sort-Routine daher vor die main-Funktion gesetzt werden oder es muss ein Prototyp von sort vor der ersten Verwendung angegeben werden.

    sort(void *v, int (*swp)())
    {
    int i,m;
    ...}
    
    4) Es werden hier 2 Zeiger *v und *swp verwendet
    die aber vorher nirgendwo deklariert sind. Und mir ist nicht
    klar wohin die zeigen.
    Diese Zeiger werden durch die Parameterdeklaration definiert. Der Compiler weiß durch die Funktionsdefinition, was die Bezeichner v und swp sein sollen. Diese Bezeichner werden beim Aufruf der Funktion durch die entsprechenen Parameter befüllt.

    sort(iarr,iswap); ==> v=iarr, swp=iswap

    Tatsächlich werden alle Parameter einer Funktion als interne Variablen der Funktion behandelt, die auf dem Stack angelegt werden.

    Viele Grüße

    • Antwort von nach 4 Stunden 0 hilfreich
      Re^2: Zeiger auf Funktion in C

      Was da im Quelltext steht sind Funktions-Prototypen
      Muss der Prototyp einer Funktion nicht die komplette erste Zeile der Funktion enthalten?
      Das ist hier nicht der Fall. Die erste Zeile der Funktion iswap z,B. lautet

      int iswap(int *v,int i, int j, int m)

      Und wenn es kein Prototyp ist, sondern wirklich, wie in der Quelle kommentiert, Deklaration der Funktionspointer, dann kann es nur falsch sein? Der Compiler weiß durch die Funktionsdefinition, was die
      Bezeichner v und swp sein sollen. Diese Bezeichner werden beim
      Aufruf der Funktion durch die entsprechenen Parameter befüllt.

      sort(iarr,iswap); ==> v=iarr, swp=iswap

      Das war neu für mich.

      Danke Stefan, deine Antwort hat mich weitergebracht.

      • Antwort von nach 4 Stunden 0 hilfreich
        Re^3: Zeiger auf Funktion in C

        Hossa :) Muss der Prototyp einer Funktion nicht die komplette erste
        Zeile der Funktion enthalten?
        Doch, muss es. Man kann lediglich die Namen der Parameter weglassen, nicht jedoch deren Datentyp. Das ist hier nicht der Fall. Die erste Zeile der Funktion
        iswap z,B. lautet

        int iswap(int *v,int i, int j, int m)


        Dann ist das in der main-Funktion definitiv falsch. Die Deklaration eines Zeigers fp_iswap auf die Funktion iswap sieht so aus:

        int (*fp_iswap)(int*, int, int, int);

        Dann kannst du die Adresse von iswap an diesen Zeiger zuweisen:

        fp_iswap= &iswap;

        wobei der Adress-Operator "&" auch weggelassen werden kann.

        Viele Grüße

Keine passende Antwort gefunden? Jetzt eigene Frage stellen!