einzelne Ziffern einer Zahl auslesen
-
Mit Rekursion ginge das hübsch:
void print_vertically(unsigned x) { if(x >= 10) { print_vertically(x / 10); } std::cout << x % 10 << '\n'; }
Die Einbindung des Arrays ist Übungsaufgabe.
-
nochmal ne Frage
wie finde ich raus wie groß ich das Array machen muss in dass ich die Zahl reinschreibe. Dazu benötige ich ja die Anzahl der Deziamalstellen der Zahl.
Im Netz habe ich jetzt etwas mit dem Log gefunden. Dazu benötige ich aber die math.h und ich will das Ganze ohne Stl machen.
Dann dachte ich mir ich zähle einfach durch:
int count = 0; while(zahl){ zahl= zahl/10; count++; }
und geb den Zählwert als Länge an das Array.
-> Fehler, der Wert muss konstant seinhabt ihr hierfür auch nochn Tipp für mich?
-
Ich hab ein paar Methoden ausprobiert. Ich habe keinen effizienten Algorithmus gefunden daher würde es denke ich schneller sein das ganze als ein string zu betrachten.
{ int zahl = 12345; int zahlLänge = GetZahlLänge(zahl); int[] ziffern = new int[zahlLänge]; for(int i = 0;i < zahlLänge;i++) { ziffern[i] = zahl % 10; zahl /= 10; } for (int i = zahlLänge-1; i >= 0; i--) { MessageBox.Show(string.Format("Ziffern: {0}",ziffern[i])); } } private int GetZahlLänge(int zahl) { int länge = 0; int teiler = 1; while (zahl / teiler >= 1) { länge++; teiler = teiler * 10; } return länge; } }
-
Patrickssj6 schrieb:
Ich hab ein paar Methoden ausprobiert. Ich habe keinen effizienten Algorithmus gefunden daher würde es denke ich schneller sein das ganze als ein string zu betrachten.
{ int zahl = 12345; int zahlLänge = GetZahlLänge(zahl); int[] ziffern = new int[zahlLänge]; for(int i = 0;i < zahlLänge;i++) { ziffern[i] = zahl % 10; zahl /= 10; } for (int i = zahlLänge-1; i >= 0; i--) { MessageBox.Show(string.Format("Ziffern: {0}",ziffern[i])); } } private int GetZahlLänge(int zahl) { int länge = 0; int teiler = 1; while (zahl / teiler >= 1) { länge++; teiler = teiler * 10; } return länge; } }
will keine STL benutzen und ne eigene Stringklasse möchte ich auch nicht schreiben
dass muss irgendwie anderst gehen.
-
Du kannst natürlich auch von vorne anfangen, dazu musst du wissen, wieviele Stellen deine Zahl hat (bekommt man mit
log10
raus). Alles weitere wie oben, musst aber ein bisschen mehr rechnen.
-
für log benötige ich doch auch die math.h oder??
-
Otz110 schrieb:
dass muss irgendwie anderst gehen.
klar geht das auch anders - etwa so:
#include <iostream> #include <cassert> template< typename T, typename Out > Out to_digits( T zahl, Out out ) { assert( zahl >= 0 ); char ziffer = '0' + zahl%10; // hier wird die Ziffer der letzten(!) Stelle bestimmt if( (zahl /= 10) != 0 ) out = to_digits( zahl, out ); // daher zuerst die Ziffern vor(!) der letzten Stelle bestimmen *out++ = ziffer; // und erst danach die letzte Ziffer wegschreiben return out; } int main() { using namespace std; char ziffern[200]; // wir wissen ja nicht wie gross die Zahl wird !? for( int x; cout << "> ", cin >> x; ) { *to_digits( x, ziffern ) = char(0); // String-Ende setzen cout << "Ziffern: " << ziffern << endl; // zur Kontrolle die Ziffernfolge ausgeben } return 0; }
-
Genau so hätte ich es dann auch getan aber der code ist einfach so häßlich...alleine das array mit unbestimmter Größe.
-
Patrickssj6 schrieb:
Genau so hätte ich es dann auch getan aber der code ist einfach so häßlich...alleine das array mit unbestimmter Größe.
stimmt - aber hier ist ja einer der es gerne kompliziert, aufwendig und fehlerträchtig haben möchte:
Otz110 schrieb:
will keine STL benutzen und ne eigene Stringklasse möchte ich auch nicht schreiben
-
Hübsch wär es mit std::stringstream.
Wenn man allerdings darauf besteht, C mit anderen Headern zu schreiben, geht das auch mit variabler Bufferlänge - man muss halt nur mitzählen. Beispielsweise:
#include <iostream> char *my_itoa_aux(unsigned x, unsigned &pos, unsigned depth) { char *buffer; if(x >= 10) { buffer = my_itoa_aux(x / 10, pos, depth + 1); } else { buffer = new char[depth + 1]; buffer[depth] = '\0'; } buffer[pos] = '0' + x % 10; ++pos; return buffer; } char *my_itoa(unsigned x) { unsigned pos = 0; return my_itoa_aux(x, pos, 1); } int main() { char *p = my_itoa(1234); std::cout << p << std::endl; delete[] p; }
-
seldon schrieb:
Mit Rekursion ginge das hübsch
Das ist immer noch nicht schön. -.-
Und überhaupt, was ist los mit dir, mit new allozierten Speicher aus einer Funktion zurückgeben?
-
In Produktionscode würde ich solchen Unfug natürlich nie einsetzen - für so was gibt's die Standardbibliothek. Unter den gegebenen Beschränkungen sehe ich aber nichts bedeutend besseres. Das Problem ist ja, dass ich erst in der innersten Rekursionsebene weiß, wie viel Speicher ich brauche - vorher allozieren ist also nicht drin.
Ich hätte jetzt noch einen RAII-Wrapper um den Zeiger herumschreiben können, und wenn ich etwas derartiges einsetzen hätte wollen, hätte ich es auch getan, aber hier, für solchen Kram? Lassen wir die Kirche im Dorf, in der Stadt können wir sie nicht gebrauchen.
Was Heap-Speicher aus einer Funktion angeht: Das macht (fast) jede Factory so. Wie sollte sie es auch anders machen? Man kann im Einzelfall darüber nachdenken, gleich Smart-Pointer zurückzugeben, aber immer ist das auch nicht praktikabel. Außerdem: Wenn man Heap-Objekte in Containern ablegt, überleben sie häufig auch die Funktion, in der sie angefordert wurden. Es ist eines der kennzeichnenden Merkmale von Heap-Objekten, dass sie den Stapelrahmen, in dem sie angelegt werden, überdauern.
Was dagegen (meistens) wenig Sinn macht, ist, Heap-Objekte in der selben Funktion anzulegen, in der man sie wieder löschen will - da sollte man besser den Stack bemühen. Und wenn man mit Arrays arbeitet, deren Länge man zur Compilezeit nicht kennt, benutzt man besser std::vector als nacktes new[] und delete[].
-
seldon schrieb:
Unter den gegebenen Beschränkungen sehe ich aber nichts bedeutend besseres.
Was waren denn die Bedingungen? Kein std::string, keine Container, keine STL, ..?
Trotzdem, warum nicht gleich ein typisches C Interface?char* my_itoa(unsigned n, char *buf) { char *p = buf, *q = buf; do { *p++ = '0' + n % 10; n /= 10; } while (n != 0); *p = '\0'; while (p > q) // std::reverse() oO { char c = *q; *q++ = *(--p); *p = c; } return buf; }
-
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];