Umwandlung von Int in String



  • Wenn man sich entschließt, aus welchen Gründen auch immer, nahe liegt da immer der Datenaustausch mit anderen Programmen auf einer low-Level Basis, auch mit Excel kann man ja sowas ganz leicht importieren, Struct mit gemischten Datentypen in .txt Dateien verfügbar zu machen, ergibt sich das Problem der Umwandlung von struct/double/int etc. in string und umgekehrt das wieder herauszulesen.

    Es braucht dann eine Schnittstelle, die die struct Daten in einen Textstring schreibt, und eine zweite, die den Textstring zerlegt und wieder als struct Datentypen verfügbar macht.

    Die Schnittstelle benötigt ihrerseits Subroutinen, die die einzelnen Datentypen wie gewünscht umwandeln. Zum Beispiel eine Integer/Long Zahl in einen Zeichenstring definierter Länge. Um eine solche handelt es sich hier.

    Die sehr praktische c-Funktion sprintf(), welche Daten jeder Art in einen String konvertiert, hat den großen Nachteil, daß die %12.2f etc. absoluten Feldbegrenzer nicht durch Variablen ersetzt werden können. Entschließt man sich, die Double-Stringfelder auf 14 Stellen zu erweitern, muß man alle sprintf() Anweisungen händisch ändern. Das ist für die Stabilität eines C/C++ Programms bedenklich.

    Besser wäre es, man könnte mit bestimmten Konstanten die Textfeldlänge bestimmen, dann kann man aber nicht sprintf() benutzen, so praktisch das auch sein mag.

    Andere verfügbare Funktionen, die ich gefunden habe:

    A standard-compliant alternative for some cases may be sprintf:
    sprintf(str,"%d",value) converts to decimal base.
    sprintf(str,"%x",value) converts to hexadecimal base.
    sprintf(str,"%o",value) converts to octal base.

    gehören nicht zum Standard-Sprachumfang und sind mir etwas verdächtig wg. Seiteneffekten insbesondere wegen dem Parameter 3, base.

    Ich hab jetzt mal ein bißchen rumprogrammiert, um einen Integer in einen String zu konvertieren, und zwar mit vorgegebener Länge des Feldes sowie rechtsbündiger Formatierung. Mit den c++ string hat man einige Probleme mit bestimmten Funktionen, die Bibliotheksfunktionen von AnsiC sind in dieser Richtung auch nicht so ganz unproblematisch, daher zu Fuß programmieren, low level. nicht string sondern char[]

    Sieht zugegebenermaßen noch nicht sehr elegant aus, funktioniert aber.

    Vielleicht hat jemand Interesse, den Code noch zu verbessern und Vorschläge zu machen wie? Die switch-Anweisung z.b. könnte man wahrscheinlich recht einfach mit Bezug auf Ascii-Code verkürzen. Ich hab aber jetzt erstmal nur getestet, ob es überhaupt läuft. Es läuft. Das nächste wäre dann, eine Double to String zu programmieren.

    Hier ist der Code:

    bool my_long_to_string(long zahl,int len,char *result)
    {
    	int const max_stellen=10; // 10 Stellen=bis 1 Milliarde+
    	long divisor=1;
    	for (int i=1;i<max_stellen;i++) divisor*=10;
    	if (zahl>=10*divisor||zahl<=-10*divisor)return false; // Zahl zu groß
    	bool minus=false;
    	long dividend=zahl;
    	if (zahl<0){minus=true;dividend=-1*zahl;} 
    	// Minus Flag setzen Zahl bleibt positiv
        long ergebnis=0; // Laufvariable für die einzelnen Divisionen
        char stringbuf[255]=""; // der Buffer für die Zahlenwerte als char
        int i;
    	int index=0; // soll nur vorrücken bei >=1 und <=9, nicht bei 0
    	for (i=0;i<max_stellen;i++)
    	{
    		if(dividend>10) ergebnis=dividend/divisor;
    		else ergebnis=dividend; // das wäre dann der Modulo-Rest
    
    		switch (ergebnis) 
    			// unelegant, könnte man mit Ascii-Werten verkürzen
    		{
    		case 0:break;  // Leading Blanks oder 0 ausschalten
    		case 1:stringbuf[index]='1';index++;break;
    		case 2:stringbuf[index]='2';index++;break;
    		case 3:stringbuf[index]='3';index++;break;
    		case 4:stringbuf[index]='4';index++;break;
    		case 5:stringbuf[index]='5';index++;break;
    		case 6:stringbuf[index]='6';index++;break;
    		case 7:stringbuf[index]='7';index++;break;
    		case 8:stringbuf[index]='8';index++;break;
    		case 9:stringbuf[index]='9';index++;break;
    
    		}
    		dividend-=divisor*ergebnis; // wenn ergebnis==0 passiert nix
                                   // dann ist die zahl noch zu klein 
    		divisor/=10; // aber der divisor muß eine Zehnerpotenz runter
    	} // for i
    	int lenpruef=strlen(stringbuf); // die tatsächliche Länge
    	if (!minus&&len<lenpruef) return false; 
    	// Exit weil die angeforderte Länge zu klein ist 
    	else if (minus&&len<=lenpruef) return false; 
    	// für das Minus-zeichen wird noch 1 Feld mehr benötigt 
    
    	for (i=0;i<len;i++)result[i]=BLANK; // Pointerfeld zurücksetzen
    
        int diff=len-lenpruef; // Zahlenstring soll rechtsbündig erfolgen
    	for (i=diff;i<len;i++) result[i]=stringbuf[i-diff];
    	if (minus) result[diff-1]='-'; // evtl. Minuszeichen davor
    	result[len]=EOS; // Stringendemarkierung falls nicht vorhanden
    	return true;
    }
    

    Die Funktion erhält die nicht änderbaren Werte (die sie auch nicht ändern soll) als call by value, und der String, der manipuliert werden soll, kommt als Call by Reference. Das empfiehlt sich auch bei höher verschachtelten Datentypen wie struct oder array of struct. Rückgabewert by value wäre ja dann eh der Zeiger.

    Wie gesagt nicht sehr elegant bisher, aber es läuft. Warum man das selbst programmieren soll, das hängt damit zusammen, was man als Brot und Butter-Funktion im Programm ständig benötigt.

    EOL (end of Line) BLANK (Leerzeichen) etc. sind per #define festgelegt.

    Pascal



  • Also komm, wenn schon dann richtig:

    bool my_long_to_string2(long zahl, int len, char *result)
    {
    	int pos = 0;
    	if(zahl < 0){
    		result[pos++]='-';
    		zahl*=-1;
    	}
    
    	pos++;
    	for(int i=zahl; i>9; i/=10)
    		pos++;
    
    	result[pos--] = '\0';
    
    	if(pos + 1 > len)
    		return false;
    
    	do{
    		result[pos--] = '0' + zahl%10;
    		zahl/=10;
    	}while(zahl != 0);
    
    	return true;
    }
    

    Aber du weißt schon dass du DREI Bibliotheken zur Verfügung hast die dir das abnehmen können ?! 🙄



  • Der Code war so dahingeworfen. So 5-Minuten-Code zur gedanklichen Entwicklung. Er enthält noch Fehler.

    Ich hab ihn mittlerweile zwar korrigiert, und auch noch eine Funktion für double hinzugeschrieben, aber du hast recht:

    Was in der Bibliothek verfügbar ist, soll man nicht nachprogrammieren.

    Dazu kommt, daß ich von c++ doch wieder auf c# zurückgewechselt bin.

    Da ist mit convert. eigentlich alles schon vorgeregelt. Bzw. auf dem Rückweg die Eigenschaften der Klassen mit .ToString().

    Die convert-Funktion läßt sich anders als die spritnf() Funktion aus C so regeln, daß man Konstanten für die Länge der Felder einsetzen kann, mit PadLeft oder PadRight, die letztendlich erreicht werden soll.

    Danke für den Hinweis.

    Pascal



  • Natürlich geht es auch in C mit variablen Längenangaben:

    int length = 12;
    int precision = 2;
    double value = 123456.789
    printf("%*.*f", length, precision, value);
    

    Du solltest dich mal intensiver mit den Standard-Libraries auseinanderzusetzen...

    Und auch in C# (bzw. NET) nimmt man nicht PadRight oder PadLeft zur Formatierung von Zahlendarstellungen, sondern Standardmäßige Zahlenformatzeichenfolgen.

    Edit: sehe gerade, daß ja auch in deinem Thread c# im dritten Anlauf diese Lösung schon gepostet wurde.


Log in to reply