Speicher fuer dim x dim Matrix anfordern
-
Ok ich bin schon ein ganzes Stück weitergekommen aber es werden nach beenden der .exe noch Fehler angezeigt, bzw. da Programm stürzt dann ab.
Auch kann ich keine Dimension größer als 9 benutzen, warum weiss ich nicht.
Code ist noch ein wenig holprig, aber bin ja noch am lernen

Hier mal das Programm:
#include <iostream> #include <iomanip> #include <cmath> #include <conio.h> #define M_PI 3.14159265358979323846 //M_PI wirk komischerweise vom Compiler nicht definiert using namespace std; // Template Prototypefunktion // template <typename T> T dot(T *x, T *y, int n); int main() { //Vektoren int *xi, *yi; float *xf, *yf; double *xd, *yd; bool *xb, *yb; //Matrizen int **I; float **F; double **D1; double **D2; int n; cout << "Bitte Dimension n eingeben: "; cin >> n; //const float M_PI = 3.141; //Speicher reservieren D1 = new double *[n]; for(int i=0; i<n; ++i) D1[i]=new double[n]; D2 = new double *[n]; for(int i=0; i<n; ++i) D2[i]=new double[n]; I = new int *[n]; for(int i=0; i<n; ++i) I[i]=new int[n]; F = new float *[n]; for(int i=0; i<n; ++i) F[i]=new float[n]; xi = new int; yi = new int; xf = new float; yf = new float; xd = new double; yd = new double; xb = new bool; yb = new bool; //Vektoren und Matrizen mit Werten fuellen for(int i=0 ; i<n ; i++) { xi[i] = i+1; yi[i] = i-1; xf[i] = 0.1f*i; yf[i] = 0.25f*i; xd[i] = M_PI*i; yd[i] = 1e-10*i; xb[i] = (i%2 == 0); yb[i] = (i%3 == 0); for(int j=0 ; j<n ; j++) { if(i==j) I[i][j] = 1; else I[i][j] = 0; if(i>j) F[i][j] = 0.2*i; else F[i][j] = 0.2*j; D1[i][j] = M_PI*(i+j); } } cout << setprecision(2); cout << "Skalarprodukt von int Vektoren: " << dot(xi,yi,n) << endl; cout << "Skalarprodukt von float Vektoren: " << dot(xf,yf,n) << endl; cout << "Skalarprodukt von double Vektoren: " << dot(xd,yd,n) << endl; //Speicher wieder freigeben for(int i=0; i<n; ++i) delete[] D1[i]; delete[] D1; for(int i=0; i<n; ++i) delete[] D2[i]; delete[] D2; for(int i=0; i<n; ++i) delete[] I[i]; delete[] I; for(int i=0; i<n; ++i) delete[] F[i]; delete[] F; delete xi; delete yi; delete xf; delete yf; delete xd; delete yd; delete xb; delete yb; _getch(); return 0; } // Template Funktion Definition // template <typename T> T dot(T *x, T *y, int n) { T res = 0; for (int i=0; i<n; i++) res += x[i]*y[i]; return res; }
-
Erklär mal, was du dir bei Zeile 47 ff. gedacht hast.
-
Nun ja ich habe am anfang nur die Matritzen mit new belegt und der Kompiler hat immer die Variablen angemeckert.
Habe daher ne bissel mit trail-and-error rumexperimentiert.
Nachdem ich Speicher für die Variablen allokiert habe hat das Programm soweit (bis das Ende) funktioniert.
-
Tyle schrieb:
Habe daher ne bissel mit trail-and-error rumexperimentiert.
Uralter, aber absolut wahrer Spruch hier aus dem Forum:
c.rackwitz schrieb:
Wenn du selber Code schreibst, musst du ihn auch verstehen. Code ist kein Haufen von wahllos zusammengeschmissenen Buchstaben und Zeichen, Code ist Logik pur. Du musst genau wissen, warum du wo und welches Zeichen setzt.
Studiere diese Aussage genau und lerne daraus.
-
Mit ist schon klar das ich das Programm noch nicht verstanden habe, daher versuche ich das ganze ja zu verstehen.
Meine Materialien sind leider in Bezug auf new und delet sehr sehr dürftig. Muss daher leider viel ausprobieren.
Wäre super wenn mir jemand erklären könnte was ich genau falsch gemacht habe und die Logik dahinter klar macht.
-
Tyle schrieb:
Meine Materialien sind leider in Bezug auf new und delet sehr sehr dürftig. Muss daher leider viel ausprobieren.
newunddeletesind ja auch keine Raketentechnik, da muss man gar nicht soviel schreiben.
Subtil sind allerdings die Anforderungen, die man erfüllen muss, damit man keine Speicherlecks hat. Aber auch dafür haben sich mittlerweile Lösungen gefunden - meistens in der Form, dass man keinnewunddeletebenutzt.
State of the Art sind dagegen Handles:std::string,std::vectorusw. usf..Auch auf die Gefahr hin mich zu wiederholen:
newgibt einen Zeiger auf allozierten Speicher zurück.
Der zurückgebene Zeiger hat einen Typ abhängig vom allozierten Objekt.Für eine einzige Instanz ist die Form
auto a = new int; // a ist int*
für ein Array ist die Form:
auto aa = new double[12]; // aa ist double*, aa zeigt auf's erste ElementSo allozierten Speicher gibt man nach Gebrauch mit
deletewieder frei.
delete a; // a von oben
, bzw.
delete[] aa; // aa von obenSo und jetzt kommst Du und erklärst uns: was Du Dir bei Zeile 47ff gedacht hast.
Bzw. was Du jetzt darüber denkst.
Zur Erinnerung: Du weisst, wie Du Arrays (aka. Vektoren) mitnewanlegst.
-
Also ich glaube ich habe den Fehler gefunden:
Vorher habe ich mit
xi = new int;nur Speicher für einen Int Wert reserviert. Was natürlich totaler Quatsch ist, das xi ein Zeiger vom Typ int ist und somit ein Array da ein Array ja auch nur ein Zeiger auf das erste Element des Arrays ist.
An der Stelle hätte ich es eigentlich schon sehen sollen, das die Werte als Array befüllt werden:
xi[i] = i+1; yi[i] = i-1; xf[i] = 0.1f*i; yf[i] = 0.25f*i; xd[i] = M_PI*i; yd[i] = 1e-10*i; xb[i] = (i%2 == 0); yb[i] = (i%3 == 0);Klar das meine vorherige Zuweisung das Programm zum Absturz gebracht hat, da ja kein Speicher, bzw. viel zu wenig Speicher zugewiesen wurde.
Somit andert sich das Programm wie folgt:
#include <iostream> #include <iomanip> #include <cmath> #include <conio.h> #define M_PI 3.14159265358979323846 using namespace std; // Template Funktion Prototype // template <typename T> T dot(T *x, T *y, int n); int main() { //Vektoren int *xi, *yi; float *xf, *yf; double *xd, *yd; bool *xb, *yb; //Matrizen int **I; float **F; double **D1; double **D2; //Teilaufgabe a) int n; cout << "Bitte Dimension n eingeben: "; cin >> n; //const float M_PI = 3.141; //Speicher reservieren D1 = new double *[n]; for(int i=0; i<n; ++i) D1[i]=new double[n]; D2 = new double *[n]; for(int i=0; i<n; ++i) D2[i]=new double[n]; I = new int *[n]; for(int i=0; i<n; ++i) I[i]=new int[n]; F = new float *[n]; for(int i=0; i<n; ++i) F[i]=new float[n]; xi = new int[n]; yi = new int[n]; xf = new float[n]; yf = new float[n]; xd = new double[n]; yd = new double[n]; xb = new bool[n]; yb = new bool[n]; //Vektoren und Matrizen mit Werten fuellen for(int i=0 ; i<n ; i++) { xi[i] = i+1; yi[i] = i-1; xf[i] = 0.1f*i; yf[i] = 0.25f*i; xd[i] = M_PI*i; yd[i] = 1e-10*i; xb[i] = (i%2 == 0); yb[i] = (i%3 == 0); for(int j=0 ; j<n ; j++) { if(i==j) I[i][j] = 1; else I[i][j] = 0; if(i>j) F[i][j] = 0.2*i; else F[i][j] = 0.2*j; D1[i][j] = M_PI*(i+j); } } cout << setprecision(2); cout << "Skalarprodukt von int Vektoren: " << dot(xi,yi,n) << endl; cout << "Skalarprodukt von float Vektoren: " << dot(xf,yf,n) << endl; cout << "Skalarprodukt von double Vektoren: " << dot(xd,yd,n) << endl; //Speicher wieder freigeben for(int i=0; i<n; ++i) delete[] D1[i]; delete[] D1; for(int i=0; i<n; ++i) delete[] D2[i]; delete[] D2; for(int i=0; i<n; ++i) delete[] I[i]; delete[] I; for(int i=0; i<n; ++i) delete[] F[i]; delete[] F; delete [] xi; delete [] yi; delete [] xf; delete [] yf; delete [] xd; delete [] yd; delete [] xb; delete [] yb; _getch(); return 0; } // Template Funktion Definition // template <typename T> T dot(T *x, T *y, int n) { T res = 0; for (int i=0; i<n; i++) res += x[i]*y[i]; return res; }Sehe ich das so richtig?
-
Ja, aber ein Array ist kein Zeiger!
Ein Array kann in einen Zeiger auf des erste Element konvertiert werden, aber es ist kein Zeiger!
Und was spricht gegen std::vector?
Denn überlege mal, was passiert, wenn eine Speicheranforderung fehlschlägt...
-
Nathan schrieb:
Und was spricht gegen std::vector?
darf er nicht benutzen, hatte ich auf der ersten Seite schon gefragt.
-
Ok dann habe ich das mit dem Array falsch verstanden.
Ist schon klar was passiert wenn die Speicheranforderung fehlschlägt, das Programm stürzt ab. Ich persönlich würde auch eher ein vector nutzen. Darf ich aber in dem Fall nicht machen da es in der Aufgabe mit new und delet gefordert wurde.
Verbraucht denn der Vector nicht auch mehr Speicherplatz?
-
Nathan schrieb:
Denn überlege mal, was passiert, wenn eine Speicheranforderung fehlschlägt
Wenn eine Speicheranforderung fehlschlägt, dann ist eh schon alles zu spät. Dann hast du vorher schon Misst gebaut, sonst würde sie nicht fehlschlagen. Darum ist ein
if( !Speicher_erfolgreich_allkoiert )sinnlos. Du musst hergehen und schauen, wie es zu solch einen Missgeschick kommen konnte (z.B. wenn du voher bereits 1000x new[] gemacht hast) und dann den Auslöser beseitigen.
-
Tyle schrieb:
Also ich glaube ich habe den Fehler gefunden
[...]Sieht doch gut aus.
Du hast jetzt tausend Möglichkeiten weiterzumachen.
Kommt auf Deine Vorkenntnisse und Deinen Spaß an der Sache an.
Mir fällt ein:- freie Funktionen zum erstellen, frei- und ausgeben der Matrix
- eine Klasse, die die Matrix beinhaltet
- Das ganze dann noch mit Memberfunktionen
- Das array in einem Stück erstellen (
new double[dim*dim];) und schauen, ob Du die Zeigerarithmetik für die Zugriffe hingebogen bekommmst - tatsächlich die STL (namentlich
std::vectorundstd::inner_product) benutzen - Bierchen trinken gehen, weil Die Übung erledigt ist
-
Tyle schrieb:
Meine Materialien sind leider in Bezug auf new und delet sehr sehr dürftig. Muss daher leider viel ausprobieren.
Falsche Schlussfolgerung.
Du würdest mehr lernen, wenn du dich zu diesen Themen in einem guten C++-Buch einlesen würdest. In C++ kann "ausprobieren" fürchterlich nach hinten los gehen. Besonders wenn es sich um Dinge handelt, die zu funktionieren scheinen, aber tatsächlich undefiniertes Verhalten sind...
-
out schrieb:
Nathan schrieb:
Denn überlege mal, was passiert, wenn eine Speicheranforderung fehlschlägt
Wenn eine Speicheranforderung fehlschlägt, dann ist eh schon alles zu spät. Dann hast du vorher schon Misst gebaut, sonst würde sie nicht fehlschlagen. Darum ist ein
if( !Speicher_erfolgreich_allkoiert )sinnlos. Du musst hergehen und schauen, wie es zu solch einen Missgeschick kommen konnte (z.B. wenn du voher bereits 1000x new[] gemacht hast) und dann den Auslöser beseitigen.
Der Trick ist, so zu programmieren, dass dadurch kein Schaden entstehen kann. Wenn die bad_alloc fliegt (und nein: new gibt bei Fehlschlag keine 0 zurück, außer man schaltet dies explizit ein), dann möchte man doch wenigstens, dass alle Dateien ordentlich geschlossen, aller Sockets ungebunden, aller Speicher sauber freigegeben und die Datenbank in einen konsistenten Zustand gebracht wird. Kurz: Man möchte einen RAII-Handler für alles benutzen. Selbst wenn die Standardbibliothek verboten ist: So ein unique_ptr ist in wenigen Minuten selbst programmiert, wenn man sich auf die nötigsten Features beschränkt.
Dabei würde man wirklich etwas über C++ lernen und nebenbei noch über new/delete. Im Gegensatz zu dieser Übungsaufgabe, die einen bloß lehrt, wie man es nicht täte.
-
Habe hier nur das Buch: "C++ Objektorientiertes Programiern von Anfang an" von Helmut Erlenkötter.
Ansonsten schaue ich bei WikiBooks C++ nach.
@Furble Wurble: Bin mit dem Programm auch noch nicht ganz am Ende, ich muss noch ne paar Template Funktionen einfügen und gucken ob die auch das machen was sie sollen.
@SeppJ: Die Übungsaufgaben halte ich auch sehr praxis fern. Da wird einem Zeug beigebracht, welches man später niemals nutzen würde.
-
So mein Programm ist nur fertig:
#include <iostream> #include <iomanip> #include <cmath> #include <conio.h> #define M_PI 3.14159265358979323846 using namespace std; // Template Funktion Prototype // template <typename T> T dot(T *x, T *y, int n); template <> bool dot(bool *x, bool *y, int n); template <typename S, typename T> S matvec(S **x, T *y, S *z, int n); template <typename S, typename T> S matmat(S **x, T **y, S **z, int n); template <typename T> void out(T *x, int n); template <typename T> void out(T **x, int n); /* int dot(int *x, int *y, int n) { int res = 0; for(int i=0 ; i<n ; i++) res += x[i]*y[i]; return res; } float dot(float *x, float *y, int n) { float res = 0; for(int i=0 ; i<n ; i++) res += x[i]*y[i]; return res; } double dot(double *x, double *y, int n) { double res = 0; for(int i=0 ; i<n ; i++) res += x[i]*y[i]; return res; } */ int main() { //Vektoren int *xi, *yi; float *xf, *yf; double *xd, *yd; bool *xb, *yb; //Matrizen int **I; float **F; double **D1; double **D2; //Teilaufgabe a) int n; cout << "Bitte Dimension n eingeben: "; cin >> n; //const float M_PI = 3.141; //Speicher reservieren D1 = new double *[n]; for(int i=0; i<n; ++i) D1[i]=new double[n]; D2 = new double *[n]; for(int i=0; i<n; ++i) D2[i]=new double[n]; I = new int *[n]; for(int i=0; i<n; ++i) I[i]=new int[n]; F = new float *[n]; for(int i=0; i<n; ++i) F[i]=new float[n]; xi = new int[n]; yi = new int[n]; xf = new float[n]; yf = new float[n]; xd = new double[n]; yd = new double[n]; xb = new bool[n]; yb = new bool[n]; //Vektoren und Matrizen mit Werten fuellen for(int i=0 ; i<n ; i++) { xi[i] = i+1; yi[i] = i-1; xf[i] = 0.1f*i; yf[i] = 0.25f*i; xd[i] = M_PI*i; yd[i] = 1e-10*i; xb[i] = (i%2 == 0); yb[i] = (i%3 == 0); for(int j=0 ; j<n ; j++) { if(i==j) I[i][j] = 1; else I[i][j] = 0; if(i>j) F[i][j] = 0.2*i; else F[i][j] = 0.2*j; D1[i][j] = M_PI*(i+j); } } cout << setprecision(2); cout << "Skalarprodukt von int Vektoren: " << dot(xi,yi,n) << endl; cout << "Skalarprodukt von float Vektoren: " << dot(xf,yf,n) << endl; cout << "Skalarprodukt von double Vektoren: " << dot(xd,yd,n) << endl; //Teilaufgabe b) cout << endl; cout << "Teilaufgabe b)" << endl; cout << "Skalarprodukt von bool Vektoren: " << dot(xb,yb,n) << endl << endl; //Teilaufgabe c) cout <<endl <<"Teilaufgabe c)" << endl; matvec(D1,xf,xd,n); cout << "Matrix-Vektor-Produkt mit double und float: " << endl; out(xd,n); matvec(F,xi,xf,n); cout << "Matrix-Vektor-Produkt mit float und int: " << endl; out(xf,n); //Teilaufgabe d) cout <<endl << "Teilaufgabe d)" << endl; matmat(D1,I,D2,n); cout << "Matrix-Matrix-Produkt mit double und int: " << endl; out(D2,n); matmat(D1,F,D2,n); cout << "Matrix-Matrix-Produkt mit double und float: " << endl; out(D2,n); //Speicher wieder freigeben for(int i=0; i<n; ++i) delete[] D1[i]; delete[] D1; for(int i=0; i<n; ++i) delete[] D2[i]; delete[] D2; for(int i=0; i<n; ++i) delete[] I[i]; delete[] I; for(int i=0; i<n; ++i) delete[] F[i]; delete[] F; delete [] xi; delete [] yi; delete [] xf; delete [] yf; delete [] xd; delete [] yd; delete [] xb; delete [] yb; _getch(); return 0; } // Template Funktions Definition dot // template <typename T> T dot(T *x, T *y, int n) { T res = 0; for (int i=0; i<n; i++) res += x[i]*y[i]; return res; } // Template Funktions Definition matvec // template <typename S, typename T> S matvec(S **x, T *y, S *z, int n) { for (int i=0; i<n; i++){ z[i]=0; } for (int i=0; i<n; i++){ for (int j=0; j<n; j++){ z[i]+=( x[i][j] * y[j]); } } return *z; } // Template Funktions Definition matmat // template <typename S, typename T> S matmat(S **x, T **y, S **z, int n) { for (int i=0; i<n; i++){ for(int j=0; j<n; j++) { z[i][j]=0; } } for (int i=0; i<n; i++){ for (int j=0; j<n; j++){ for (int k=0; k<n; k++) { z[i][j]+=( x[i][k] * y[k][j]); } } } return **z; } // Template Funktions Definition out // template <typename T> void out(T *x, int n) { for(int i=0; i<n; i++) { cout <<"Vektor: " << x[i] << endl; } cout << "Dimension: " << n << endl <<endl; } template <typename T> void out(T **x, int n) { for(int i=0; i<n; i++) { cout << endl; for(int j=0; j<n; j++){ cout << setprecision(2) << setw(4) << x[i][j]; } } cout << endl <<endl; } // Template Spezialisierung // template <> bool dot(bool *x, bool *y, int n) { if (x == y) return true; else return false; }
-
Deklarier doch die Variablen erst, wenn du sie initialisierst. Braucht weniger Code, ist übersichtlicher, und verhindert Fehler durch zu frühe Benutzung.
if (x == y) return true; else return false;kannst du einfacher schreiben als
return x == y;Aber ich glaube, dieser Code ist nicht richtig, da du nur die Zeiger vergleichst und nicht die Inhalte des Arrays.
Funktionstemplates solltest du nicht spezialisieren, sondern überladen.
Und die Templatedefinitionen müssten streng genommen vor
main()stehen, da der Compiler zur Zeit der Instantiierung die volle Definition kennen muss. Manche Compiler sind hier zwar nachlässiger, aber das macht es nicht richtig.
-
Nexus schrieb:
Und die Templatedefinitionen müssten streng genommen vor
main()stehen,Eine solche Regel ist mir nicht bekannt (für Funktionstemplates).
-
Ah okay, ich dachte bisher, das wäre eine Eigenheit von MSVC. Das heisst, es reicht, wenn die Templatedefinition in der selben Übersetzungseinheit wie die Instanziierung steht?
-
@Tyle:
Definiere doch mal _USE_MATH_DEFINES vor dem cmath Include. Dann dürfte auch PI definiert sein.Darfst du denn wenigstens Klassen nutzen? Dein Code ist ja an Grausamkeit schwer zu überbieten.