Forum: PC-Programmierung Integer zu String, aber (Speicher-)effizient.


von Christian H. (christian_h52)


Lesenswert?

Für ein Programm muss ich einen beliebigen Integerwert in ein C-Array 
umwandeln. Im Moment mache ich das so:
1
char len[sizeof(int)*8+1];
2
(void) sprintf(len,"%d",i);

Doch ich soll keine "willkürlichen" Grenzen verwenden, sodass ich die 
Größe des Arrays an den Integerwert anpassen muss - wie könnte ich das 
angehen? Um die Anzahl der Stellen zu berechnen, bräuchte ich eine 
Schleife, aber dieser Code befindet sich selbst in einer Schleife, daher 
würde ich wenn es geht auf eine Schleife verzichten.

von Sam .. (sam1994)


Lesenswert?

sprintf hängt der ASCII Zahl eine '\0' an, welche das Ende des Strings 
angibt. Was ist dein Problem?

von Christian H. (christian_h52)


Lesenswert?

Dass ich (sizeof(int)*8+1)-Char Werte reserviere obwohl unter Umständen 
nur viel weniger gebraucht werden. Die Zahl, die umgewandelt wird, ist 
wohl meist doch kleiner als 10.

von Stefan W. (stefan_w37)


Lesenswert?

Christian H. schrieb:
>
1
char len[sizeof(int)*8+1];
2
> (void) sprintf(len,"%d",i);

warum sizeof(int)*8+1? selbst wenn du die berechnung sehr einfach halten 
willst wäre da eine 3 statt einer 8 angebrachter (und +2 statt +1 -> 
vorzeichen).

Dort dynamisch speicher reservieren (wieviel du brauchst sagt dir der 
10er-logarithmus, aber voelliger overkill da) ist imo uebertrieben ...

von Sam .. (sam1994)


Lesenswert?

1
char* c = alloc(9);
2
sprintf(c,"%d",i);
3
c = realloc(c, strlen(c)+1);
ungetestet

von Andi (Gast)


Lesenswert?

Also wenn ich dich richtig verstehe willst du die Anzahl an Stellen 
einer Zahl bestimmen....

Also bei 458 -> 3
oder 12 -> 2, 145789 -> 6

Dann geht das ganz einfach mit Hilfe des Logarithmus

int(log(x)) + 1



lg

von Sam .. (sam1994)


Lesenswert?

Andi schrieb:
> Dann geht das ganz einfach mit Hilfe des Logarithmus

Einfach ja, effizient nein.

und oben müssen 12Bytes allociert werden (weiß nicht wie ich auf 9 kam).

von Volkmar D. (volkmar)


Lesenswert?

Andi schrieb:
> Dann geht das ganz einfach mit Hilfe des Logarithmus
>
> int(log(x)) + 1

ist nur sehr 'teuer', sprich kostet viel Rechenzeit.

von Jasch (Gast)


Lesenswert?

Christian H. schrieb:
> Für ein Programm muss ich einen beliebigen Integerwert in ein C-Array
> umwandeln. Im Moment mache ich das so:
>
>
1
char len[sizeof(int)*8+1];
2
> (void) sprintf(len,"%d",i);
>
> Doch ich soll keine "willkürlichen" Grenzen verwenden, sodass ich die
> Größe des Arrays an den Integerwert anpassen muss - wie könnte ich das

Musst Du das wirklich, die String-Darstellung eines int hat auf jeder 
Plattform eine definierte Maximallänge?

Das Forum heisst "PC-Programmierung", wenn ich das ernst nehme ist der 
Unterschied zwischen 3 Bytes, 10 Bytes oder 15 Bytes total irrelevant.

Es sei denn Du haettest Millionen davon, in dem Fall musst Du das 
vermutlich eh ganz anders machen - eigene Speicherverwaltung ganz anders 
als malloc() und Co. wäre angesagt, mit minimiertem Overhead und ohne 
den vom Standard erzwungenen "Verschnitt" durch Alignmentanforderungen.

> angehen? Um die Anzahl der Stellen zu berechnen, bräuchte ich eine
> Schleife, aber dieser Code befindet sich selbst in einer Schleife, daher
> würde ich wenn es geht auf eine Schleife verzichten.

Schleife, einige ifs, Logarithmus, alles zu viel Aufwand wenn Du nur ein 
paar irrelevante Bytes einsparen willst.

von Thomas W. (wagneth)


Lesenswert?

Ginge das abzählen so ?
1
#define BASE 10
2
3
uint?_t length = 0;
4
uint?_t vgl = 0;
5
6
while ( vgl < value) // 
7
{
8
  length ++;
9
  vgl *= BASE;
10
  vgl += BASE - 1;
11
}
12
13
/*
14
15
Die obige Schleife sollte doch das hier machen:
16
17
if (x>9) length++;
18
if (x>99) length++;
19
if (x>999) length++;
20
if (x>9999) length++;
21
if (x>99999) length++;
22
if (x>999999) length++;
23
if (x>9999999) length++;
24
...
25
*/

von Karl H. (kbuchegg)


Lesenswert?

