Ergebnis 1 bis 10 von 10

Thema: [C++] Vector-Struct Problem

  1. #1

    [C++] Vector-Struct Problem

    Hallo,

    lang, lang ist's her, dass ich hier war ^^

    Mein Problem:

    Ich habe einen Vector, der auf einem Struct basiert und möchte diesem Vector nun ein Element hinzufügen.

    Code (c++):
    #include <iostream>
    // fuer Vectoren
    #include <vector>
     
    using namespace std;
     
    // Weight class
    class CWeight {
        private:
            struct sWeightEntry {
                char chDate[10];
                float fWeight;
            };
        public:
            // oeffentliche Variablen
            vector<sWeightEntry> vWeightList;
     
            // oeffentliche Funktionen definieren
     
            int AddWeight(char chDate[10], float fWeight) {
                cout << chDate << " : " << fWeight << "\n";
                vWeightList[0].chDate = chDate;
                vWeightList[0].fWeight = fWeight;
                return 0;
            }
    };
     
    // Hauptfunktion
    int main();
    // Gewichtsfunktionen
    int newEntry();
    int naviWeight();
     
    int main() {
        // clear screen
        clrscr();
     
        // print Menu
        // [code rausgenommen zur besseren Übersichtlichkeit (nur Ausgabe)]
     
        int iInput;
        cin >> iInput;
     
        switch(iInput) {
            case 1:
                naviWeight();
                break;
            case 99:
                // Beenden des Programms
                clrscr();
        }
     
        return 0;
    }
     
    int naviWeight() {
        clrscr();
        cout << "+++++++++++++++++++++\n";
        cout << "+                   +\n";
        cout << "+ ";
        cout << "q";
        cout << " - Zurueck       +\n";
        cout << "+ ";
        cout << "o";
        cout << " - Ueberblick    +\n";
        cout << "+ ";
        cout << "n";
        cout << " - neuer Eintrag +\n";
        cout << "+                   +\n";
        cout << "+++++++++++++++++++++\n\n";
     
        char chInput;
        cin >> chInput;
     
        switch(chInput) {
            case 'q':
                 main();
                 break;
            case 'o':
                 cout << "overview\n";
                 break;
            case 'n':
                 newEntry();
                 break;
        }
        return 0;
    }
     
    int newEntry() {
        CWeight mWeight;
     
        cout << "\nDatum:\n\n";
     
        char chDate[10];
        cin >> chDate;
     
        cout << "\nGewicht:\n\n";
     
        float fWeight;
        cin >> fWeight;
     
        mWeight.AddWeight(chDate, fWeight);
     
        // Eingabe von ner Zahl, damit es weitergeht
        int iIn;
        cin >> iIn;
     
        // Aufruf vom übergeordneten Menü
        naviWeight();
        return 0;
    }
     


    Die Fehlermeldung:
    Zitat Zitat
    ...\main.cpp||In member function `int CWeight::AddWeight(char*, float)':|
    ...\main.cpp|32|error: incompatible types in assignment of `char*' to `char[10]'|
    ||=== Build finished: 1 errors, 0 warnings ===|
    Wo liegt da das Haar in der Suppe?

    Geändert von Niji-chan (20.07.2009 um 10:21 Uhr)

  2. #2
    Die Compilerausgabe ...\main.cpp|32|error: incompatible types in assignment of `char*' to `char[10]'| bezieht sich auf folgende Quelltextzeile: vWeightList[0].chDate = chDate;

    Hier willst du einem Array vom Typ char was zuweisen. Da chDate prinzipiell die Adresse von chDate[0] darstellt und diese durch die Kompilierung schon fest steht, kannst du sie konventionell nicht ändern.

    Ein Lösungsansatz wäre die Daten einzeln zu verschieben oder einen Datentyp zu deklarieren, der die Adresse mit beinhaltet.

  3. #3
    @Niji:

    Du verstehst nicht wie man mit C-Feldern umgeht. Du versuchst ein Feld in ein anderes zu kopieren, indem du die Adresse, unter der das erste Feld erreichbar ist, zu der Adresse, unter der das zweite Feld erreichbar ist, änderst.
    So interpretiert es nämlich der Compiler, obwohl deine tatsächliche Intention die ist, die Werte der Elemente des ersten Feldes gleich denen des zweiten zu setzen.

    Der folgende Code zeigt wie man auf verschiedene Weisen eine tatsächliche Kopie eines Feldes erzielt:
    Code:
    #include <cstdlib>
    // ...
    char feld[10];
    char copy[10];
    
    // Möglichkeit 1 (elementweise Kopie)
    for (int i = 0; i < 10; ++i)
        copy[i] = feld[i];
    
    // Möglichkeit 2 (binäre Kopie mit memcpy)
    memcpy(copy, feld, 10);
    
    // Das wird nicht funktionieren!
    copy = feld;
    //...
    Übrigens (mir ist nicht klar, ob es dir bewusst ist): Es ist egal, ob du den Parametertyp als 'char*', 'char[]', oder 'char[10]' deklarierst. In allen Fällen handelt es sich um einen Zeiger auf einen 'char' und die optionale Deklaration der Länge dient höchstens dem Leser als Dokumentation: "Ah, hier erwartet er ein Feld aus 'char's mit der Länge 10".

    Zum weiteren Code will ich mich erstmal nur soweit äußern, dass er auf den ersten Blick wenig Sinn macht, angesichts dessen, was du mit dem Stack anstellst und deiner Menülogik. Ich denke, da gibt es noch weitere, nicht weniger gravierende Verständnisprobleme und vermute, dass du nach der Lösung des aktuellen Problems, noch mit weiteren konfrontiert sein wirst.

  4. #4
    PHP-Code:
    //nicht wirklich php code :P
    class CWeight {
        private:
            
    struct sWeightEntry {
                
    char chDate[10];
                
    float fWeight;
                
    sWeightEntry(const char *datefloat weight) : // Konstruktor
                    
    fWeight(weight// setzen von lokalem fWeight auf weight
                
    {
                    
    memcpy(chDatedatesizeof(chDate)); // kopieren der Array
                    
    chDate[9] = '\0'// sicherheitshalber
                
    }
            };
        public:
            
    // oeffentliche Variablen
            
    vector<sWeightEntryvWeightList;

            
    // oeffentliche Funktionen definieren

            
    void AddWeight(const char *chDatefloat fWeight) {
                
    cout << chDate << " : " << fWeight << "\n";
                
    vWeightList.push_back(sWeightEntry(chDatefWeight));
            }
    }; 

    Geändert von Drakes (12.07.2009 um 19:22 Uhr)

  5. #5
    Vielen lieben Dank!

    Da hab ich wohl noch einiges zu lernen

    Auf jeden Fall funktioniert es jetzt und ich kann jetzt weiter C++ üben

    Danke auch für die schnellen Antworten

    lg

  6. #6
    Ich würde noch den memcpy-Aufruf folgendermaßen schreiben...
    Code:
    memcpy(chDate, date, std::min(sizeof(date), sizeof(chDate)));
    ...denn memcpy erfordert, dass beide Blöcke mindestens die übergebene Länge haben.

    Wenn man davon ausgeht, dass es nullterminierte C-Strings sind (was die Parameter date und chDate sein können und im Grunde sind), wäre strlen angebrachter.

    Eigentlich gibt es aber überhaupt keinen Grund, wieso du hier nicht Strings anstelle von C-Strings verwenden solltest.
    Code:
    #include <string>
    //...
    
    // in einen string einlesen
    char buffer[10];
    std::cin.width(10); // maximal 9 buchstaben + die terminierende Null einlesen
    std::cin >> buffer;
    std::string s = buffer;
    
    // einen string initialisieren
    std::string t = "Hello World!";
    
    // einen string kopieren
    t = s;
    
    // einen string ausgeben
    std::cout << s.c_str();
    
    //...

    Geändert von Kyuu (12.07.2009 um 22:48 Uhr)

  7. #7
    Ok - thx nochmal

    Habe jetzt ein neues Problem …

    Ich speicher die eingegebenen Daten in einer binary-Datei. Wenn ich diese jedoch bei einem Neustart auslese kommt da nur irgend ein Blödsinn heraus - es steht dann also nicht sowas wie
    Code:
    24.07.2009    :    60
    sondern in etwa
    Code:
                         : 3029.21
    :\Program Files\[...]\ :  2.7404e+17
    Hat vll. jemand eine Idee woher das kommt / soll ich nochmal den Code posten, wie er zur Zeit aussieht?

    lg

  8. #8
    Ich weiss nicht genau, was du meinst. Eine Binaerdatei enthaellt doch nicht zwangsweise Text etc. Kommt drauf an, was du speicherst. Und eine Datei veraendert sich doch auch nicht beim Reboot. Sieht mir ehr nach einem Pointerfehler aus.

    Ohne Code kommen wir hier definitiv nicht weiter. Ich bin jetzt aber erst einmal 2 Wochen in "Urlaub".

  9. #9
    Code (c++):
    #include <iostream>
    // fuer Datenhandling
    #include <fstream>
    // fuer Textfarbe usw.
    #include <conio2.h>
    // fuer Vectoren
    #include <vector>
    // Namensraum std verwenden
    using namespace std;
    /**
     * Klasse zum Verarbeiten von Gewicht
    **/
    class CWeight {
        private:
            struct sWeightEntry {
                char chDate[10];
                float fWeight;
                sWeightEntry(const char *date, float weight) : // Konstruktor
                    fWeight(weight) // setzen von lokalem fWeight auf weight
                {
                    memcpy(chDate, date, sizeof(chDate)); // kopieren der Array
                    chDate[9] += '\0'; // sicherheitshalber
                }
            };
        public:
            // oeffentliche Variablen
            vector<sWeightEntry> vWeightList;
     
            // oeffentliche Funktionen definieren
     
            /**
             * Gewicht in Klassen-Vektor schreiben
             *
             * @param char chDate Datum bestehend aus 10 Zeichen
             * @param float fWeight Gewicht
             * @return void
            **/
            void AddWeight(const char *chDate, float fWeight) {
                cout << chDate << " : " << fWeight << "\n";
                vWeightList.push_back(sWeightEntry(chDate, fWeight));
            }
    };
     
    // nav class
    // hier weggelassen, da es im Grunde nur Ausgabe des Menüs ist
     
    class CDragonfly {
        private:
            // private vars
     
            CWeight mWeight;
     
            // vars to stop while-loops
            bool bEnd;
            bool bEndWeight;
     
            int iInput;
            char chInput;
     
            // private functions
     
            /**
             * get an int from user and return it
             * @return int integer which is entered by user
            **/
            int getIInput() {
                textcolor(LIGHTGREEN);
                int iInput;
                cin >> iInput;
                textcolor(LIGHTGRAY);
                return iInput;
            }
            /**
             * get a float from user and return it
             * @return float float which is entered by user
            **/
            float getFInput() {
                textcolor(LIGHTGREEN);
                float fInput;
                cin >> fInput;
                textcolor(LIGHTGRAY);
                return fInput;
            }
            /**
             * get a char from user and return it
             * @return char char which is entered by user
            **/
            char getChInput() {
                textcolor(LIGHTGREEN);
                char chInput;
                cin >> chInput;
                textcolor(LIGHTGRAY);
                return chInput;
            }
     
            int save() {
                ofstream output("scale.df", ios::binary);
                if(output == NULL) {
                    return -1;
                }
                output.write((char *) &mWeight, sizeof(mWeight));
                output.close();
                return 0;
            }
        public:
            CDragonfly() {
                // open file to read
                ifstream fileInput("scale.df", ios::binary);
                if(fileInput == NULL) {
                    //return -2;
                }
                fileInput.read((char *) &mWeight, sizeof(mWeight));
     
                bEnd = false;
                while(bEnd != true) {
                    CNav::MainNav();
                    iInput = getIInput();
     
                    switch(iInput) {
                        case 1:
                            bEndWeight = false;
                            while(bEndWeight != true) {
                                CNav::Weight();
                                chInput = getChInput();
     
                                switch(chInput) {
                                    case 'q': // go out of this menu
                                         bEndWeight = true;
                                         break;
                                    case 'o': // show the overview
                                         if(fileInput == NULL) {
                                             //return -2;
                                         }
                                         fileInput.read((char *) &mWeight, sizeof(mWeight));
                                         for(unsigned int i = 0; i < mWeight.vWeightList.size(); i++) {
                                             cout << mWeight.vWeightList[i].chDate << "\t:\t" << mWeight.vWeightList[i].fWeight << "\n";
                                         };
                                         iInput = getIInput();
                                         break;
                                    case 'n': // new weight-date input
                                         cout << "\nDatum:\n\n";
                                         textcolor(LIGHTGREEN);
                                         char chDate[10];
                                         cin >> chDate;
                                         textcolor(LIGHTGRAY);
     
                                         cout << "\nGewicht:\n\n";
                                         float fWeight;
                                         fWeight = getFInput();
     
                                         mWeight.AddWeight(chDate, fWeight);
                                         save();
                                         break;
                                }
                            }
                            break;
                        case 98: // show the main information
                            CNav::Info();
                            chInput = getChInput();
                            break;
                        case 99:
                            save();
                            fileInput.close();
                            clrscr();
                            bEnd = true;
                            break;
                    }
                }
            }
    };
     
    // Hauptfunktion
    int main();
     
    int main() {
        CDragonfly mDragonfly;
     
        return 0;
    }
     


    Problem tritt also an sich bei CDragonfly() am Anfang beim Auslesen der Datei auf.

    Edit: ach ja - und schönen Urlaub

  10. #10
    Sorry, aber diesen Wust werde ich mir nicht antun, zumal der aktuell Code Tag grausam ist. Im dunklen Design ist er faktisch unlesbar. Und da er nur 80 Zeichen breit ist, dein Code aber meher hundert Zeichen breit, allerdings der Scrollbalken nur ganz unten ist, ist das mehr als unleserlich. Und man kann nichtmal mit STRG+A den Quellcode markieren, um ihn in einem anderen Editor zu kopieren. Du solltest dir einen kuerzeren Codestil zulegen. EOE80 oder EOE120 maximal. Aber ich weiss selbst, wie schwer das ist.

    Edit: Ok, ich hab mir doch mal die Muehe gemacht, den Code in einen Editor zu kopieren und nen fluechtigen Blick drauf zu werfen.

    Code:
     output.write((char *) &mWeight, sizeof(mWeight));
    Das ist riesiger Bloedsinn. ostream.write kannst du im Grunde nur auf SDTs (Simple Data Types) anwenden, also auf byte, int, float, char und ihre arrays.
    Mit komplizierten Datentypen wie Structs, Classes oder Pointern funktioniert das nicht, wenn du auch bei einem struct ohne Methoden zufaellig Glueck haben kannst.
    Der Grund ist der, dass bei komplexen Datenstrukturen zusaetzliche Informationen gespeichert werden, die du so nicht zu Gesicht bekommst, wie Alignments im Speicher fuer schnelleren Datenzugriff, Loop-Up-Tabellen virtueller Methoden, Referenzen auf Elternklassen, Methodenpointer, usw. Wenn du nun so ein Objekt direkt in eine Datei schreibst, wird auch das genau gemacht: eine Kopie des aktuellen Objektes. Wenn du es aber wieder einladen willst, kommt nur noch schrott raus. Ueberall dort, wo du eine Array oder einen Pointer im Datentyp hast (und in Classes hast du viele Pointer, auch wenn du sie nicht immer siehst), wird ja nicht der Inhalt des Pointers gespeichert, sondern nur die Addresse, worauf er zeigt. Beim Einlesen liest er auch nur diese Addresse und dagt dem Objekt "Dort stehen deine Daten". Da diese Daten aber niemals gespeichert wurde, zeigt nun der Pointer irgendwo ins Nirvana, und dort kann alles moegliche stehen, und das ist fuer dein Programm einfach nur Datenmuell. Daher bekommst du nach jedem Neustart auch andere Werte, da der Pointer nach dem Einladen immer an die selbe Stelle zeigt, aber immer was anderes drin steht.

    Wie loest man nun das Problem ? Dazu wuerde ich dir empfehlen, dass du statt ostream.write einfach den << und den >> operator verwendest. Du solltest fuer ALLE(!) deine Klassen, die du speichern willst, den istream& operator>>(istream& instream) fuer die Eingabe und den ostream& operator<< (ostream& outstream) fuer die Ausgabe ueberladen. Diese Operatoren geben dann z.B. ueber outstream << fWeight; die Daten der einzelnen SDTs in den Stream aus bzw lesen sie in der selben Reihenfolge ein. Wenn du einen Member hast, der dynamisch alloziiert wird (z.B. ein Array mittels new) dann erzeugst du das entsprechende Array und liest alle Werte einzeln ein. Wenn deine Klasse Member hat, die ihrerseits Objekte sind, rufst du den entsprechenden operator>> oder operator<< der dazugehoehrigen Klasse auf, so dass sich die Klasse selber darum kuemmert. Wenn du allerdings nicht von dir geschriebene Objekte hast, die die >> und << nicht implementieren, musst du selbst Hand anlegen, z.B. bei std::vector<typ>. Im operator<< machst du dann sowas wie
    Code:
    vector<bla> v;
    ...
    outstream << v.size();    // wieviele Elemente hat mein vector ?
    for (int i=0; i<v.size(); ++i) { // ueber alle Elemente des Vectors
      outstream << v[i];     // Speichern des SDTs
    }
    ...
    und im operator>> machst du dann den umgekehrten Code
    Code:
    vector<bla> v;
    ...
    v.clear(); // Leeren des alten vectors.
    int num_elements = 0;
    instream >> num_elements; // wieviele Elemente hat mein vector ?
    bla dummyvariable;  // Variable vom typ der Vectorelemente
    for (int i=0; i<num_elements; ++i) {
      instream >> dummyvariable;   // Einlesen des SDTs
      v.push_back(dummyvariable);   // Speichern des SDTs im vector.
    }
    ...
    Wenn du das alles sauber und stimmig implementiert hast, so dass deine I/O nur noch auf SDTs basiert, klappt das auch mit dem Einlesen und Auslesen.

    Geändert von Ineluki (25.07.2009 um 01:35 Uhr)

Stichworte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •