String to Integer
-
Guck dir mal die Konvertierungsfunktionen aus der STL an, die braucht man nicht mehr selbst zu schreiben.
-
Ja schon aber darum geht es nicht. Eine Frage bleibt dennoch: In meinem Code lasse ich eine numerische Variable n mitlaufen damit ich den Index bekomme. Wie komme ich an den Index ohne diese zusätzliche Variable? Der müsste doch im Iterator stecken
for( string::reverse_iterator i = str.rbegin(); i != str.rend(); i++, n++)
also in i.
Viele Grüße, roro.
-
@nameName sagte in String to Integer:
Verwende '9' 'F' und 'f' anstatt Zahlen
Coller Tipp!!!! Danke!!!!
Machts lesbarer, viele Grüße!!
-
@_ro_ro sagte in String to Integer:
Coller Tipp!!!! Danke!!!!
Das klingt jetzt so, als seien meine übrigen Tipps/Review blöd
@_ro_ro sagte in String to Integer:
Wie komme ich an den Index ohne diese zusätzliche Variable?
Nimm doch eine einfache, normale for-Schleife, anstatt das iterator-Geraffel... Bei std::string s ist das zulässig
-
@_ro_ro sagte in String to Integer:
Ja schon aber darum geht es nicht. Eine Frage bleibt dennoch: In meinem Code lasse ich eine numerische Variable n mitlaufen damit ich den Index bekomme. Wie komme ich an den Index ohne diese zusätzliche Variable? Der müsste doch im Iterator stecken
for( string::reverse_iterator i = str.rbegin(); i != str.rend(); i++, n++)
also in i.
Viele Grüße, roro.
Worum denn, willst du das nur als Übungsaufgabe umsetzen? Und wofür brauchst du den Index? Vielleicht erklärst du mal, was genau du machen möchtest.
Über
std::distance
kannst du die Anzahl der Elemente zwischen zwei Iteratoren bestimmen. Bei reverse-iteratoren also die Anzahl der Elemente von hinten nach vorne. Vielleicht ist der bessere Ansatz, den string von vorne nach hinten zu durchlaufen, dann kommst du auch ohne das teurepow
aus. Und das Iterieren über den Inhalt geht mit range-based-for auch eleganter:uint32_t str2uint( std::string const& str, unsigned int base /*=10*/ ) { uint32_t retval = 0; for( auto ch : str ) { retval *= base; ... } return retval; }
Mir fallen da noch zwei Dinge auf:
- Die Funktion heißt
str2int
, konvertiert aber zuuint32_t
. Iststr2uint
da nicht vielleicht sinnvoller? - Du übergibst einen
base
Parameter, gehst aber davon aus, dass er immer 16 ist (jedenfalls wird jedes Zeichen auf den Bereich 0-15 geprüft). Für alle anderen Bases funktioniert deine Konvertierungfunktion nicht richtig.
- Die Funktion heißt
-
@DocShoe sagte in String to Integer:
Du übergibst einen base Parameter, gehst aber davon aus, dass er immer 16 ist
Nein. Die base wird übergeben. 16 ist nur der Default. Der numerische Index ist die Potenz für die base, wird also innerhalb der for()-Schleife gebraucht.
float f = pow(base,n);
ist der Koeffizient. So ergibt sich der numerische Wert zu
result += f*ord;
und das wird aufsummiert.
MFG
-
Ja, das sehe ich.
- was passiert bei base > 16? Teste doch mal mit base 18 und dem Alphabet [0-9a-h] (Kleinbuchstaben!)
- was passiert bei Base = 10 und dem string "deadbeef", was ist dann das Ergebnis?
PS:
Du hast immer noch nicht verraten, warum du die Funktionen aus der STL nicht benutzen kannst/möchtest.
-
Mein Compiler kennt std::stoi noch nicht. Also bleibt nur der Eigenbau. Eine Prüfung auf a-fA-F überlege ich mir noch. Die Perl-Funktion hex wirft eine Exception für den Fall daß Buchstaben > F oder > f ankommen. In meiner Umgebung wäre eine Exception natürlich auch ne Lösung.
MFG
-
@DocShoe sagte in String to Integer:
Über
std::distance
kannst du die Anzahl der Elemente zwischen zwei Iteratoren bestimmen. Bei reverse-iteratoren also die Anzahl der Elemente von hinten nach vorne. Vielleicht ist der bessere Ansatz, den string von vorne nach hinten zu durchlaufen, dann kommst du auch ohne das teurepow
aus. Und das Iterieren über den Inhalt geht mit range-based-for auch eleganter:Nach meinem Verständnis braucht man eher ein
pow
, wenn man den Zahlen-String eben von vorne nach hinten durchläuft. So wie ich den Code verstehe wird inf
der Stellenwert berechnet,
also der wert, mit dem der Ziffernwert multipliziert werden muss um den Gesamtwert der Zahl zu ermitteln (Der Stellenwert wäre also 1, 10, 100, 1000, ... für Dezimalzahlen oder 1, 2, 4, 8, ... für Binärzahlen).Rückwärts ist also okay, aber man braucht den Stellenwert nicht jedes mal mit der Fließkomma-Funktion
pow
neu zu berechnen, sondern man kann ihn einfach mitführen. Dann kann man nämlich direkt mit Integer-Werten arbeiten und braucht auch dasn
nicht mehr:uint32_t place_value = 1; for (...) { ... place_value = place_value * base; }
- Du übergibst einen
base
Parameter, gehst aber davon aus, dass er immer 16 ist (jedenfalls wird jedes Zeichen auf den Bereich 0-15 geprüft). Für alle anderen Bases funktioniert deine Konvertierungfunktion nicht richtig.
So wie ich das lese funktioniert das für alle Basen 16. Mit
ord
wird lediglich der Ziffernwert des aktuellen Zeichens ermittelt und dieser ändert sich zwischen verscheidenen Basen nicht:1 (hex) == 1 (dezimal) == 1 (binär)
. Das sollte also okay sein.
- Du übergibst einen
-
Ne, das funktioniert auch für Base = 10 nicht, weil nirgendwo eine Überprüfung eines einzelnen Zeichens gegen
base
stattfindet. Es werden alle Werte von 0-15 richtig geparst, aber es findet keine Plausibilitätsprüfung statt. Im Beispiel mit 'deadbeef' wird bei base10 fröhlich mit Werten >9 gerechnet. Das Ganze funktioniert nur mit base16 richtig.@_ro_ro :
Welchen Compiler benutzt du denn? Die STL Funktionen sind mit dem Standard C++11 eingeführt worden, das ist über 10 Jahre her. Musst du für deinen Compiler vllt nur den Sprachstandard festlegen (per Kommandozeilenparameter, Projekteinstellungen, etc)?
-
Natürlich werde ich meinerseits einer angemessen Fehlerbehandlung nachkommen. Ich habe jedoch gerade eben festgestellt daß es in der Server-Umgebung bereits eine Einrichtung gibt die malformed Hex-Strings erkennt. D.h., daß meine Fehlerbehandlung gar nicht mehr greift weil der Request schon vorher von abgefangen wird.
MFG
-
@DocShoe sagte in String to Integer:
Ne, das funktioniert auch für Base = 10 nicht, weil nirgendwo eine Überprüfung eines einzelnen Zeichens gegen
base
stattfindet. Im Beispiel mit 'deadbeef' wird bei base10 fröhlich mit Werten >9 gerechnet. Das Ganze funktioniert nur mit base16 richtig.Ja, das stimmt für ungültige Eingaben. Da bekommt base16 aber ebenfalls z.B. mit
1Z56
Probleme. Für Zeichen die mit einem Wert > 102 codiert werden, wird schliesslich der Wert direkt inord
übernommen. Da habe ich jetzt erstmal nicht den Fokus drauf gelegt sondern nur auf den Grundalgrorithmus. Es muss natürlich sichergestellt werden, dass nur gültige Ziffern verarbeitet werden bzw. die gesamte Eingabe stimmt.
-
@_ro_ro sagte in String to Integer:
Mein Compiler kennt std::stoi noch nicht. Also bleibt nur der Eigenbau. Eine Prüfung auf a-fA-F überlege ich mir noch. Die Perl-Funktion hex wirft eine Exception für den Fall daß Buchstaben > F oder > f ankommen. In meiner Umgebung wäre eine Exception natürlich auch ne Lösung.
MFG
Wenn es der gleiche compiler ist wie aus diesem post https://www.c-plusplus.net/forum/topic/354463/fehlermeldung-wenn-instanz-ohne-new-erstellt-wird/2
dann stellen sich 2 Fragen:- Wieso kannst du nicht einen neuere Version des compilers nutzen? Denn der mingw build 5.3.0 stammt aus 2015. Aktuell ist 11.0.0 (mit gcc 13.1.0)
- Wieso aktivierst du nicht den c++11 mode des compilers? Wie ich es hier grob beschrieben habe? https://www.c-plusplus.net/forum/topic/354463/fehlermeldung-wenn-instanz-ohne-new-erstellt-wird/4
-
#include <cstdint> #include <string> #include <set> #include <map> #include <stdexcept> #include <iostream> bool baseValid(const uint8_t base) { std::set<uint8_t> bases = {2, 4, 8, 10, 16, 32}; return bases.find(base) != bases.end(); } uint32_t str_to_uint32(const std::string &str, const uint8_t base = 10) { if (!baseValid(base)) { throw std::invalid_argument("Invalid base"); } std::map<char, uint8_t> charToNum = {{'0', 0}, {'1', 1}, {'2', 2}, {'3', 3}, {'4', 4}, {'5', 5}, {'6', 6}, {'7', 7}, {'8', 8}, {'9', 9}, {'a', 10}, {'b', 11}, {'c', 12}, {'d', 13}, {'e', 14}, {'f', 15}, {'g', 16}, {'h', 17}, {'i', 18}, {'j', 19}, {'k', 20}, {'l', 21}, {'m', 22}, {'n', 23}, {'o', 24}, {'p', 25}, {'q', 26}, {'r', 27}, {'s', 28}, {'t', 29}, {'u', 30}, {'v', 31}}; uint32_t result = 0; for (auto c : str) { auto cl = std::tolower(c); if (charToNum.find(cl) == charToNum.end()) { throw std::invalid_argument("Invalid character"); } result = result * base + charToNum[cl]; } return result; } int main(int argc, char const *argv[]) { std::cout << str_to_uint32("deadbeef", 16) << "\n"; std::cout << str_to_uint32("01237") << "\n"; return 0; }
Bei den includes bin ich mir unsicher, ob alle richtig sind.
Des Weiteren, bitte die Kompilierzeile mit angeben.
-
die Fehlerbehandlung geht auch so:
uint32_t str2int(string &str, uint8_t base = 16 ){ size_t n = 0; uint32_t result = 0; for( string::reverse_iterator i = str.rbegin(); i != str.rend(); i++, n++){ uint8_t ord = int(*i); if( ord >= '0' && ord <= '9' ) {ord -= 48;} // 0-9 else if( ord >= 'a' && ord <= 'f') {ord -= 87;} // a-f else if( ord >= 'A' && ord <= 'F') {ord -= 55;} // A-F else{ throw string("Wrong Character in Parameter-String"); } float f = pow(base,n); result += f*ord; } return result; }
Also gleich da wo es knallen könnte.
Danke auch und Viele Grüße!!!
-
Bitte Codeschnipsel immer formatiert posten... Gebot des Anstands.
-
@nameName sagte in String to Integer:
Bitte Codeschnipsel immer formatiert posten... Gebot des Anstands.
nun, ich bevorzuge in Sachen Einrückung den Style Java Sun. Und der ist absolut legitim
Viele Grüße.
-
Ich hätte auch schreiben können, das ist eine Selbstverständlichkeit. Und nein, dein Code ist nicht formatiert. Bin mal raus aus dem Thema.
-
@nameName sagte in String to Integer:
Ich hätte auch schreiben können, das ist eine Selbstverständlichkeit. Und nein, dein Code ist nicht formatiert. Bin mal raus aus dem Thema.
Meinen Code habe ich mit den Mitteln formatiert die das Forum dazu anbietet. Infolgedessen sieht der von mir gepostete Code ganz genauso aus wie der Code den die Anderen hier gepostet haben.
MFG
-
@_ro_ro sagte in String to Integer:
@DocShoe
Mein Compiler kennt std::stoi noch nicht.Ernsthaft?
Bist du sicher, dass du dann nicht upgraden solltest? Die Funktion gibt es seit C++11 (also seit 2011). Wir haben jetzt 2024. Bist du sicher, dass du wirklich einen so alten Compiler (oder Standardbibliothek) hast oder brauchst?
Welchen Compiler verwendest du in welcher Version?
Dann hättest du ja auch keine Smart-Pointer zur Verfügung?! Und
std::auto_ptr
ist seitstd::unique_ptr
nicht mehr zeitgemäß. C++11 war ein riesiges Update der Sprache C++ mit unzähligen neuen Features. Du programmierst doch auch nicht in Perl 4?! Und würdest sicher niemandem raten, Perl 4 zu lernen.