• Liebe User, bitte beachtet folgendes Thema: Was im Forum passiert, bleibt im Forum! Danke!
  • Hallo Gemeinde! Das Problem leidet zurzeit unter technischen Problemen. Wir sind da dran, aber das Zeitkontingent ist begrenzt. In der Zwischenzeit dürfte den meisten aufgefallen sein, dass das Erstellen von Posts funktioniert, auch wenn das Forum erstmal eine Fehlermeldung wirft. Um unseren Löschaufwand zu minimieren, bitten wir euch darum, nicht mehrmals auf 'Post Reply' zu klicken, da das zur Mehrfachposts führt. Grußworte.

Merkwürdiges C++ Problem

Mitglied seit
12.04.2003
Beiträge
1.806
Reaktionen
0
Also ich will gerade ein Programm zur Berechnung von Gewichten von Quadraturformeln schreiben, läuft auch ganz gut, allerdings habe ich gerade ein sehr merkwürdiges Problem:
Die Funktion "weights" wird nur dann richtig aufgerufen, wenn die Funktion "Multiply" vorher aufgerufen wurde. Also wenn man in der Main die Funktion "Multiply" weglässt, dann wird die äußere Schleife in der Funktion "weights" nur einmal durchlaufen und dann bricht die Funktion ab und zwar nachdem das "RUNDE " << i << " DURCHLAUFEN"<< da steht.
Wenn der viele Code zu nervig ist kann ich den auch noch reduzieren, aber eigentlich ist das Programm sehr einfach und das Problem liegt nur bei den beiden Funktionen, die irgendwie voneinander abhängen...


Code:
#include <iostream>
#include <list>
#include <cmath>
using namespace std;

class variable{

    private:
    int exponent;
    pair<int, int> koeffizient;

    public:
    void kuerzen(){
        int ctr=2;
        while (ctr<=abs(koeffizient.first) && ctr<=abs(koeffizient.second)){
            if (koeffizient.first%ctr==0 && koeffizient.second%ctr==0){
                koeffizient.first/=ctr;
                koeffizient.second/=ctr;
            }
            else ctr++;
        }
        if(koeffizient.first<0 && koeffizient.second<0){
            koeffizient.first=abs(koeffizient.first);
            koeffizient.second=abs(koeffizient.second);
        }
        else if(koeffizient.first>0 && koeffizient.second<0){
            koeffizient.first=koeffizient.first*(-1);
            koeffizient.second=abs(koeffizient.second);
        }
    }
    variable(){exponent=0; koeffizient.first=0; koeffizient.second=1;};
    variable(int koe1, int koe2, int exp){
        exponent=exp;
        koeffizient.first=koe1;
        koeffizient.second=koe2;
        kuerzen();
    };

    void set_koe1(int koe1){koeffizient.first=koe1; kuerzen();}
    void set_koe2(int koe2){koeffizient.second=koe2; kuerzen();}
    void set_exp(int exp){exponent=exp;}
    int get_exp(){return exponent;}
    int get_koe1(){return koeffizient.first;}
    int get_koe2(){return koeffizient.second;}
    void print(){
        if (exponent!=0 && exponent !=1)
            cout << koeffizient.first << "/" << koeffizient.second << "*" << "x"<< "^" << exponent;
        else if (exponent==1)
            cout << koeffizient.first << "/" << koeffizient.second << "*" << "x";
        else if (exponent==0)
            cout << koeffizient.first << "/" << koeffizient.second;
    }
};

class term{
////ÄNDERN: PUBLIC-PRIVATE
    public:
    list<variable*> m_list;


    void add(variable *monom){m_list.push_back(monom);}

    void print(){

        list<variable*>::iterator iter;
        iter=m_list.begin();
        for (int i=0; i<m_list.size(); i++){
            (*iter)->print();
            if(i==m_list.size()-1) break;
            else{
                if ((*++iter)->get_koe1()>0)
                cout << "+";
            }

        }
        cout << endl;
    }

    void integrate(){
        list<variable*>::iterator iter;
        for (iter=m_list.begin(); iter!=m_list.end(); iter++){
            (*iter)->set_koe2((*iter)->get_koe2()*((*iter)->get_exp()+1));
            (*iter)->set_exp((*iter)->get_exp()+1);
        }
    }
};

void multiply(term *fterm, term *sterm, term *&solution){
    variable *temp_vari;

    solution=new term;
    list<variable*>::iterator iter1;
    list<variable*>::iterator iter2;

    for(iter1=(*fterm).m_list.begin(); iter1!=(*fterm).m_list.end(); iter1++){
        for (iter2=(*sterm).m_list.begin(); iter2!=(*sterm).m_list.end(); iter2++){
            temp_vari=new variable;
            temp_vari->set_koe1((*iter1)->get_koe1()*(*iter2)->get_koe1());
            temp_vari->set_koe2((*iter1)->get_koe2()*(*iter2)->get_koe2());
            temp_vari->set_exp((*iter1)->get_exp()+(*iter2)->get_exp());
            solution->add(temp_vari);
        }
    }
    solution->print();
}

