einzelne Ziffern einer Zahl auslesen
-
Woher weißt du da, wie groß buf sein muss?
-
Soll sich halt der Aufrufer drum kümmern. So wie man das (eigentlich) immer macht, wenn man kein RAII hat.
Edit: Warte mal, es ging nur darum, eine variable Pufferlänge zu haben? Hm. Ok. Ich würde trotzdem zwei verschiedene Funktionen bevorzugen, bei denen die eine halt einfach den benötigten Platz ausrechnet.
-
Unfug, die Verwaltungsdaten für den Speicherblock per new übersteigen wohl in 99% der Fälle den Speicher dann man überhaupt haben will.
Einfach 12 Bytes statisch allozieren und jedes 32bit Int lässt sich mitsamt Vorzeichen und Null-Terminator im Zehnersystem als String abspeichern.
-
Ethon__ schrieb:
Einfach 12 Bytes statisch allozieren und jedes 32bit Int lässt sich mitsamt Vorzeichen und Null-Terminator im Zehnersystem als String abspeichern.
-
Wie würdest denn du es machen? Ich wette dass ich für die Antwort gleich 2 Daumen-runter Smileys brauche.
-
Dein Vorschlag ist mit Abstand der schlechteste, da 1) Seiteneffekte und 2) nicht threadsafe. Ich würde es wie cooky machen.
-
Statische Allokation im Gegensatz zur Dynamisch Allokation. Hat garnichts mit dem static-Keyword zu tun, an das du gerade denkst.
char statisch[12] char* dynamisch = new char[12];
-
Zeig mir doch mal, wie du die Funktion nun schreiben würdest.
-
Eigentlich genauso wie Cookie, nur ohne weiter über Funktionen nachzudenken, die zählen und einen dynamischen String anlegen.
Aber ich hab Cookies Lösung mal so angepasst wie ich es am Angenehmsten fände:
#include <iostream> template<int IntSize> struct number_string_buffer { }; template<> struct number_string_buffer<1> { char value[5]; }; template<> struct number_string_buffer<2> { char value[7]; }; template<> struct number_string_buffer<4> { char value[12]; }; template<> struct number_string_buffer<8> { char value[22]; }; template<typename IntT> number_string_buffer<sizeof(IntT)> to_digits(IntT value) { number_string_buffer<sizeof(IntT)> result; char* put = result.value, *begin = result.value; do { *put++ = '0' + value % 10; value /= 10; } while (value != 0); *put = '\0'; while(put > begin) // std::reverse() oO { char c = *begin; *begin++ = *(--put); *put = c; } return result; } int main() { std::cout << to_digits(char(123)).value << '\n' << to_digits(short(12345)).value << '\n' << to_digits(int(1234567890)).value << '\n' << to_digits(123456789012345ll).value << '\n'; }
-
Naja, wenn man schon davon ausgeht, dass Bytes immer 8 Bit breit sind, dann kann man auch die benötigte Bufferlänge direkt ausrechnen:
template<int IntSize> struct number_string_buffer { // ln(10) / ln(2) ~ 2.41 char value[IntSize * 241 / 100 + 3]; };
Und wenn wir schon so weit sind, dann kann man sich auch die Mühe machen, die Umdreherei unnötig zu machen:
#include <iostream> template<typename T> class number_string_buffer { public: number_string_buffer(T x) { value_ = buffer_.data + bufsize - 1; *value_ = '\0'; // Wenn man signed-Datentypen auch erlaubt, muss ggf. ein Vorzeichen // behandelt werden. bool vz; if(x < 0) { vz = true; x = -x; } else { vz = false; } do { *--value_ = '0' + x % 10; x /= 10; } while(x != 0); if(vz) { *--value_ = '-'; } } number_string_buffer(number_string_buffer const &other) : buffer_(other.buffer_), value_(buffer_.data + (other.value_ - other.buffer_.data)) { } char const *value() const { return value_; } private: // Wenn wir schon davon ausgehen, dass immer 1 Byte = 8 Bit: static int const bufsize = sizeof(T) * 241 / 100 + 3; struct { char data[bufsize]; } buffer_; char *value_; }; template<typename T> std::ostream &operator<<(std::ostream &out, number_string_buffer<T> const &buf) { return out << buf.value(); } template<typename T> number_string_buffer<T> to_digits(T x) { return number_string_buffer<T>(x); } int main() { std::cout << to_digits(char(123)) << '\n' << to_digits(short(12345)) << '\n' << to_digits(int(1234567890)) << '\n' << to_digits(123456789012345ll) << '\n' ; }
Jetzt sollte man natürlich eigentlich noch prüfen, ob T ein integraler Basistyp ist, aber das macht ohne Standardbibliothek nun wirklich keinen Spaß mehr.
-
seldon schrieb:
Naja, wenn man schon davon ausgeht, dass Bytes immer 8 Bit breit sind, dann kann man auch die benötigte Bufferlänge direkt ausrechnen:
So etwas wollte ich auch gerade bauen, aber ich muss leider feststellen: 2 * 2.41 = 4.82 < 5. Habe ich mich irgendwie verrechnet?
Edit: Oups + 1 vergessen?
-
Da kommt die +3 her. sizeof(T) * 241 / 100 ist höchstens 1 unter der benötigten Ziffernzahl, dann +1, um immer genug zu haben, +1 für das Vorzeichen und +1 für den Sentinel. Bleibt sizeof(T) * 241 / 100 + 3.
-
Jo, das habe ich dann auch gemerkt. Wobei ich ln(10) / ln(2) immer noch nich so ganz nachvollziehen kann. Zumal das bei mir ~3.32 ergibt.
-
Dann sollte man es schlicht mit numeric_limits versuchen bzw es einfach nachprogrammieren. Da gibts ja den digits-Member.
-
Ah. Ja, der Kommentar ist falsch. Gemeint ist 8 / (ln(10) / ln(2)).
ln(10) / ln(2) ist der Logarithmus von 10 zur Basis 2. Eine Zahl, die in Radix 10 mit n Ziffern darstellbar ist, ist in Basis 2 mit ungefähr ln(10) / ln(2) * n Ziffern darstellbar, das ist die Idee.