Thomas W. schrieb:
> Ginge das abzählen so ?

Na ja.
Probiers aus.

(negative Zahlen brauchen eine Stelle mehr und an den Bereichsgrenzen 
musst du aufpassen)

Aber wie schon gesagt: Wozu?
Die paar Bytes, die in

char len[20];
(void) sprintf(len,"%d",i);

kurzzeitig für nichts überzählig reserviert werden, sind völlig 
irrelevant. Es lohnt den Aufwand nicht, sich da etwas anderes einfallen 
zu lassen, vor allen Dingen, wenn dieser Aufwand selber wieder eine 
Menge Resourcen kostet. Man treibt da den Teufel mit dem Belzebub aus. 
Den Unmengen von Integern wird man sinnvollerweise sowieso nicht in 
Textform speichern, sondern so wie sie sind .. als int oder long oder 
was man dann auch immer hat. Textrepräsentierungen braucht man 
normalerweise nur an I/O Schnittstellen und wenn man da kurzzeitig (in 
einer Funktion) mal 10 Bytes zuviel allokiert hat, dann ist das kein 
Thema um das man sich Sorgen machen muss. Wenn diese temporären 10 Bytes 
den Unterschied zwischen läuft und läuft nicht ausmachen, dann hat man 
an anderen Stellen schon viel größere Probleme.

von Thomas W. (wagneth)


Lesenswert?

@KH:
Ja die 0, Vorzeichen und überläufe funktionieren nicht.
Alles "dazwischen" geht.

Wie zählt man besser ab ?
(garnicht, ok)

von Karl H. (kbuchegg)


Lesenswert?

Thomas W. schrieb:
> @KH:
> Ja die 0, Vorzeichen und überläufe funktionieren nicht.
> Alles "dazwischen" geht.
>
> Wie zählt man besser ab ?

Ist doch alles schon angesprochen worden.
Entweder Logarithmus oder durch 10 dividieren bis man bei 0 ist und 
mitzählen.

von Udo S. (urschmitt)


Lesenswert?

Ist schon verrückt was der TO auf einem PC!? für Verrenkungen machen 
will um 5 oder 10 Bytes zu sparen.
Irgendwie habe ich das Gefüht das eigentliche Problem liegt anderswo.

von Christian H. (christian_h52)


Lesenswert?

Danke für die vielen Antworten. Also die Angabe lautet wie folgt:
1
Willkürliche Grenzen sind soweit als möglich zu vermeiden.
2
Ist es notwendig, Grenzen einzuführen, so ist die Überschreitung dieser Grenzen zu behandeln.
3
Alle diese Grenzen sind als symbolische Konstante (Makrodefinitionen!) zu vereinbaren.

Gehe ich hier zu weit? Würde es eine effizientere Approximation des 
Log10-geben - vl eine grobe Annäherung durch Taylor Polynom? Selbst wenn 
das Resultat ein wenig über dem des logs sein sollte, wäre das doch 
egal.

von Robert L. (lrlr)


Lesenswert?

da ich mit  Pascal arbeite, kann ich (mal wieder) nur den Kopf schütteln 
;-)

C und Strings sind schon was tolles ;-)


gib es in C wirklich keine "IntToString" (optimierte) Funktion die das 
FixFertig zurück liefert?

also wenn man sich schon über sowas "rudimentäres" jedes mal den kopf 
zerbrechen muss, und (vor allem) jeder Programmiere dass nach seinem gut 
dünken "löst"...

naja egal:


ich würde:
a) auf die Paar byte sch.. (vorallem wenn es um einen PC geht, und nicht 
um einen µC)

b) einmal (pro thread) Speicher GLOBAL reservieren (in der maximal 
möglichen länge (also 12 Byte)
dort hinein das sprintf(...)
das Ergebnis dann dynamisch reservieren

bzw. wenn man die 12 "vermeiden will" kann man sich beim EINMALIGEN 
globalen reservieren ja mehr mühe geben, und z.b. je nachdem ob der 
integer 16, 32 oder 64 bit hat, dort einmalig die maximale länger 
ermitteln

von Karl H. (kbuchegg)


Lesenswert?

Robert L. schrieb:

> gib es in C wirklich keine "IntToString" (optimierte) Funktion die das
> FixFertig zurück liefert?

natürlich gibt es das. Wird ja auch benutzt.
Aber ich muss als Aufrufer die Speicherfläche zur Verfügung stellen und 
da muss ich sie entsprechend dimensionieren.
In C gibt es keine dynamisch wachsende/schrumpfende Strings. Hat den 
Nachteil, dass man sich um solche Sachen selber kümmern muss. Hat den 
Vorteil, dass man keine versteckten dynamischen Allokierungen hat, die 
ihrerseits wieder zu Problemen führen können (Speicherfragmentierung / 
Out of Memory). Wenn ich dynamisch wachsende Strings brauche, muss ich 
mir die selber machen.

> also wenn man sich schon über sowas "rudimentäres" jedes mal den kopf
> zerbrechen muss, und (vor allem) jeder Programmiere dass nach seinem gut
> dünken "löst"...

Darüber zerbricht man sich auch nicht den Kopf, man wählt ...

> a) auf die Paar byte sch.. (vorallem wenn es um einen PC geht, und nicht
> um einen µC)

