Lösung von Aufgabe aus C++ Primer



  • Noch eine andere Übung (ich mach jetzt nicht extra einen neuen Thread auf):
    3.13

    Lesen Sie eine Reihe von Intergerzahlen in einen Vektor ein. Berechnen Sie die Summe von jeweils zwei aufeinander folgenden Elementen und geben Sie sie aus. Wenn die Anzahl der Elemente ungerade ist, teilen Sie dies dem Benutzer mit und geben den letzten Wert ohne Addition aus. [MIT ITERATOREN LÖSEN, NICHT MIT INDIZES!]

    Hier der Code:

    #include <iostream>
    #include <string>
    #include <vector>
    
    using std::cin;
    using std::cout;
    using std::endl;
    using std::string;
    using std::vector;
    
    int main()
    {
        vector<int>::size_type elements;
        vector<int> values;
        cout << "Wieviele Elemente? ";
        cin >> elements;
    
        for(vector<int>::size_type j = 1; j <= elements; ++j)
        {
            int temp = 0;
            cin >> temp;
            values.push_back(temp);
        }
    
        cout << endl;
    
        int temp = 0;
        short counter = 0;
    
        for(vector<int>::iterator iter = values.begin(); iter != values.end(); ++iter)
        {
            temp += *iter;
            ++counter;
            if(counter == 2)
            {
                cout << temp << endl;
                temp = 0;
                counter = 0;
            }
        }
    
        if( (elements % 2) != 0)
        {
            vector<int>::iterator iter = values.end();
            --iter;
            cout << "Anzahl der Elemente ist ungerade." << endl;
            cout << *iter << endl;
        }
    
        return 0;
    }
    

    Eure Meinung ist wieder gefragt.
    Was mit sehr gefehlt hat, ist eine Funktion oder sowas, mit der ich sehen kann wo sich der Iterator gerade befindet (gibts dass?), kam leider in meinem Buch noch nicht vor.
    Was mir auch noch gefehlt hat, wie kann ich einen Iterator mal mehr als ein Element erhöhen/erniedrigen? (den nur mit "++/--" ist dass äußerst aufwendig)
    Kam leider auch noch nicht in meinem Buch vor.

    MfG
    Stromberg



  • if(values.empty())
    {
    //nichts zu berechnen
    }
    for(vector<int>::const_iterator iter = values.begin(), end (values.end()), last(values.end()-1); iter != end; iter += 2)
    {
     if(iter == last)
     {
      cout << "ungerade: " << *iter << endl;
     }
     else
     {
      cout << *iter + *(iter+1) << endl;
     }
    }
    

    Was mit sehr gefehlt hat, ist eine Funktion oder sowas, mit der ich sehen kann wo sich der Iterator gerade befindet (gibts dass?)

    ich weiß nicht, wozu man das brauchen sollte - aber es gibt so etwas:
    std::distance (zu finden in <iterator>) - musst nur aufpassen, dass er auch auf den letzten iterator kommt mit dem gegebenen startiterator - sonst siehts bissl schlecht aus ^^

    Was mir auch noch gefehlt hat, wie kann ich einen Iterator mal mehr als ein Element erhöhen/erniedrigen?

    Mit +=/-= - geht aber imho nur bei random access-containern (std::vector ^^)

    for(vector<int>::size_type j = 0; j < elements; ++j) //find es von 0 hübscher ^^
        {
            int temp; //über die initialisierung hier lässt sich sicherlich streiten - ab und an mach ich das zwar auch, aber hier ists denke ziemlich sinnlos ^^
            cin >> temp;
    //evtl noch überprüfung auf good, ggf. flags wieder setzen oder direkt mit exceptions arbeiten...
            values.push_back(temp);
        }
    

    so würd ich es jz auf die schnelle machen...

    bb



  • Die Abbruchbedingung iter != values.end() -1 verstehe ich noch nicht so ganz.
    Wenn ich z.B. 10 Elemente habe, dann ist iter am Anfang 0.
    Dann "+2" iter = 2.
    Dann "+2" iter = 4.
    Dann "+2" iter = 6.
    Dann "+2" iter = 8.
    Dann "+2" iter = 10. (values.end()) was doch eigentlich gar nicht möglich ist.

    Und end()-1 wäre iter ja eigl. 9. Aber auf 9 kommt man ja nie. Ich bin verwirrt, is glaub schon zu spät für mich, kannst du mir dass bitte nochmal erklären?

    MfG
    Stromberg



  • das von unskilled crashed auch wunderbar bei ungeraded anzahl.



  • sry, hier fehlt noch nen break:

    if(iter == last) 
     { 
      cout << "ungerade: " << *iter << endl; 
      break; //hier ^^
     }
    

    also bei 3 Elementen sollte das so in etwa funzen:

    1.Element
      iter == last <= false
      -> *iter + *(iter+1) == Summe aus 1+2
    -> iter += 2
    3.Element
      iter == last <= true
      -> "ungerade: " << *iter
      -> break
    

    das mit dem break lag wohl daran, dass es schon ein wenig später war und so ^^
    naja - happy christmas :xmas2:

    bb



  • Zum Einlesen übrigens noch:

    #include <iterator>
    
    …
    
    std::copy(std::istream_iterator<int>(std::cin), std::istream_iterator<int>(), std::back_inserter(vec));
    

    Einzeiler sind doch toll 🙂



  • Hier der 2. Teil der Übung, ist nun bloß n bisschen abgeändert.

    Ändern Sie das Programm nun so, dass es zuerst die Summe des ersten und des letzten, dann die Summe des zweiten und des vorletzten Elements ausgibt usw. [bezogen auf 1. Teil]

    Hab dass dann so, unter Einbeziehung eurer ganzen Ratschläge, Tipps..., umgesetzt.

    #include <iostream>
    #include <string>
    #include <vector>
    
    using std::cin;
    using std::cout;
    using std::endl;
    using std::string;
    using std::vector;
    
    int main()
    {
        vector<int>::size_type elements;
        vector<int> values;
        cout << "Wieviele Elemente? ";
        cin >> elements;
    
        for(vector<int>::size_type i = 0; i<elements; ++i)
        {
            int temp = 0;
            cout << "Wert " << i+1 << ":";
            cin >> temp;
            values.push_back(temp);
        }
    
        cout << endl;
    
        for(vector<int>::const_iterator iter_begin = values.begin(), iter_end = values.end()-1;
        iter_begin != iter_end + 1; ++iter_begin, --iter_end)
        {
            if(iter_begin == iter_end)
            {
                cout << "Anzahl der Elemente ist ungerade." << endl;
                cout << "Restwert: " << *iter_begin;
                break;
            }
            cout << *iter_begin + *iter_end << endl;
        }
    
        return 0;
    }
    

    So ists aber doch sehr gut, oder kann man daran noch etwas aussetzen? (Stil / Allg. Verbesserungen?)

    MfG
    Stromberg



  • Und nun noch die andere Aufgabe:

    Lesen Sie Text in einen Vektor ein und speichern Sie jedes Wort der Eingabe als Vektorelemenet. Verwandeln Sie die Wörter in Großbuchstaben. Geben Sie die umgewandelten Elemente in Zeilen zu je acht Wörtern aus.

    Aber diesmal darf man es nur mit Iteratoren lösen, nicht mit Indizes.

    Hier der Code:

    #include <iostream>
    #include <string>
    #include <vector>
    #include <cctype>
    
    using std::cin;
    using std::cout;
    using std::endl;
    using std::string;
    using std::vector;
    
    int main()
    {
        vector<string> words;
        string temp;
        while(getline(cin,temp) and temp != "~")
        {
            words.push_back(temp);
        }
    
        for(vector<string>::iterator iter = words.begin(); iter != words.end(); ++iter)
        {
            for(string::iterator string_iter = (*iter).begin(); string_iter != (*iter).end(); ++string_iter)
            {
                *string_iter = toupper(*string_iter);
            }
    
            cout << *iter << " ";
            if((distance(words.begin(),iter) + 1) % 8 == 0) cout << endl; //immer nach 8 Wörtern Zeilenumbruch
        }
    
        return 0;
    }
    

    Eure Meinung? Wie hätte ihr dass gelöst? .....

    MfG
    Stromberg



  • for(vector<int>::size_type i = 0; i<elements; ++i)
        {
            int temp = 0;
            cout << "Wert " << i+1 << ":";
            cin >> temp;
            values.push_back(temp);
        }
    

    =>

    //cin.exceptions setzen + try/catch drum packen oder fehler-flags nach jeder eingabe prüfen
        for(vector<int>::size_type i = 0; i < elements;)
        {
            cout << "Wert #" << ++i << ":"; //unser i+1
            int temp;
            cin >> temp;
            values.push_back(temp);
        }
    
    for(vector<int>::const_iterator iter_begin = values.begin(), iter_end = values.end()-1; iter_begin != iter_end + 1; ++iter_begin, --iter_end)
    

    1. Wer hat das vorgeschlagen?
    2. Was willst du dort machen?

    return 0; ist zwar nicht falsch aber warum schreibst du es mit hin?

    (*iter).begin()
    

    Wie wärs statt dessen mit iter->begin() - dann sieht man vll auch noch durch?! ^^

    for(vector<string>::iterator iter = words.begin(); iter != words.end(); ++iter)
    

    Hier wird jedes mal wieder words.end() aufgerufen... Ist bei Vektor "nur" data+elements - aber trotzdem sinnlos, weil vermeidbar - glaube auch nicht, dass das rausoptimiert wird...

    for(vector<string>::iterator iter = words.begin(); iter != words.end(); ++iter)
        {
            for(string::iterator string_iter = (*iter).begin(); string_iter != (*iter).end(); ++string_iter)
            {
                *string_iter = toupper(*string_iter);
            }
    
            cout << *iter << " ";
            if((distance(words.begin(),iter) + 1) % 8 == 0) cout << endl; //immer nach 8 Wörtern Zeilenumbruch
        }
    

    Ich weiß zwar, dass es so performanter ist, aber ich würde IMMER die eingabe von der verarbeitung und die wiederrum auch von der ausgabe trennen - die geschwindigkeits-einbußen sollten zu vernachlässigen sein, aber man könnte es dann schön in aufgabenbereiche aufsplitten - und es gehört halt einfach nicht zusammen ^^ (ausahmen sind nat., wenn man n elemente addieren soll diese aber danach nicht mehr braucht - aber ich finds trotzdem hässlich so was zu mischen ^^)

    bb



  • for(vector<int>::const_iterator iter_begin = values.begin(), iter_end = values.end()-1; iter_begin != iter_end + 1; ++iter_begin, --iter_end)
    

    Ich habe mir dass so gedacht. Die Aufgabenstellugn war hier doch neu, man sollte das erste und dass letzte Feld addieren, das zweite und das vorletzte...u.s.w.
    Somit lass ich einen Iterator von vorne (iter_begin) und einen von hinten (iter_end) ablaufen, und addiere die beiden.

    Wie soll ich dass dann verbessern?

    for(vector<string>::iterator iter = words.begin(); iter != words.end(); ++iter)
    

    so

    const vector<string>::const_iterator end = words.end()
    for(.....; iter != end;.......)
    

    ??? Oder wie meinst du dass?
    Ich kann mir aber nicht vorstellen, dass jedesmal words.end() neu aufgerufen wird, ich glaub schon dass der Compiler des wegoptimiert.

    MfG
    Stromberg

    PS: Danke für deine Hilfe.



  • Zum Rückwärtsdurchgehen verwendet man üblicherweise container::reverse_iterator.

    Gruß
    Don06


Anmelden zum Antworten