void weights(int n){

    term *alpha;
    term *tempterm1, *tempterm2;
    variable *tempvar1, *tempvar2;
    for (int i=0; i<=n; i++){
        //alpha=new term;
        for (int j=0; j<=n; j++){
            if(i!=j){
                tempvar1=new variable;
                tempvar1->set_exp(1);
                tempvar1->set_koe1(n);
                tempvar1->set_koe2(i-j);
                tempvar2=new variable;
                tempvar2->set_exp(0);
                tempvar2->set_koe1(-j);
                tempvar2->set_koe2(i-j);
                tempvar1->print();
                cout << endl;
                tempvar2->print();
                cout << endl;
                cout << "RUNDE " << i  << " DURCHLAUFEN"<< endl;
                tempterm1->add(tempvar1);
                tempterm1->add(tempvar2);

            }

        }
    }


}





int main(){


variable *neu, *neu2, *neu3;
neu=new variable(-1,2,1);
neu2=new variable(2,3,3);
neu3=new variable(3,-4,4);
term *eins;
term *zwei;
term *drei;
eins=new term;
zwei=new term;
eins->add(neu);
eins->add(neu2);
zwei->add(neu3);
eins->print();
zwei->print();
multiply(eins, zwei, drei);
int n=1;
weights(n);
return 0;


}
 
Mitglied seit
08.07.2001
Beiträge
1.625
Reaktionen
0
Kannst du das Problem bitte auf ein Minimalbeispiel reduzieren? Bei soviel Code hält sich meistnes die Lust zu helfen in Grenzen. Und noch ne genauere Beschreibung was das Programm machen soll, cih blick dei Erklärung grad nicht.
 
Zuletzt bearbeitet:

voelkerballtier

Coverage, Staff, Coding
Mitglied seit
01.12.2003
Beiträge
1.603
Reaktionen
0
dein problem liegt afaik nur in der weight funktion. Dort dereferenzierst du zeiger, die nicht initialisiert wurden, nämlich tempterm1 und tempterm2.

Code:
#include <iostream>
void weights(int n){

    term *alpha;
/////////////////////////// zeiger erstellen, aber kein speicher holen
    term *tempterm1, *tempterm2;
//////////////////////////
    variable *tempvar1, *tempvar2;
    for (int i=0; i<=n; i++){
        //alpha=new term;
        for (int j=0; j<=n; j++){
            if(i!=j){
                tempvar1=new variable;
                tempvar1->set_exp(1);
                tempvar1->set_koe1(n);
                tempvar1->set_koe2(i-j);
                tempvar2=new variable;
                tempvar2->set_exp(0);
                tempvar2->set_koe1(-j);
                tempvar2->set_koe2(i-j);
                tempvar1->print();
                cout << endl;
                tempvar2->print();
                cout << endl;
                cout << "RUNDE " << i  << " DURCHLAUFEN"<< endl;
                //////////////////// uninitialisierte zeiger dereferenzieren
                //////////////////// sollte segmentation fault werfen
                tempterm1->add(tempvar1);
                tempterm1->add(tempvar2);
                ////////////////////
            }

        }
    }


}

dass es funktioniert, wenn du vorher multiply aufrufst ist vermutlich einfach zufall, weil dann auf den speicheradressen tempterm1 grad noch nen term liegt.

Aber mal allgemein - warum benutzt du überhaupt so haufenweise zeiger? Ich seh auch kein einziges delete, du produzierst also haufenweise speicherleaks. Und das:

term *&solution

macht irgendwie gar keinen Sinn - nen Pointer auf ne Referenz?
Also ich behaupte mal du brauchst für dein Programm keinen einzigen Zeiger auf irgendwas - der momentane code ist auf jeden fall ein ziemlicher mess... sorry.
 
Mitglied seit
08.07.2001
Beiträge
1.625
Reaktionen
0
So. Wie gesagt so ganz blick ich den Code noch net, noch dazu ist er absoult unsauber. Aber was dir auf jeden Fall ist ein

tempterm1 = new term;
tempterm2 = new term;

@den über mir: unsere Beiträge ham sich überschnitten. Aber ich geb dir absolut recht, der Code ist absolute Katastrophe.
 
Mitglied seit
12.04.2003
Beiträge
1.806
Reaktionen
0
Ah danke :catch:

also an sich programmiere ich das nur um in den Semesterferien nicht aus der übung zu kommen, wird also keine weitere funktion haben. Natürlich würde ich sonst die ganzen Klassen und Funktionen auslagern.

Warum sollen denn die Zeiger keinen Sinn machen? Ansonsten kopiere ich die ganzen Objekte ja immer bei nem Funktionsaufruf.
Also z.b. bei der weights Funktion werden später einige Objekte der Klasse Term erstellt, die wiederum aus Variablen bestehen, die werden dann untereinander multipliziert und dann noch integriert. Und dafür würden die immer wieder kopiert werden. Und die deletes werden natürlich noch folgen :)

und *&solution ergibt Sinn. Wenn man in der Main drei->print() aufrufen würde, würde es ohne das & nicht funktionieren weil der Zeiger in der main nicht verändert wird.

