Ausgabe in C
-
Okay das klingt verständlich. Und auch für mich lösbar.
Aber eine weitere Frage habe ich dazu noch, wie kann ich es machen, dass wenn ich die Binärzahl ausgeb nach jeweils 4 Stellen ein Freizeichen ist?
-
Also wenn ich das jetzt richtig verstanden habe, was du sagtest, dann sieht mein Programm so aus:
#include<stdio.h> int main(void) { int speicher[32], dezimalzahl ,i; printf("Bitte geben sie eine Dezimalzahl ein:"); printf("\n\n"); scanf("%d",&dezimalzahl); for ( i=0; dezimalzahl > 0; i++) { speicher[i]=dezimalzahl%2; dezimalzahl=dezimalzahl/2; } for (; i > 0; i--) { printf("%d",speicher[i-1]); } return 0; }
-
Toastaa schrieb:
Also wenn ich das jetzt richtig verstanden habe, was du sagtest, dann sieht mein Programm so aus:
Und wie sieht dein Programm aus, wenn du ihn nicht richtig verstanden hast? :xmas2:
-
Dann würde es genauso aussehen, nur das ich es anders gelöst hätte als er es sagte.
-
Toastaa schrieb:
Aber eine weitere Frage habe ich dazu noch, wie kann ich es machen, dass wenn ich die Binärzahl ausgeb nach jeweils 4 Stellen ein Freizeichen ist?
Entweder mit einer Schleife und putchar() (und if (i % 4 == 0)), oder mit solchen Konstrukten:
void print_bin(const char *s) { while (*s && printf("%.4s ", s) == 5) s += 4; }
Da gibt es jetzt unzählige Formatierungsmöglichkeiten.
Und nein, du hast mich nicht richtig verstanden.
-
Ja das habe ich auch grade gemerkt als ich mir nochmal einen bericht zur Rekursion durchgelesen habe :).
Aber da werde ich mich morgen nochmal genauer informieren.
Aber ich danke dennoch schonmal für die Hilfe.
-
Das mit der Rekursion war nicht meine Idee. (Und offen gesagt finde ich die Idee auch doof.)
void print_bin(const char *s) { while (*s && printf("%.4s ", s) == 5) s += 4; } char *make_bin(unsigned num, char *buf, unsigned buf_size) { char *p = buf + buf_size - 1; if (buf_size == 0) return buf; // Oder gleich assert(), oder einfach ignorieren, buf_size = 0 macht keinen Sinn. *p = '\0'; while (p-- != buf) { *p = num % 2 + '0'; num /= 2; //if (num == 0) // Falls du nicht mit Nullen füllen möchtest. // return p; } return p + 1; } int main() { unsigned number = 34754643; char buffer[sizeof(unsigned) * CHAR_BIT + 1]; print_bin(make_bin(number, buffer, sizeof(buffer))); getchar(); }
-
cooky451 schrieb:
Das mit der Rekursion war nicht meine Idee. (Und offen gesagt finde ich die Idee auch doof.)
Vergleich mal dein Code mit meinem und sage mir nochmal ins Gesicht, dass das ne doofe Idee war.
#include <stdio.h> void toBinary(int n) { if (n != 0) { toBinary(n/2); printf("%d", n%2); } } int main() { toBinary(9); printf("\n"); return 0; }
Liebe Grüße
Steffo
-
Na ja, ich schreibe ja auch in einen String. Wenn du einfach nur die Ausgabe haben möchtest, dann doch bitte gleich so:
void printBinary(int n, unsigned j) { if (j != 0) { printBinary(n/2, j - 1); if (j % 4) printf("%d", n%2); else printf("%d ", n%2); } } int main() { printBinary(34754643, sizeof(int) * CHAR_BIT); return 0; }
-
Auf solche Details kommt es auch nicht mehr drauf an und selbst wenn du in einem String schreiben willst, bist du mit Rekursion besser dran.
L. G.
Steffo
-
Doch es macht einen Unterschied, du bekommst da kleine Probleme mit der Nullterminierung. :xmas1:
-
Wo soll da das Problem sein?
/*...*/ if (j == sizeof(unsigned) * CHAR_BIT) { buf[sizeof(unsigned) * CHAR_BIT] = '\0'; /* Oder so ähnlich... */ } /*...*/
-
Da siehst du die Puffergröße jetzt aber als gegeben an, das zählt nicht. Wenn es so einfach ist, schreibe doch eine äquvalente Funktion, die 7 Zeilen wirst du wohl überleben.
-
#include <stdio.h> #include <stdlib.h> static void writeBinary(int n, int *c) { if (n != 0) { ungetc(n % 2 + '0', stdin); writeBinary(n / 2, c); (*c)++; } } void toBinary(int n, char **s) { int c = 0; ungetc(' ', stdin); writeBinary(n, &c); *s = (char*) malloc(sizeof(char) * c + 1); scanf("%s", *s); } int main() { char *s = NULL; toBinary(8, &s); printf("%s\n",s); free(s); return 0; }
-
Was haltet Ihr denn von dieser Herangehensweise?
#include <stdio.h> #include <stdlib.h> #include <assert.h> void print_binary(unsigned int number) { unsigned int flag = 1 << ((sizeof(unsigned int) * CHAR_BIT) - 1); /* directly print 0 if number is 0 */ if (!number) { putchar(number + '0'); return; } /* cut off leading zeros */ while (!(number & flag)) flag >>= 1; /* print the result */ while (flag) { putchar(number & flag ? '1' : '0'); flag >>= 1; } } typedef struct binary_string { /* guaranteed to be big enough to hold all bits of an unsigned int plus the terminating null character */ char buffer[(sizeof(unsigned int) * CHAR_BIT) + 1]; } binstr_t; void to_binary(unsigned int number, binstr_t * output) { unsigned int n = (sizeof(unsigned int) * CHAR_BIT) - 1; char * p = NULL; assert(output != NULL); p = output->buffer; /* almost the same like above */ if (!number) { output->buffer[0] = '0'; output->buffer[1] = '\0'; return; } while (!(number & (1 << n))) --n; do { *p++ = (number & (1 << n)) ? '1' : '0'; } while(n--); *p = '\0'; } int main(void) { unsigned int n = 0; binstr_t str; for (; n < 16; ++n) { printf("print_binary: "); print_binary(n); putchar('\n'); to_binary(n, &str); printf("to binary: %s\n", str.buffer); } return 0; }
-
Steffo schrieb:
#include <stdio.h> #include <stdlib.h> static void writeBinary(int n, int *c) { if (n != 0) { ungetc(n % 2 + '0', stdin); writeBinary(n / 2, c); (*c)++; } } void toBinary(int n, char **s) { int c = 0; ungetc(' ', stdin); writeBinary(n, &c); *s = (char*) malloc(sizeof(char) * c + 1); scanf("%s", *s); }
Diese Art des Missbrauchs von ungetc ist durch den Standard nicht gedeckt:
ISO/IEC 9899:1999 7.19.7.11 (3) schrieb:
One character of pushback is guaranteed. If the ungetc function is called too many times on the same stream without an intervening read or file positioning operation on that stream, the operation may fail.
Ich sehe auch nicht, was man hier groß mit Rekursion wollen sollte. Geht auch, aber die Gruppierung wird auf die Weise ziemlich umständlich, und Performancevorteile darf man sich in diesem Fall von einem rekursiven Vorgehen sicher nicht versprechen.
Eine einfache Möglichkeit, die ganze Problematik mit der Suche nach der Länge des Ergebnisstrings zu umgehen, ist, von hinten zu schreiben und einen Zeiger mitten in den Buffer als String zu benutzen. Ich stelle mir das etwa so vor:
#include <limits.h> #include <stddef.h> #include <stdio.h> #include <string.h> char *binary_representation(char *buffer, size_t buflen, unsigned x) { char *p = buffer + buflen - 1; size_t used = 0; int group = 0; do { ++used; if(used >= buflen) return NULL; --p; if(group == 4) { group = 0; *p = ' '; } else { ++group; *p = (x & 1) + '0'; x >>= 1; } } while(x != 0); buffer[buflen - 1] = '\0'; return p; /* * Wenn man die Daten unbedingt am Anfang des Eingabebuffers haben will, * kann man hier statt der letzten zwei Zeilen * * memmove(buffer, p, used); * buffer[used] = '\0'; * return buffer; * * schreiben. Frisst natürlich etwas mehr Laufzeit, aber für Linksjustierung * braucht man halt ein Zwischenergebnis. */ } int main(void) { char buffer[100]; char *bin; bin = binary_representation(buffer, sizeof(buffer), 1234); if(bin) { puts(bin); } return 0; }
-
seldon schrieb:
Diese Art des Missbrauchs von ungetc ist durch den Standard nicht gedeckt:
ISO/IEC 9899:1999 7.19.7.11 (3) schrieb:
One character of pushback is guaranteed. If the ungetc function is called too many times on the same stream without an intervening read or file positioning operation on that stream, the operation may fail.
Dann nimmt man halt einen Stack oder so etwas ähnliches. Jedenfalls ist Rekursion hier m. A. n. eleganter. Und das Performance-Argument zählt nicht. Weshalb?
Nehmen wir mal an, man will 1000 000 000 in binär umwandeln. Wieviel rekursive Aufrufe sind das? Das sind aufgerundet genau log2(1000 000 000) = 30 Aurufe --> Sich hier Performancegedanken zu machen, ist fehl am Platz.Schau dir mal meine Schnittstelle an (Parameter: beliebige Zahl, mit NULL initialisierter Pointer) und deine Schnittstelle (Parameter: buffer, mit der fixen Größe 100, Größe des Buffers und beliebige Zahl). Bei meiner Methode hat der Endanwender weniger Arbeit und muss sich weniger Gedanken machen.
L. G.
Steffo
-
Ich sehe irgendwie dein Argument nicht. Es geht wunderbar als Schleife. Rekursion ist hier technisch gar nicht nötig, es ist bloß eine andere Art, die Schleife zu schreiben.
-
SeppJ schrieb:
Ich sehe irgendwie dein Argument nicht. Es geht wunderbar als Schleife. Rekursion ist hier technisch gar nicht nötig, es ist bloß eine andere Art, die Schleife zu schreiben.
Alles geht als Schleife. Selbst nicht endrekursive Aufrufe kann man in Schleifen mit Stack umwandeln. Die Frage ist hier, was eleganter ist und dennoch eine zufriedenstellende Performance hergibt.
-
Ob Performance von Interesse ist, hängt stark davon ab, wie oft solche Umwandlungen geschehen sollen. So oder so ist aber die Vorstellung, dass 30 Funktionsaufrufe für die Umwandlung einer Ganzzahl in Binärnotation eine vernünftige Implementation wären, ziemlich albern.
Was die Schnittstelle angeht, die hat mit den Implementationsdetails hier ziemlich wenig zu tun. Den Code, mit dem man die gleiche Schnittstelle nachbilden kann, habe ich ja schon in den Kommentar geschrieben - auch mit memmove hinten drangehängt dürfte das allemal schneller sein als die Rekursion, und wenn du zusätzlich zur Rekursion noch einen Stack benutzen willst, mit ziemlicher Sicherheit auch übersichtlicher. Die Gruppierung in Nibbles hattest du übrigens auch nicht erschlagen, und das ist rekursiv auch nicht wirklich elegant zu machen. Oder?