Array und Pointer
-
Ich habe das nun so gelöst, obwohl ich mit dieser Lösung nicht zufrieden bin, da ich einen neuen Speicher reserviere...
Wieso also reservierst du selbst Speicher? Die richtige Lösung wäre, eine automatische Stack-Variabe zu nehmen:
Punkt tmp1; Punkt tmp2;Edit: Sei verdammt, SeppJ!
-
Sone schrieb:
Ich habe das nun so gelöst, obwohl ich mit dieser Lösung nicht zufrieden bin, da ich einen neuen Speicher reserviere...
Wieso also reservierst du selbst Speicher? Die richtige Lösung wäre, eine automatische Stack-Variabe zu nehmen:
Punkt tmp1; Punkt tmp2;Edit: Sei verdammt, SeppJ!
Stimmt auch wieder, bin irgendwie bei den ganzne Pointer und Adresse Variablen hängengeblieben...Danke

-
@DKlay13:
Nur mal so eine Frage bezüglich des Programmierstils:Ist zufälligerweise der Begriff Jürgen Wolf in deinem Bekanntenkreis gefallen?
Übrigens: Sagt dir der Begriff Speicherloch was?
PS:
Ich bin überhaupt kein Freund von Zeigern auf Zeigern...
-
@Bitte ein Bit
ka wer das sein soll...sollte man Jürgen Wolf kennen? und was ist an meinem Programmierstill nicht in Ordnung?Memoryleaks sagt mir was, aber da das eine "Übung" habe ich mir keine gedanken gemacht über delete von Variablen...
-
DKlay13 schrieb:
@Bitte ein Bit
ka wer das sein soll...sollte man Jürgen Wolf kennen? und was ist an meinem Programmierstill nicht in Ordnung?Nein, Jürgen Wolf sollte man nicht kennen. Der ist Autor von den schlechtesten C/C++* Lehrbüchern überhaupt.
Und was deinen Programmierstil angeht:
In C++ nutzt man beispielsweise Referenzen für pass-by-reference, nicht Pointer.
Und Arrays übergibt man nach dem Iteratorenprinzip, ein Zeiger auf das erste Element und eins hinter das letzte Element, dann kann man folgende Schleifen schreiben:for (; begin != end; ++begin) // tu was mit *beginDann muss man auch nicht viel ändern, um den Code für STL-Container (die man eh bevorzugen sollte) anzupassen.
*Man, meine versteckten Witze werden immer besser.

-
Und Arrays übergibt man nach dem Iteratorenprinzip, ein Zeiger auf das erste Element und eins hinter das letzte Element
Um den Vorteil hier noch ein wenig deutlicher zu machen: Man muss nicht das komplette Array angeben, auch Untermengen sind möglich.
Die Funktion (oder besser das Funktionstemplate) ist so nicht an den Containertyp oder den Iterator gebunden, und kann praktisch über alle Mengen iterieren. Extrem Flexibel.
das erste Element und eins hinter das letzte Element
Beiläufig werfe ich für den TE noch den Begriff rechtsoffenes Intervall ein.
-
Hmm ok das kannte ich zwar aber selten bis nie verwendet, aber wieso wird mein Programmierstill runtergemacht? Die Funktionprototypen sind ja nicht von mir gemacht sondern vorgegeben und evtl. ist das ja auch der Sinn der ganzen Übung

Trotzdem Danke an alle
-
Ach so, ist mir gar nicht aufgefallen.
Trotzdem das dann als Hinweis für die Zukunft.
-
Nein, Jürgen Wolf sollte man nicht kennen. Der ist Autor von den schlechtesten C/C++* Lehrbüchern überhaupt.
Genau deswegen frage ich ja nach. Sein Code hat eine gewisse Ähnlichkeit zu JW. Und man möchte ja vermeiden dass er einen solchen Stil anschlägt.
@DKlay13:
Hmm ok das kannte ich zwar aber selten bis nie verwendet, aber wieso wird mein Programmierstill runtergemacht?
Tut mir Leid, ich möchte dich oder deinen Programmierstil nicht runtermachen sondern nur dir einige Fehler in deinem Code aufzeigen.

