Doppelpunkt Bedeutung in Bedingung



  • Hallo,

    ich lerne gerade C++ mit dem Buch C++ programmieren (Ulrich Breymann). In einem seiner Beispiele hat er in einer for-Schleife eine Bedingung mit einem Doppelpunkt und ich finde im Buch und im Netz leider keine Antwort. Ich wäre wirklich dankbar, wenn mir jemand die Bedeutung des Doppelpunktes erläutern könnte.

    for (auto zeichen : str)
    

    Hier noch zur Vollständigkeit der komplette Code des Beispiels. Aufgabe ist es, den String als Long auszugeben.

    int main()
    {
      const string str{"17462309"};          // aus Aufgabentext
      long int z = 0L;
      for (auto zeichen : str) {
        z *= 10;
        z += static_cast<int>(zeichen) - static_cast<int>('0');
      }
      cout << "z = " << z;
    return 0;
    }
    

    Ich hatte die Aufgabe wie folgt gelöst, was ebenfalls funktioniert. Aber würde gerne den Doppelpunkt verstehen (gibt leider keine Erklärungen im Buch zu den Lösungen):

    
    const string Zahl = "17462309";
    long int Hilfsvariable { 0L };
    for (int i = 0; i < Zahl.length(); i++)
    	{
    		Hilfsvariable *= 10;
    		Hilfsvariable += static_cast<int>(Zahl.at(i)) - static_cast<int>('0');
    		
    	}
    	cout << "Die Zahl ist: " << Hilfsvariable << '\n';
    

    Vielen Dank,
    Tommy



  • In der pdf-Version des Buches steht dazu auf Seite 98:

    Zitat:
    Auf die Zählvariable kann verzichtet werden, wenn auf alle Elemente des Containers
    zugegriffen werden soll, weil dann die folgende Kurzform (englisch range based for)
    verwendet werden kann:

    for (double wert : einVektor) { // Kopie jedes Elements
    cout << wert << ’\n’;
    }
    

    Man kann die Schleife so lesen: Führe den Schleifenkörper für alle Objekte wert in
    einVektor aus. Die lokale Variable wert ist dabei eine Kopie des jeweiligen Elements
    des Containers. Die Kopie kann innerhalb der Schleife verändert werden, ohne dass sich
    die Änderung auf den Container auswirkt, etwa:

    for (double wert : einVektor) { // veränderliche Kopie
    wert = 2.0 * wert;
    cout << wert << ’\n’;
    }
    

    Ende des Zitats



  • Hallo Belli,

    vielen, vielen Dank dir!
    Jetzt wo du es geschrieben hast. Ist es mir auch eingefallen, dass ich es im Buch gesehen hatte. Hab es nur leider nicht mehr gefunden :(.

    Beste Grüße,
    Tommy



  • Wo ist eigentlich der Unterschied zwischen { irgendwas }; und = irgendwas;? Anscheinend ist C++ ja der Wilde Westen...



  • @EinNutzer0 hat hier jemand von Keksen gesprochen?



  • Das kommt auf den genauen Kontext (d.h. die konkreten Datentypen) an, aber lies dir mal die verschiedenen Initialisierungsmöglichkeiten durch: Initialization

    Das einheitliche Initialisieren mittels { ... } wird auch "uniform initialization" genannt, s.a. C++11/C++14 Uniform initialization sowie Modern C++ Features – Uniform Initialization and initializer_list.



  • @EinNutzer0 sagte in Doppelpunkt Bedeutung in Bedingung:

    Wo ist eigentlich der Unterschied zwischen { irgendwas }; und = irgendwas;? Anscheinend ist C++ ja der Wilde Westen...

    Das eine geht, das andere geht nicht:

    int main()
    {
       int a;
       int b;
       int irgendwas;
       
       a = 5;
       b = 10;
       irgendwas = 20;
       
       b = irgendwas; // geht
       b{irgendwas};  // geht nicht
    }
    


  • @Belli: Wenn du den Code von @EinNutzer0 genauer angesehen hättest, dann würdest du wohl verstehen, daß es um die Initialisierung geht (bei const string str{"17462309"}; bzw. const string Zahl = "17462309";).

    Und ansonsten könnte man es auch genau andersrum beantworten:

    int irgendwas;
    
    {irgendwas};  // geht
    = irgendwas; // geht nicht
    

    😉



  • @Th69 sagte in Doppelpunkt Bedeutung in Bedingung:

    @Belli: Wenn du den Code von @EinNutzer0 genauer angesehen hättest, dann würdest du wohl verstehen, daß es um die Initialisierung geht

    Die Stelle hab ich in:

    @EinNutzer0 sagte in Doppelpunkt Bedeutung in Bedingung:

    Wo ist eigentlich der Unterschied zwischen { irgendwas }; und = irgendwas;? Anscheinend ist C++ ja der Wilde Westen...

    wohl übersehen ...



  • Und wofür genau wird

    @Kvothe sagte in Doppelpunkt Bedeutung in Bedingung:

    static_cast<int>(

    benötigt? Also dieses static_cast<int>? Jedes Zeichen ist doch schon nur ein Codepoint. Und sogar, falls ein Zeichen keine "Zahl" sein sollte, wieso genügt nicht ein einfaches (int)?



  • @EinNutzer0 sagte in Doppelpunkt Bedeutung in Bedingung:

    Jedes Zeichen ist doch schon nur ein Codepoint.

    @EinNutzer0 sagte in Doppelpunkt Bedeutung in Bedingung:

    falls ein Zeichen keine "Zahl" sein sollte

    wtf



  • @Swordfish sagte in Doppelpunkt Bedeutung in Bedingung:

    wtf

    Sehr aufschlussreich.

    Hab es schon gefunden: https://stackoverflow.com/a/36310798

    Der static_cast<int> ist an der Stelle falsch. Was ist das für ein Buch, ich dachte, der Breymann sei euer Standardwerk?



  • Was genau ist denn falsch? Würde es auch gerne verstehen, da ich es ja anscheinend aktuell falsch lerne aus dem Buch.
    Danke, Grüße, Tommy



  • @Kvothe sagte in Doppelpunkt Bedeutung in Bedingung:

    Was genau ist denn falsch? Würde es auch gerne verstehen, da ich es ja anscheinend aktuell falsch lerne aus dem Buch.
    Danke, Grüße, Tommy

    Nichts



  • @Kvothe sagte in Doppelpunkt Bedeutung in Bedingung:

    Was genau ist denn falsch? Würde es auch gerne verstehen, da ich es ja anscheinend aktuell falsch lerne aus dem Buch.
    Danke, Grüße, Tommy

    Der cast ist überflüssig, wenn der string nur Ziffern enthält, und hier sind nur schlechtgelaunte Menschen. Das ist das Problem. Aber verunstalte deinen Code ruhig.



  • @EinNutzer0, @Kvothe: Nein, der static_cast<int> (bzw. in C (int)) ist nicht falsch, sondern hier nur überflüssig (der Code ist jedoch dadurch verständlicher).
    Es reicht

    z += zeichen - '0';
    

    Dies nennt sich "numeric promotion" (bzw. hier "integral promotion"), s.a. Implicit conversions (unter "Numeric promotions").

    @EinNutzer0: Dein Link ist übrigens nicht genau genug, denn ASCII ist zwar die (heute auf den meisten Systemen) übliche Zeichenkodierung, aber vom C sowie C++ Standard nicht einzig vorgeschriebene (z.B. gibt es noch EBCDIC). Es ist aber für die Ziffern garantiert, daß diese hintereinander von 0 bis 9 liegen, so daß man die Subtraktion durchführen kann (nur z.B. für Buchstaben gilt dies nicht mehr).
    Man sollte nur nicht direkt zeichen - 48 schreiben, da 48 nicht unbedingt der Code für 0 sein muß (leider sieht man es so sehr häufig in [Anfänger-]Code).



  • Danke. So hätte ich diese Aufgabenstellung angegangen...:

    #include <limits.h>
    #include <string>
    #include <iostream>
    
    unsigned long long getNumber(std::string s)
    {
        unsigned long long r = 0;
        for (char c : s) {
            int i = c - '0';
            if (i < 0 || i > 9 || r > ULLONG_MAX + (r * 10 + i)) {
                return r;
            }
            r = r * 10 + i;
        }
        return r;
    }
    
    int main(int argc, char* argv[])
    {
        using namespace std;
        string s = "98765432111111111101";
        cout << getNumber(s) << endl;
        for (unsigned long long test = ULLONG_MAX - 10; test != ULLONG_MAX; test++) {
            cout << getNumber(to_string(test)) << endl;
        }
        for (unsigned long long test = ULLONG_MAX; test != ULLONG_MAX - 10; test--) {
            cout << getNumber(to_string(test)) << endl;
        }
        cout << getNumber("-123trash") << endl;
        return 0;
    }
    

    (Also, ohne Akrobatik)



  • Hi, ich verstehe deine Lösung nur bedingt. Wenn ich sie ausführe kommt bei mir auch nicht die Nummer raus. Es fehlt hinten eine 1. Und die Punkte mit ULLONG_MAX sind mir auch noch neu. Verstehe daher die Lösung (siehe unten) nicht. Kannst du das genauer erklären was diese Tests machen?
    Danke dir, Beste Grüße Tommy

    9876543211111111110
    18446744073709551605
    18446744073709551606
    18446744073709551607
    18446744073709551608
    18446744073709551609
    18446744073709551610
    18446744073709551611
    18446744073709551612
    18446744073709551613
    18446744073709551614
    18446744073709551615
    18446744073709551614
    18446744073709551613
    18446744073709551612
    18446744073709551611
    18446744073709551610
    18446744073709551609
    18446744073709551608
    18446744073709551607
    18446744073709551606
    0



  • @Kvothe Die Ausgabe sieht bei mir auch so aus und ist intendiert.

    "98765432111111111101" ist für unsigned long long int zu groß, die Verarbeitung sollte also an geeigneter Stelle abgebrochen werden.

    Die Randbereiche (unsigned long long test = ULLONG_MAX - 10; test != ULLONG_MAX; test++ und unsigned long long test = ULLONG_MAX; test != ULLONG_MAX - 10; test--) sollten hingegen alle die Test passieren.

    "-123trash" ist Müll, der nicht geparst werden sollte (0 als Rückgabe oder eine Exception).

    Implementierung:
    r > ULLONG_MAX + (r * 10 + i) prüft, ob ein Overflow (Underflow?) stattfinden wird, und bricht in diesem Fall die Verarbeitung ab.



  • Hi, danke dir für die Antwort. Ich versuche es noch im Detail zu verstehen :). ULLONG_MAX habe ich nachgeschaut und hat diesen Wert: 18,446,744,073,709,551,615 (0xffffffffffffffff). Du ziehst von dem Maximalwert immer 10 ab und gehst dann 10 Schritte wieder hoch und gibst die Zahlen aus, korrekt? Was genau ist der Grund dafür? Um zu zeigen was der maximal darstellbare Wert von long long ist würde doch eine Ausgabe von getNumber(to_string(ULLONG_MAX) reichen, oder wo hängt es bei mir gerade?
    Sind die 10 einfach willkürlich gewählt um im Randbereich ein wenig mehr Sicherheit zu haben?

    Beste Grüße,
    Tommy


Log in to reply