undefined reference to



  • Hallo an alle.

    Zur Zeit sitze ich an einer Übungsaufgabe im c-howto Tutorial.

    Darin geht es um eine Spielfigur, die in einem 8x8 Feld mit den Tasten a, w, d, s bewegt werden soll.
    Für mich war die Aufgabe an manchen Stellen leider noch etwas zu kompliziert, so dass ich die entsprechenden Passagen abgetippt habe, um diese dann so nachzuvollziehen.

    #include<stdio.h>
    
    void printField(int *field);
    void move(int *field, int *posX, int *posY, char zug);
    
    int main()
    
    {
        int field[8][8] = {0}, posX=0, posY=0;
        char zug;
    
        //Setzen der Figur auf das Feld (0,0)
    
        field[posY][posX]=1; //Da posX und posY 0 sind, wird das Feld oben links mit 1 initialisert.
        printf("\nBeenden mit x\n");
    
        do //Schleife erscheint immer nach dem Eintippen der Aufforderung.
        {
            printField(&field[0][0]); //Befehl, um das Feld auszugeben.
            printf("\nZuege: a links, w hoch, d rechts, s runter: ");
            scanf("%c", &zug);
            move(&field[0][0], &posX, &posY, zug); //Mit & wird der Zeiger aus der Funktion oben auf die Variablen gesetzt.
        }
        while (zug != 'x');
        return 0;
    
        //Ausgabe Spielfeld
        void printField(int *field)
        {
            printf("\n");
            int i, j;
            //Befehl für die Zeilen. Y-Achse
            for(i=0; i<8; i++)
            {
                //Befehl für die Spalten. X-Achse
                for(j=0; j<8; j++)
                {
                    printf("%d ", *(field+i*8+j));//Insgesamt geht man von (0,0) aus i*8+j Felder weiter.
                }
                printf("\n");
            }
    
        }
    
        //Bewegen der Spielfigur
        void move(int *field, int *posX, int *posY, char zug)
        {
            //Löschen der alten Position
            *(field + *posY*8 + *posX) = 0; /*Der Zeilenwert wird *8 gerechnet und dazu der Spaltenwert addiert.
                                                Durch das Initialisieren mit 0 wird die alten Position 'gelöscht' und die 1 durch
                                                eine 0 ersetzt. */
    
            //Neue Position
            switch(zug)
            {
                case 'a': (*posX)--; break;
                case 'w': (*posY)--; break;
                case 'd': (*posX)++; break;
                case 's': (*posY)++; break;
            }
    
            //Überschreiten der Grenze
            if (*posX<0) *posX = 7;
            if (*posX>7) *posX = 0;
            if (*posY<0) *posY = 7;
            if (*posY>7) *posY = 0;
    
            //Neue Position bei Überschreitung
            *(field + *posY*8 + *posX) = 1;
        }
    
    }
    

    Der Compiler meldet jetzt zwei Fehlermeldungen, nämlich

    undefined reference to 'printField' und undefined reference to 'move'

    Das beudeutet doch, dass der Compiler die Funktionen nicht mit den entsprechenden Verlinkungen im Hauptprogramm verbinden kann, oder?



  • Es gibt in C keine funktionslokalen Funktionen.
    Alle Funktionen werden im Code global definiert
    (Die Sichtbarkeit kann durch static eingegrenzt werden)



  • Mit global ist gemeint, dass deine Funktionsdefinition außerhalb von main(){} liegen muss, also oberhalb oder unterhalb von main() und nicht wie bei dir innerhalb.



  • Hi

    Danke für eure Antworten.

    Dass die Funktionen außerhalb des Hauptprogrammes definiert werden müssen ist soweit verständlich.

    Das Lustige ist jetzt aber, dass in der Musterlösung die Funktionen genau wie in meiner oben geposteten Lösung auch nicht vor dem Hauptprogramm definiert werden.
    Und warum das dort dann trotzdem funktioniert verstehe ich nicht.

    #include<stdio.h>
    
    void printField(int *field);
    void move(int *field, int *posX, int *posY, char zug);
    
    int main() {
    
    	int field[8][8] = { 0 }, posX=0, posY=0;
    	char zug, temp;
    
    	// setzen der Spielfigur
    	field[posY][posX] = 1;
    
    	printf("\nBeenden mit x\n");
    
    	do {
    		printField(&field[0][0]);
    		printf("\nZug [w hoch, a links, s runter, d rechts]: ");
    		scanf("%c%c", &zug, &temp);
    		move(&field[0][0], &posX, &posY, zug);
    	}while(zug != 'x');
    
    	return 0;
    }
    
    // Ausgabe Spielfeld
    void printField(int *field) {
    	printf("\n");
    	int i, j;
    	// Schleife fuer Zeilen, Y-Achse
    	for(i=0; i<8; i++) {
    		// Schleife fuer Spalten, X-Achse
    		for(j=0; j<8; j++) {
    			printf("%d ", *(field+i*8+j));
    		}
    		printf("\n");
    	}
    }
    
    // Spielfigur bewegen
    void move(int *field, int *posX, int *posY, char zug) {
    	// alte Position loeschen
    	*(field + *posY * 8 + *posX) = 0;
    
    	// neue Position bestimmen
    	switch(zug) {
    		case 'w': (*posY)--; break;
    		case 'a': (*posX)--; break;
    		case 's': (*posY)++; break;
    		case 'd': (*posX)++; break;
    	}
    
    	// Grenzueberschreitung pruefen
    	if(*posX < 0) *posX = 7;
    	if(*posX > 7) *posX = 0;
    	if(*posY < 0) *posY = 7;
    	if(*posY > 7) *posY = 0;
    
    	// neue Position setzen
    	*(field + *posY * 8 + *posX) = 1;
    }
    


  • Shelldor schrieb:

    Das Lustige ist jetzt aber, dass in der Musterlösung die Funktionen genau wie in meiner oben geposteten Lösung auch nicht vor dem Hauptprogramm definiert werden.
    Und warum das dort dann trotzdem funktioniert verstehe ich nicht.
    ...

    Schau dir mal ganz genau an welcher Stelle im Quelltext die geschweiften Klammern auf und zu stehen. 👍
    Dann solltest du den Unterschied zwischen den Quelltexten erkennen.



  • f.-th. schrieb:

    Shelldor schrieb:

    Das Lustige ist jetzt aber, dass in der Musterlösung die Funktionen genau wie in meiner oben geposteten Lösung auch nicht vor dem Hauptprogramm definiert werden.
    Und warum das dort dann trotzdem funktioniert verstehe ich nicht.
    ...

    Schau dir mal ganz genau an welcher Stelle im Quelltext die geschweiften Klammern auf und zu stehen. 👍
    Dann solltest du den Unterschied zwischen den Quelltexten erkennen.

    Hmmm.... also ich erkenne, dass in beiden Quelltexten die geschweiften Klammern paarweise geöffnet und geschlossen sind. Es steht also keine Klammer 'alleine'.

    Was mir auffällt ist, dass in der Musterlösung die geöffnete, geschweifte Klammern direkt nach der Funktionsverlinkung stehen. In meiner Lösung darunter.
    Kann das etwas damit zutun haben? 😕 😕 😕



  • In deiner Lösung ist main erst in Zeile 73 zu Ende.
    Dadurch sind die anderen Funktionen innerhalb von main . (Funktionslokal)

    In der Musterlösung ist main in Zeile 24 zu Ende.
    Dadurch sind die anderen Funktionen global definiert.

    main ist auch nur eine Funktion. Zwar mit spezieller Bedeutung und genormten Aufruf.
    Sie wird als erste (User-)Funktion vom Startcode aufgerufen.

    Was verstehst du unter Funktionsverlinkung 😕



  • er meint wahrscheinlich

    void funktion(){
    //code
    }
    

    gegenüber

    void funktion()
    {
    //code
    }
    

    macht aber keinen unterschied, da man im prinzip auch

    void funktion(){//code}
    

    schreiben kann. klammern untereinander finde ich persönlich auch übersichtlicher und moderne entwicklungsumgebungen zeigen normalerweise das "gegenstück" zur jeweiligen klammer an, wenn man das caret neben diese bewegt.



  • DirkB schrieb:

    In deiner Lösung ist main erst in Zeile 73 zu Ende.
    Dadurch sind die anderen Funktionen innerhalb von main . (Funktionslokal)

    In der Musterlösung ist main in Zeile 24 zu Ende.
    Dadurch sind die anderen Funktionen global definiert.

    main ist auch nur eine Funktion. Zwar mit spezieller Bedeutung und genormten Aufruf.
    Sie wird als erste (User-)Funktion vom Startcode aufgerufen.

    Was verstehst du unter Funktionsverlinkung 😕

    Wahnsinn. Daran hat es gelegen 🙂 Vielen Dank!
    Woran hast du das 'gesehen', dass dort der Fehler war?

    Mit 'Funktionsverlinkungen' meine ich das Ansprechen der Funktionen im Hauptprogramm.

    HansKlaus schrieb:

    er meint wahrscheinlich

    void funktion(){
    //code
    }
    

    gegenüber

    void funktion()
    {
    //code
    }
    

    macht aber keinen unterschied, da man im prinzip auch

    void funktion(){//code}
    

    schreiben kann. klammern untereinander finde ich persönlich auch übersichtlicher und moderne entwicklungsumgebungen zeigen normalerweise das "gegenstück" zur jeweiligen klammer an, wenn man das caret neben diese bewegt.

    Danke für die Antwort 🙂
    War mir in dem Moment nicht so sicher, ob die Position der geschweiften Klammern Einfluss auf das Compilen haben.
    Aber genauso meinte ich das 😉



  • Shelldor schrieb:

    Woran hast du das 'gesehen', dass dort der Fehler war?

    Erfahrung.

    Allerdings ist dein Code sehr schön eingerückt.
    Darum kann man das sehr schön sehen.

    Auch die fehlende Klammer nach dem return in main , bzw. die folgende Funktionsdefinition und
    die extra Klammer am Ende vom Code.


Anmelden zum Antworten