Wenn dein Prof. deinen neuen Code nicht akzeptiert, dann mach es halt so wie er es mag.
1.) Speicherloch: Wer ein new aufruft, muss auch das entsprechende delete aufrufen. Besser ist da RAII oder Smart Pointer (unique_ptr,...). Es gibt kein Argument zu sagen: soll sich das Betriebsystem um die Freigabe kümmern!
2.) Zeiger sind gemein. Sie können auf die gewünschten Daten zeigen, aber auch auf nullptr, 0xCCCCCCCC oder ähnlichem. Referenzen gefallen mir da besser.
3.) const ist dein Freund. Schränkt deinen Code in einer schönen Art und Weise ein, und vermeidet unerwünschte Seiteneffekte wie:double maxAbstand(Punkt **arrPunkt, Punkt *p1, Punkt *p2) { double nMax = 0; double nTempCalc; //arrPunkt ist übergebenes Feld //über p1 und p2 werden die Punkte zurückgegeben welche den größten abstand haben //double abstand(Punkt p1, Punkt p2) for(int x=0; x<ARRAY_GROESSE; x++) { nTempCalc = abstand( *(arrPunkt[x]), *(arrPunkt[ARRAY_GROESSE-1-x]) ); if( nMax < nTempCalc) { p1 = arrPunkt[x]; p2 = arrPunkt[ARRAY_GROESSE-x-1]; nMax = nTempCalc; } } // So hier bin ich gemein. Ich lösche das Punkt Array. DeletePointArray(arrPunkt); // Frage: Wohin zeigen nun p1 und p2? Und wie bemerke ich den Fehler? // Ist eigentlich sehr gemeiner Fall. Denn sobald jemand das Array verändert, // werdem deine Zeiger oder deren Inhalt p1 und p2 ungültig. (Punkt einfügen) // Ich glaube hier wäre es besser die Punkt Call By Value zurückzugeben! return nMax; }4.)
//double abstand(Punkt p1, Punkt p2) double abstand(const Punkt& p1, const Punkt& p2) // Kein Overhead, da Call By Reference, nicht Call by Value. // Call by Value wäre hier vermutlich auch noch ok, da Point realtiv klein ist { return sqrt( (p2.y-p1.y)*(p2.y-p1.y) + (p2.x-p1.x)*(p2.x-p1.x) ); }4.) Nicht ganz so wichtig: Ich bin kein Freund von Zeiger auf Zeigern. Ich habe ständig das Problem wie ich darauf zugreife:
Punkt **arrPunkt = neuesPunktFeld(ARRAY_GROESSE); (*arrPunkt)[0] = Punkt; //oder *(arrPunkt[0]) = Punkt;5.) Nicht ganz so wichtig: Um ein Array hochzählen sollte man zumindestens ein unsigned int nutzen oder besser size_t und ähnliches. Problem: Wenn die int nur 16 Bits hat, kannst du so nur 2^15 Elemente = 32768 ansprechen.
Punkt **neuesPunktFeld(int nDim) { Punkt **arrPunkt = new Punkt*[nDim]; //for(int i = 0; i < nDim; i++) // so finde ich es lesbarer for(unsigned int i = 0; i < nDim; i++) // so finde ich es lesbarer { arrPunkt[i] = neuerPunkt(); } return arrPunkt; }
-
DKlay13 schrieb:
Punkt *neuerPunkt() { ... } Punkt **neuesPunktFeld(int nDim) { Punkt **arrPunkt = new Punkt*[nDim]; for(int i=0; i<nDim; i++) { arrPunkt[i] = neuerPunkt(); } return arrPunkt; }Die Funktion "neuesPunktFeld" erzeugt kein Feld aus Punkten sondern ein Feld aus Zeigern auf Punkten. Es ist also nicht nur gelogen sondern auch ungeschickt.
In gutem, modernem C++ würde das eher so aussehen:
Punkt neuerPunkt() // <-- kein Zeiger als Rückgabewert { ... // <-- kein new } vector<Punkt> neuesPunktFeld(int nDim) // <-- kein Zeiger als Rückgabewert { vector<Punkt> v; // hier reserviert der vector für v.reserve(nDim); // <-- uns den Speicher und kümmert for (int i=0; i<nDim; ++i) { // sich dann selbst um die Freigabe v.push_back(neuerPunkt()); } // Das reserve ist optional. push_back kann von sich aus auch den // vector vergrößern. Aber hier wissen wir schon die finale Größe // und können es dem vector per reserve mitteilen. Das wird dann // ein kleines bisschen effizienter so. return v; }Man kann das auch noch etwas generischer machen, so dass die Funktion neuesPunktFeld eine nahezu beliebige schon existierende Datenstruktur befüllen kann. Aber das wäre hier wahrscheinlich Overkill.
Fazit: Nimm das, was man Dir da beibringen will, nicht für bare Münze. Möglicherweise kennt Dein Lehrer auch nicht die Größe seiner Wissenslücken; denn sonst könnte er Euch nicht guten Gewissens so einen schlechten Stil beibringen.
typedef structund Doppel-Zeiger ohne eine Spur von RAII sind leider Warnhinweise bzgl. Inkompetenz. Ich empfehle Dir ein begleitendes Selbststudium basierend auf 'nem schlauen Buch, was einen guten Ruf genießt. Achtung: guter Ruf != positive Amazon-Bewertungen. Ein Anfänger, der keine Ahnung hat, kann ein Buch höchstens hinsichtlich Schreibstil bewerten jedoch nicht die Qualität des technischen Inhalts.
-
Danke nochmal für die Tips werde ich mir zu Herzen nehmen

Aber das mit dem doppelt Pointer würde mich trotzdem interessieren auch wenn es schlechter Still ist.