von Karl H. (kbuchegg)


Lesenswert?

Christian H. schrieb:
> Danke für die vielen Antworten. Also die Angabe lautet wie folgt:
>
>
1
Willkürliche Grenzen sind soweit als möglich zu vermeiden.
2
> Ist es notwendig, Grenzen einzuführen, so ist die Überschreitung dieser
3
> Grenzen zu behandeln.
4
> Alle diese Grenzen sind als symbolische Konstante (Makrodefinitionen!)
5
> zu vereinbaren.
>
> Gehe ich hier zu weit?

Kommt drauf an.
Ist dieses "zum String umwandeln" ein wesentlicher Bestandteil deiner 
Aufgabe oder ist das ein Nebenschauplatz, weil du eben irgendwo 
Rechenergebnisse ausgeben musst um zu zeigen, dass deine 
Hyper-Duper-Routenberechnung auch tatsächlich funktioniert.

Wie lautet denn die komplette Aufgabenstellung?

von Christian H. (christian_h52)


Lesenswert?

Das ist eben nur eine Nebenbedinung. Es werden Zeichen verarbeitet. 
Paralell wird mitgezählt und die Anzahl soll immer wieder ausgegeben 
werden. Diese ist in einem Integer und daher muss ich den in einen 
String umwandeln.

von Karl H. (kbuchegg)


Lesenswert?

Christian H. schrieb:
> Das ist eben nur eine Nebenbedinung. Es werden Zeichen verarbeitet.
> Paralell wird mitgezählt und die Anzahl soll immer wieder ausgegeben
> werden. Diese ist in einem Integer und daher muss ich den in einen
> String umwandeln.

Und warum musst du das dann intern in einen String umwandeln.
Wenn du einen Integer ausgeben musst, musst du doch nicht extra 
umwandeln

  printf( "%d", Anzahl );

und schon steht die Anzahl auf der Konsole.
(Oder ist da eine GUI involviert. Dann freilich müsste man vorher 
umwandeln, wenn man keine entsprechende Funktion hat. Aber auch dann 
würde ich diesen Teil nicht als eigentlichen Bestandteil der Aufgabe 
ansehen. Ist aber IMHO)

von Udo S. (urschmitt)


Lesenswert?

Christian H. schrieb:
> Das ist eben nur eine Nebenbedinung. Es werden Zeichen verarbeitet.
> Paralell wird mitgezählt und die Anzahl soll immer wieder ausgegeben
> werden. Diese ist in einem Integer und daher muss ich den in einen
> String umwandeln.

Ja und dann mach das in einer lokalen Variablen, die Größe ist der 
dekadische Logarithmus abgerundet + 2 (keine negative Anzahl) Das Ganze 
definierst du als Konstante, da rechnet es der Compiler einmal aus.
Das ist ja keine willkürliche sondern eine gerechtferigte Grenze.

von Rolf Magnus (Gast)


Lesenswert?

Wenn du die maximale Länge ermittelst, die der erzeugte String haben 
kann und das als fixe Größe nimmst, ist das doch keine willkürliche 
Grenze.
Wenn man z.B. festlegt, daß ein Dateiname maximal 8 Zeichen lang sein 
darf, gefolgt von einem Punkt und bis zu drei weiteren Zeichen, dann 
wäre das eine willkürliche Grenze.

von Christian H. (christian_h52)


Lesenswert?

Danke für eure Mühen! Ich habe es jetzt wie folgt gelöst:
1
int n;
2
3
n = fprintf(...);
4
5
// so kann ich den Integer in einen String umwandeln und bekomme die Anzahl der Stellen zurück!

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Also ich fürchte du hast die Aufgabe an der Stelle missverstanden:

> Willkürliche Grenzen sind soweit als möglich zu vermeiden.
Also nicht einfach 1000 als Grenze festlegen, weil man denkt passt 
schon, oder Beschränkungen einführen wo keine nötig sind.

> Ist es notwendig, Grenzen einzuführen,
> so ist die Überschreitung dieser Grenzen zu behandeln.
Zielt wohl auf Fehlerbehandlung/Pufferüberläufe ab.

> Alle diese Grenzen sind als symbolische Konstante
> (Makrodefinitionen!) zu vereinbaren.
Keine Magic Numbers.

Wenn maximal 20 Zeichen bei der Umwandlung rauskommen könnne: Ist doch 
schön, kurze Begründung warum, eine Macrokonstante anlegen und fertig...

von Rolf Magnus (Gast)


Lesenswert?

Christian H. schrieb:
> Danke für eure Mühen! Ich habe es jetzt wie folgt gelöst:
>
> int n;
>
>
>
> n = fprintf(...);
>
>
>
> // so kann ich den Integer in einen String umwandeln und bekomme die Anzahl der 
Stellen zurück!

Wie "fprintf()"? Gibst du es etwa irgendwo aus, nur um rauszubekommen, 
wie lang der String wird? Das ist sicher nicht die Idee der Aufgabe 
gewesen!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.