Linker Error



  • Hi an alle!

    Bin hier neu und ihr seit meine letzte hoffnung...

    Ich hab ein programm geschrieben mit dem ich mir die primzahlen bis zu einer bestimmten zahl anzeigen lassen will. ich hab nun einen fehler nach dem anderen ausgebessert, aber jetzt häng ich... der code lautet:

    #include <iostream>
    #include <stdlib.h>
    
    using namespace std;
    void prime(int);
    
    int main()
    {
    
        int p;
    
        cout << "Primzahlen bis Zahl X angeben           <1>" << endl;
        cout << "Ihre Eingabe: ";
        cin >> p;
    
        if(p==1)
    {
    
     cout << " Geben Sie eine Zahl X ein und das Programm" << endl;
                    cout << "gibt alle Primzahlen bis zu dieser Zahl aus!" << endl;
                    cout << "X = ";
                    int num = 0;
                    cin >> num;
                    prime(num);
              }     
                         int num;
                     void prime(int num);
    
    		                 bool isPrime=true;
    				                 for ( int i = 0; i <= num; i++)
    						                 {
    										                 for ( int j = 2; j <= num; j++)
    														                 {
     					if ( i!=j && i % j == 0 )
    						{
    						  isPrime=false;
    						  break;
    						}
    				}
    				if (isPrime)
    				{
    				  cout <<"Primzahl: "<< i << endl;
    				}
    				isPrime=true;	
    
      }
    
        cin.get();
    cin.get();}
    

    und mein compiler (dev-c++) gibt als fehlermeldung aus:

    C:\Dev-Cpp\matura\main.o(.text+0x1ae) In function main': [Linker error] undefined reference toprime(int)'
    C:\Dev-Cpp\matura\Makefile.win [Build Error] [project.exe] Error 1

    was mach ich falsch?

    danke im voraus



  • mit

    void prime(int num);
    

    deklarierst du eine Funktion namens prime, mit

    prime(num)
    

    rufst du sie auf und der Linker weiß nicht woher er sie bekommen soll (sie ist nirgendwo definiert).



  • Danke; und könntest du mir vielleicht auch sagen wie ich es definiere?

    mfg



  • Nomos schrieb:

    Danke; und könntest du mir vielleicht auch sagen wie ich es definiere?

    So wie du main definiert (und grottenschlecht formatiert) hast.

    sprich:

    void prime(int);
    

    muss noch ausgestaltet werden...

    void prime(int num)
    {
        // ... hier ist Code einzufügen
    }
    

    Jetzt aber grundsätzliche Anmerkungen:

    • Formatiere deinen Code anständig, das hilft auch beim finden von Fehlern und grundsätzlich verbessert es die Lesbarkeit.
    • Auch bei einer Funktionsdeklaration ist es für den Lesenden ganz gut wenn man die Parameternamen sehen kann. "void prime(int);" wie bei dir sagt nur aus das du ein int erwartest, ein sprechender Name hilft Wunder. Normalerweise betrachtet man wenn man später mit Headern und Source arbeitet in erster Linie die Header (Deklarationen) um einen Überblick zu bekommen.
    • Stichwort sprechende Namen: Dies solltest du dir auch angewöhnen. Benenne alles so das man den Sinn möglichst schon beim ersten Lesen herleiten kann. Ein Code wird deutlich häufiger gelesen als geschrieben.

    Nur mal ein Beispiel für eine bessere Formatierung:

    // ...
    int main()
    {
        int p;
    
        cout << "Primzahlen bis Zahl X angeben           <1>" << endl;
        cout << "Ihre Eingabe: ";
        cin >> p;
    
        if(p==1)
        {
            cout << " Geben Sie eine Zahl X ein und das Programm" << endl;
            cout << "gibt alle Primzahlen bis zu dieser Zahl aus!" << endl;
            cout << "X = ";
            int num = 0;
            cin >> num;
            prime(num);
        }    
        // Ich schätze das weiter unten sollte die Funktionsdefinition werden...
        // daher Code hier geändert
    
        // <-- Hier kannst du deine "Wartefunktionen" wieder reinschreiben,
        //     schau dazu aber besser mal in die Konsolen-FAQ
    }
    
    // Hier habe ich einiges geändert, was du mit einer sauberen Formatieren
    // gesehen hättest. Ich habe den Code aber nicht auf Richtigkeit geprüft
    
    void prime(int num)
    {
        bool isPrime=true;
        for ( int i = 0; i <= num; i++)
        {
            for ( int j = 2; j <= num; j++)
            {
                if ( i!=j && i % j == 0 )
                {
                    isPrime=false;
                    break;
                }
            }
            if (isPrime)
            {
                cout <<"Primzahl: "<< i << endl;
            }
    
            isPrime=true;   
        }
    }
    

    cu André



  • Ich hab das ganze jetzt umgändert und eine zweite funktion hinzugefügt; das problem von vorhin besteht allerdings noch immer...

    #include <iostream>
    #include <stdlib.h>
    #include <math.h>
    #include <limits.h>
    
    using namespace std;
    void prime(int);
    
    int main()
    {
    
        int p;
    
        cout << "Primzahlen bis Zahl X angeben                    <1>" << endl;
        cout << "Ueberpruefen, ob die Zahl X eine Primzahl ist    <2>" << endl;
        cout << "Ihre Eingabe: ";
        cin >> p;
    
       if(p==1)
    {
    
     cout << " Geben Sie eine Zahl X ein und das Programm" << endl;
                    cout << "gibt alle Primzahlen bis zu dieser Zahl aus!" << endl;
                    cout << "X = ";
                    int num = 0;
                    cin >> num;
                    prime(num);
              }     
                         int num;
                     void prime(int num);
                     {
    		                 bool isPrime=true;
    				                 for ( int i = 0; i  <=  num;  i++)
    						                 {
    					for ( int j = 2;  j <= num; j++)				            
    				 {
     					if ( i!=j  &&  i  %  j  ==  0  )
    						{
    						  isPrime=false;
    						  break;
    						}
    				}
    				if (isPrime)
    				{
    				  cout <<"Primzahl: "<< i << endl;
    				}
    				isPrime=true;	
    
      } 
    }
    
      if(p==2)
      {
       int a, b, p, c, f;
    	cout << "Geben Sie eine Zahl X ein." << endl;
    	cout << "Diese wird in Primzahlen zerlegt." << endl;
    	cout << "X = ";
    	cin >> a;
    	p = 2;
    	b = a;
    	f = 0;
    	while (p <= b) {
    		c = 0; 
    		while ((b % p) == 0) {
    			b /= p;
    			c++;
    		}
    		for (int i = 0; i<c; i++) {
    			if (f != 0) cout << " * ";
    			cout << p;
    			f = 1;
    		}
    		p++;
    	}
    	cout << " = " << a << endl;
    
      }    
    
        cin.get();
    cin.get();}
    


  • Nomos schrieb:

    Ich hab das ganze jetzt umgändert und eine zweite funktion hinzugefügt; das problem von vorhin besteht allerdings noch immer...

    Würdest du
    a) bitte richtig formatieren um deine Fehler zu sehen, und
    b) Funktionen nicht innerhalb von Funktionen schreiben (schau dir mal mein Beispiel an).

    cu André



  • So, und was hältst du davon?

    #include <stdio.h>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
         int menu;	
         Menu:	
         cout << endl;
         cout << "     Menu" << endl;
         cout << endl;
         cout << " Zeigen ob eine Zahl eine Primzahl ist        <1>" << endl;
         cout << " Primfaktorenzerlegung                        <2>" << endl;
         cout << " Zeigt Primzahlen bis Zahl X an               <3>" << endl;
         cout << " Programm beenden                             <4>" << endl;
         cout << endl;
         cout << " Ihre Eingabe: ";
         cin >> menu;	
    
               if (menu==1)
                     {
    
                          int a, i, g, no_prime, o=0;
                          i = 0;
                          g = 0;
                          no_prime= 0;
    
                          system ("cls");
         	              cout << endl;
         	              cout << "      <1>" << endl;
         	              cout << endl;
                          cout << " Geben Sie eine Zahl ein: ";
         	              cin >> a;
         	              cout << endl << " Die Zahl ist: " << a << endl;
         	              for (i=2; i<=a; i++)
    
                          {
    
                               if (a % i == 0)
    
                                 {
                                        cout << " " << i << " ist ein Faktor von " << a << endl;
                                        ++o;
                                 }
                          }
    
                          if (o == 1)
                          cout << " Die Zahl " << a <<" ist eine Primzahl";
    
                          else
         		          cout << " Die Zahl " << a <<" ist keine Primzahl";
    
                          cin.get();
                          cin.get();
                          system("cls");
                          goto Menu;
    
                     }
    
               if (menu==2)
    
                     {
    
                          int zahl, temp;
                          int divisor = 2;
                          system ("cls");
                          cout << endl;
                          cout << "      <2>" << endl;
                          cout << endl;
                          cout << " Geben Sie eine Zahl ein: ";
                          cin >> zahl;
    
                          temp = zahl;
                          cout << endl;
                          cout << " " << zahl << "= ";
    
                          while(divisor < zahl/2)
    
                          {
    
                               if(temp%divisor == 0)
    
                                 {
    
                                        printf("%d * ",divisor);
                                        temp /= divisor;
    
                                 }
    
                               else
    
                                 {
    
                                        divisor++;
                                 }
    
                          }
    
                          printf("\b\b  \n");
                          cin.get();
                          cin.get();
                          system("cls");
                          goto Menu;
    
                     }
    
               if (menu==3)
    
                     {
    
                          system("cls");
                          int a;
                          int e;
                          int prim = 1;
                          int i;
    
                          cout << endl;
                          cout << "      <3>" << endl;
                          cout << endl;
                          cout << " Startzahl eingeben: ";
                          cin >> a;
                          cout << endl;
                          cout << " Endzahl eingeben: ";
                          cin >> e;
                          cout << endl;
    
                          for(a; a<e; a++)
    
                          {
                               prim = 1;
                               for(i=2 ; i<=a/2 ; i++)
    
                                 {
    
                                        if(a%i == 0)
    
                                               {
    
                                                      prim = 0;
                                                      break;
                                               }
                                 }
    
                               if(prim)
    
                                 {
    
                                        printf(" %d \n",a);
    
                                 }
    
                          }
    
                          cin.get();
                          cin.get();
                          system("cls");
                          goto Menu;
    
                     } 
    
               if (menu==4)
    
                     {
    
                          cin.get();
    
                     }    
    }
    


  • Nomos schrieb:

    So, und was hältst du davon?

    Vom ersten Überfliegen her schon besser zu lesen, wenn gleich ich etwas schwächer einrücken würde (sonst wirst du bei ein wenig geschachtelten Ausdrücken Probleme bekommen).

    Zumeist schreibt man Bedingungs und Schleifenköpfe in die gleiche Ebene wie den umgebenden Code, und Klammern entweder auf der gleichen Ebene oder mit dem enthaltenen Code eine Ebene tiefer.

    // Variante 1

    int main
    {
        cout << "Kleines Einrückbeispiel" << endl;
        for(int i=0; i<10; ++i)
        {
            cout << "Schleifendurchlauf " << i << endl;
        }
    }
    

    Hier erkennt man auf anhieb das, das erste cout und der Schleifenbegin in einer logischen Ebene liegen, der Schleifendurchlauf liegt selbst eine Ebene tiefer.

    // Variante 2 (seltener)

    int main
        {
        cout << "Kleines Einrückbeispiel" << endl;
        for(int i=0; i<10; ++i)
            {
            cout << "Schleifendurchlauf " << i << endl;
            }
        }
    

    Hier ist der Sinn das auch die Klammern in der Ebene des zugehörigen Codes liegen, ich finde es aber etwas ungewöhnlich zu lesen.

    Weitere Varianten sind z.B. die Beginnende Klammer immer noch an das Ende der Vorzeile zu schreiben. Dies ist aber IMHO für Anfänger schlechter zu lesen. Mein eigener Favorit ist Variante 1, bei extrem kurzen Funktionen (die nur aus einer Anweisung bestehen, setze ich die Öffnende Klammer auch mal in die Vorzeile).

    So nun ganz kurz zum Inhaltlichen (Näher eingehend nach der Auflistung)

    • Setze niemals goto in einer Hochsprache ein!
    • Vermeide viele if()-Blöcke wenn es besser mit else if oder switch geht...
    • Vermeide zu lange Funktionen, lager dann in eigenständige Funktionen aus...
    • Weiterhin hatte ich sprechende Namen für Variablen ja schon angemerkt...
    • Wähle immer passende Typen

    Thema: goto
    Es gibt viele Gründe gegen goto, grundsätzlich gesagt ist es ein sehr unsauberes Codeelement das vermieden werden sollte (um nicht zu sagen: in Sauberen Programmen wirst du es niemals sehen; ich kenne kein professionelles Programm was goto verwendet). Und du solltest goto niemals einen kompetenten Dozenten oder Arbeitskollegen zeigen...

    Man kann goto in der Regel durch umschließende Schleifen ganz einfach ersetzen (Bei dir wäre es eine Schleife die statt dem Menu: Label beginnt und am Ende prüft ob 4 eingegeben wurde, ansonsten wird der Code wiederholt).

    Thema: if
    Dein Programm führt zwangsweise 4 if-Prüfungen aus, obwohl sich diese wiedersprechen. Bei solchen Werten wie bei dir würde sich hier ein switch deutlich besser machen:

    do
        {
            // ... <-- Menüanzeige
            switch(menu)
            {
                case 1:
                    // <-- Fall 1; Falls du hier Variablen deklarierst solltest
                    // du nochmals Klammern wie folgt:
                    {
                        // ...
                    }
                    break;
                case 2:
                    // <-- Fall 2
                    break;
                case 3:
                    // <-- Fall 3
                    break;
            }
        } while(menu != 4); // Wiederhole solange menu != 4 ist...
    

    Die andere alternative ist wenn du komplexere Ausdrücke verwendest die sich ausschließen mit if / else if / else zu arbeiten, so wird die Auswertung nur solange gemacht bis der zutreffende Fall eintrifft.

    do
        {
            // ... <-- Menüanzeige
            if(menu == 1)
            {
                // ...
            }
            else if(menu == 2)
            {
                // ...
            }
            else if(menu == 3)
            {
            }
            // Ein abschließendes else ist in diesem Fall nicht nötig, da
            // wir ja nur die Fälle 1,2,3 brauchen...
        } while(menu != 4); // Wiederhole solange menu != 4 ist...
    

    Thema: lange Funktionen
    Um so länger eine Funktion ist, umso schwerer ist diese zu lesen. Dann lieber Teile der Funktion wieder auslagern.

    // ...
    
    void CheckPrimeNumber(); // Funktionsdeklaration
    
    int main()
    {
        //...
        switch(menu)
        {
            case 1:
                CheckPrimeNumber();
                break;
            case 2:
        // ...
    }
    
    void CheckPrimeNumber() // Funktionsdefinition
    {
        // Hier deinen entsprechenden Code kopieren.
    }
    

    Thema: Sprechende Namen
    Stell dir einfach vor du hast ein Programm geschrieben und muss ein Halbes Jahr später dieses Programm korrigieren. Mit sprechenden Namen wirst du es deutlich leichter haben es wieder zu verstehen.

    Sowas wie:

    int a, i, g, no_prime, o=0;
    i = 0;
    g = 0;
    no_prime= 0;
    

    Ist nicht sprechend, zum anderen kannst du auch initialisierungen in eine Zeile schreiben und es gibt mehrere Gründe warum man grade als Anfänger lieber jede Variable in eine einzelne Zeile schreiben sollte...

    // Dies ist möglich:
    int a=0, i=0, g=0, no_prime=0, o=0;
    
    // Vielleicht ist das aber lesbarer:
    int a=0;
    int i=0;
    // ...
    

    Thema: Typen
    Warum hast du no_prime als int definiert, obwohl du nur zwischen ja und nein entscheiden musst?

    Besser:

    bool no_prime = false;
    // Noch besser: (Sprechender)
    bool isPrimeNumber = true;
    

    cu André


Log in to reply