Ach ja und zur Funktion falls es irgendwen noch interessiert:
Ich will das hier berchnen:
latex2png.php
(letzte Zeile)
Und was die einzelnen Funktionen machen sollte sich ja aus dem Namen ergeben :) (bis auf weights, aber darin wird sich wahrscheinlich dann die Schlussendliche Berechnung der Gewichte abspielen)

edit: ja bild sieht scheiße aus, aber hab gerade keine Lust nen besseres zu suchen also: rechtsklick->grafik anzeigen
 
Zuletzt bearbeitet:

voelkerballtier

Coverage, Staff, Coding
Mitglied seit
01.12.2003
Beiträge
1.603
Reaktionen
0
Ah danke :catch:

also an sich programmiere ich das nur um in den Semesterferien nicht aus der übung zu kommen, wird also keine weitere funktion haben. Natürlich würde ich sonst die ganzen Klassen und Funktionen auslagern.

Warum sollen denn die Zeiger keinen Sinn machen? Ansonsten kopiere ich die ganzen Objekte ja immer bei nem Funktionsaufruf.
Also z.b. bei der weights Funktion werden später einige Objekte der Klasse Term erstellt, die wiederum aus Variablen bestehen, die werden dann untereinander multipliziert und dann noch integriert. Und dafür würden die immer wieder kopiert werden. Und die deletes werden natürlich noch folgen :)

Dafuer gibt es in c++ referenzen.

und *&solution ergibt Sinn. Wenn man in der Main drei->print() aufrufen würde, würde es ohne das & nicht funktionieren weil der Zeiger in der main nicht verändert wird.

sorry mein fehler - *& ist ref-to-ptr nicht ptr-to-ref und damit natuerlich sinnvoll.

Dennoch: du kannst den ganzen Pointer-Kram weglassen und die Funktionsargumente als Referenzen setzen, dann wird auch nix mehr kopiert und alles wird lesbarer. Wenn du in C++ Pointer benutzt musst du dafuer schon einen sehr guten Grund haben - und Vermeidung von Kopien bei Funktionsaufrufen gehoert sicherlich nicht dazu.
 
Mitglied seit
12.04.2003
Beiträge
1.806
Reaktionen
0
Hmm also an sich war ich mir da recht sicher (eher Pointer als Referenzen nutzen), aber ich hab bisher auch nur ein Buch über C++ gelesen und es in einem Semester reingeballert bekommen und noch nicht allzu viele praktische Erfahrungen (natürlich schon 1000 "Programme" geschrieben aber keins mehr als 800 Zeilen). Falls das hier sarkastisch rüberkommt, das soll es nicht.
Was machen Referenzen denn besser als Pointer? Ich meine gelesen zu haben, dass es gerade anderesrum ist: es gibt beides, aber man nutz kaum die Referenzen.
 

voelkerballtier

Coverage, Staff, Coding
Mitglied seit
01.12.2003
Beiträge
1.603
Reaktionen
0
welches buch war das denn?
Wenn du Pointer vermeidest musst du dich nicht um die Speicherverwaltung kuemmern. Ohne Pointer haettest du den hier besprochenen Bug nicht gehabt.
Lustigerweise benutzt du mit *& dann doch ne referenz, obwohl du konsequenterweise ** haettest nehmen muessen :)

Sowas z.Bsp.:
Code:
void multiply(term *fterm, term *sterm, term *&solution){
    variable *temp_vari;

    solution=new term;
    ...
    solution->print();
}
schreit foermlich nach Speicherleck, weil du in ner funktion speicher holst, der dann irgendwo anders freigegeben werden muss. Rufst du zweimal multiply mit dem gleichen pointer auf, kannst du den ersten nich mehr freigeben. schlecht...

Prinzipiell solltest du immer wenn du ein new schreibst direkt danach das entsprechende delete einbauen, sowas nachher zu machen fuehrt erfahrungsgemaess immer zu speicherproblemen...
 
Zuletzt bearbeitet:
Mitglied seit
12.04.2003
Beiträge
1.806
Reaktionen
0
Also das Buch war c++ für Spieleprogrammierer und.. naja ich hatte jetzt halt ein Semester c++ und da sind wir auch wesentlich mehr auf Pointer als auf Referenzen eingegangen. Aber jetzt wo ich so drüber nachdenke sollte ich mir vielleicht doch noch mal den Unterschied angucken, denn das was Du sagst stimmt schon (dass ich die ganzen 'new's nicht mehr wegbekomme :) ).
 

ROOT

Technik/Software Forum, Casino Port Zion
Mitglied seit
17.11.2002
Beiträge
7.052
Reaktionen
38
Ort
MS
Mit Pointern spart man sich immerhin das ganze call-by-ref geconste, das machts schon fast wieder einfacher :naughty:
 

voelkerballtier

Coverage, Staff, Coding
Mitglied seit
01.12.2003
Beiträge
1.603
Reaktionen
0
naja nur wenn man dann auf const-correctness verzichtet. Ansonsten schreibt man auch T const * p mit gleichem Aufwand...
 
Oben