Doppelpunkt Bedeutung in Bedingung



  • @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 ...


  • Gesperrt

    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


  • Gesperrt

    @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


  • Gesperrt

    @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).


  • Gesperrt

    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


  • Gesperrt

    @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



  • Ja, er will das Verhalten im Grenzbereich testen, was mal eine seiner guten Ideen ist.


  • Gesperrt

    #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) {
                continue;
            }
            if (r > ULLONG_MAX + (r * 10 + i)) {
                return ULLONG_MAX;
            }
            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;
    }
    

    ginge auch noch, aber das führt vielleicht zu Ergebnissen/Ausgaben, die nicht mehr nachvollziehbar wären. Insbesondere könnte "-123trash" -> 123 ein unerwünschtes oder unerwartetes Verhalten sein.

    Aber das kommt auf den Kontrakt an.



  • Hi Zusammen, jetzt habe ich noch eine Ergänzung zu der Frage. Im Buch in Kapitel 2. Funktions-Templates ist in dem Beispiel eine for-Schleife wie folgt angegeben:

    	for (const auto& element : vek) {
    		if (kleiner(max, element)) {
    			max = element;
    		}
    

    Was genau bewirkt das Referenz-Zeichen in dem Fall bei der Deklaration von element? Wenn ich es weglasse ändert sich erstmal gar nichts. So wie ich das verstehe, kann ich doch element durch const sowieso nicht ändern.


  • Mod

    Es ist schon richtig, dass das eine Referenz anlegt, und dass das Objekt dahinter trotz Referenz nicht änderbar ist. Aber Referenzen haben auch einen Sinn und Zweck jenseits von "darüber kann man das Objekt indirekt ändern": Man spart dadurch eine Kopie. Das kann in zwei Fällen nützlich sein. Zum einen gibt es Objekte, die man gar nicht kopieren kann (Streams beispielsweise). Zum anderen kann das auch effizienter sein, und zwar dann wenn das Erstellen einer Kopie sehr teuer ist. Stell dir beispielsweise vor, in deinem Vektor lägen lauter große Bilder.

    Referenzen auf const-Objekte sind sehr üblich und du wirst ihnen noch oft begegnen.



  • @SeppJ Hi SeppJ, das verstehe ich noch nicht so ganz, weil ich nach der Begründung im Buch davon ausgegangen bin, dass sowieso eine Kopie aller Werte des jeweiligen Elements des Containers angelegt wird (siehe Zitat unten).

    Aber verstehe ich dich richtig, dass der folgende Code - ohne Referenz - ein Objekt element anlegt, welches alle Elemente von vek kopiert hat:

    for (const auto element : vek)
    

    Und im folgenden Fall wird keine Kopie angelegt.

    for (const auto& element : vek)
    

    Ich glaube was mir fehlt ist die volle Bedeutung des Doppelpunktes. Nach meiner Logik fehlt noch die Initalisierung von element in folgendem Sinne:

    for (const auto& element{vek} : vek)
    

    So hatte ich zumindest Referenzen aus dem Buch verstanden. element ist eine Referenz auf ein Objekt. Aber ich muss das zu referenzierende Objekt ja auch erstmal angeben. Oder ist dies wieder durch "range based for" automatisch gegeben?

    @Belli sagte in Doppelpunkt Bedeutung in Bedingung:

    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



  • @Kvothe sagte in Doppelpunkt Bedeutung in Bedingung:

    Aber verstehe ich dich richtig, dass der folgende Code - ohne Referenz - ein Objekt element anlegt, welches alle Elemente von vek kopiert hat:

    Nein. Insbesonders der hintere Teil passt nicht: ... welches alle Elemente von vek kopiert hat

    In "element" ist jeweils nur ein Element (steht doch auch so im fett hervorgehobenen Zitat). Im ersten Schleifendurchlauf wird in element das erste Element aus dem Vektor kopiert. Dann kommt der Schleifenkörper. Danach wird in element das zweite Element aus dem Vektor kopiert und so weiter.

    Mit & ist element im 1. Durchlauf eine Referenz auf das erste Element, im 2. Durchlauf eine Referenz auf das 2. und so weiter.



  • @Kvothe Ich glaube, dass verstehst du noch nicht richtig.

    for (const auto element : vek)
    

    In jedem Schleifendurchlauf wird eine Kopie eines Element des Vektors angelegt. D.h. insgesamt wird jedes Element einmal kopiert.

    for (const auto& element : vek)
    

    In jedem Schleifendurchlauf wird eine Referenz auf ein Element des Vektors angelegt. D.h. die Daten, die an der jeweiligen Stelle des Vektores liegen, werden nicht kopiert.

    for (const auto& element{vek} : vek)
    

    Das ist Blödsinn. Der : Operator sorgt dafür, das element richitg initialisiert ist. Außerdem willst du immer nur auf ein Element aus dem Vektor zugreifen, d.h. es würde eh keinen Sinn ergeben, dass mit dem gesamten Vektor zu initialisieren.



  • @wob Ah okay :), vielen Dank!
    Ich bin bisher davon ausgegangen, dass "element" eine identische Kopie des gesamten Vektors ist und dann dessen Elemente durchgezählt werden. Damit ist einiges klarer.


Anmelden zum Antworten