Normale Zahl in Binäre Zahl umwandeln.
-
Verehrter Herr CJosef: Falsche Schlussfolgerung!
Mach Dir den richtigen Kopf, aber nicht irgendeinen. Warum nicht 256 oder 64K? Eigentlich sollte eine Anfänger kein int benutzen, da es prozessorabhängig ist.
Wie der Link von CJosef sehr schön zeigt, steht immer "at least" dort. Wenn man also "plattformunabhängig" programmieren will, dann sollte nicht irgendeine Fantasiegrosse benutzt werden, um für die Ausgabe einer 0 oder einer 1 immer ein Byte zu "opfern".
Wenn wir also schon über die 128 einzelnen Bytes auf einem Mikrocontroller diskutieren, dann sollten wir vorsichtshalber immer limits.h bemühen, um die Längen der Entwicklungsplattform (die hoffentlich an das Zielsystem angepasst sind) zu verwenden.
Leider ist bei meiner letzten Stellungnahme ein Satz unvollständig.
Ich wollte eigentlich fragen, wozu die Funktion zwei Rückgabewerte hat, einmal das normale Funktionsergebnis und einmal den Zeiger als zweiten Parameter, der ja am Funktionsende zurückgegeben wird.
puts (nimmt man das denn immer noch?) erhält also den temporären Funktionszeiger sowie (hoffentlich) denselben Zeiger im Argument zurück.Einerseits soll also die Funktion einen Zeiger auf einen vorbereiteten Puffer nehmen, um andererseits diesen Zeiger wieder zurückzugeben.
Eine Alternative wäre
#include <stdio.h> void int2binstr ( int number, char* binstr ) { // TODO ... } int main ( void ) { int num = 4711; char binstr [ 128 ] = { 0 }; int2binstr ( num, binstr ); puts (binstr); return 0; }
Also kein direkter Rückgabewert. Die Rückgabe erfolgt über die Parameterliste.
Wenn wir schon dabei sind, die blutigen Anfänger zu verwirren, dann machen wir es doch einmal richtig ordentlich und diskutieren das eingeklammerte (hoffentlich) einmal vollständig in aller Freundschaft aus.
#include <stdio.h> char* int2binstr ( int number, char* binstr ) { // TODO ... *binstr++='1'; /*nur zur Demo*/ *binstr++='1'; *binstr='\0'; return binstr; } int main ( void ) { int num = 4711; /*hat derzeit keine Wirkung*/ char binstr [ 128 ] = { 0 }; binstr[0]='a'; binstr[1]='b'; printf_s("%s\n",binstr); printf("%s : %s : %c%c\n",binstr,int2binstr(num,binstr),binstr[0],binstr[1]); return 0; }
16-18 Wir benutzen den schönen Puffer erst einmal für andere Zwecke.
6-8 Das soll Veränderungen durch die Funktion simulieren. Clever wie wir sind verlassen wir uns nicht darauf, dass der Puffer immer noch lauter Abschlusszeichen hat. Vielmehr setzen wir das in 8 vorsichtshalber.
19 Daprintf
an dieser Stellebinstr
als letzten Parameter mit dem Format %s im Gegensatz zu Zeile 18 nicht wirklich mag (d. h., es stürzt ab), geben wir die beiden Zeichen einzeln mit %c aus.binstr
und das Ergebnis unserer Funktion formatieren wir dagegen mit %s. Die böse Absicht wird gleich erklärt.Dann schauen wir uns das Ergebnis an
ab 11 : : ab Drücken Sie eine beliebige Taste . . .
Zeile 1 haben wir erwartet.
Zeile 2 erstaunt den Fachmann, der Laie wundert sich.Erklärungsversuch:
Der Funktionsaufruf in 19 arbeitet die Argumente von rechts nach links ab. Daher werden die beiden Zeichen
ab
schon einmal auf den Keller (stack) gelegt, bevor es weitergeht.Jetzt erfolgt der Funktionsaufruf. Dummerweise sind der Rückgabewert und das Argument nun unterschiedlich. Der Rückgabewert ist ein Zeiger, der auf das dritte Zeichen '\0' verweist. Hat unser Anfänger nicht bemerkt. Auch hat er keine Vorsorge getroffen und den Zeiger am Anfang gerettet, um ihn jetzt zurückzugeben.
binstr
ist ein Werparameter, so dass nur seine Kopie von diesen Manipulationen etwas mitbekommt. Er wird beim Aussprung aus der Funktion wieder restauriert und verweist auf den Anfang des Puffers. Daher ist in der Anzeige das erste Feld wie erwartet, das zweite Feld aber leer, das dritte Feld zeigt einen Wert, den es ab sofort nirgends mehr gibt.Wir können nun untereinander weiterstreiten, welche Lösung robuster ist. Wehe, der Anfänger macht einen solchen Fehler. Da sind unsere Diskussion über den Speicherbedarf und limits.h Ernüsse (ups, peanuts) dagegen.
-
Um mögliche Diskussionen zu vermeiden. Die Rückgabe über die Parameterliste bedeutet nicht, dass der dort befindliche Zeiger verändert werden kann, sondern nur sein Inhalt.
-
Bau das hier einfach um, ist zwar C++ aber vielleicht kannste es ja in C umbauen und den Shift Kram auch mit einbauen.
#include <iostream> #include <vector> using namespace std; int main() { int zahl,rest; vector<int> Dualzahl; cout << "Eingabe der Zahl: "; cin >> zahl; do { rest=zahl%2; Dualzahl.push_back(rest); zahl=zahl/2; } while (zahl>0); for(int i=Dualzahl.size()-1;i>=0;i--) { cout<<Dualzahl[i]; } return 0; }
-
Waldschrat schrieb:
#include <stdio.h> #include <limits.h> #define DATENTYP long long /*Durch Klammern von (x) wird ein uebergebener Ausdruck zuerst ausgewertet*/ #define zeigeBit(x) ((x)!=0)?fprintf_s(stdout,"1"):fprintf_s(stdout,"0") const void zeigeByte(DATENTYP cZ) { unsigned char nI; for (nI=sizeof(cZ)*CHAR_BIT;nI>0;nI--) { /*sizeof liefert Bytezahl*/ if (nI%4==0) fprintf_s(stdout," "); /*mit Luecken ist die Zahl besser lesbar*/ zeigeBit(cZ&(0x1i64<<(nI-1))); /*Postfix i64 auch fuer long long*/ } /*for*/ fprintf_s(stdout,"\n"); } /*zeigeByte*/
Du hast die Aufgabenstellung nicht verstanden:
Jinjael schrieb:
... und zum Ausgeben an die main Funktion zurückschicken.
Waldschrat schrieb:
...
Wehe, der Anfänger macht einen solchen Fehler.
...Ein Fehler ist ein Fehler. Wofür ist es relevant, ob den ein Anfänger macht?
-
Waldschrat schrieb:
Eigentlich sollte eine Anfänger kein int benutzen, da es prozessorabhängig ist.
Ist diese Vorsicht nicht ein wenig übertrieben? Was sollte schon passieren?
Vllt. sollte man sich erst recht irgendwelche fiesen Fallen in Übungsaufgaben ausdenken, die auf variable Integergrößen zurückzuführen sind.
Ein Anfänger/Lehrling/Student bezahlt dann schon während der Lehrzeit entsprechendes Lehrgeld, was weniger
schädlich/gefährlich sein dürfte, als später in der freien Programmierwildbahn.Waldschrat schrieb:
Verehrter Herr CJosef: Falsche Schlussfolgerung!
Mach Dir den richtigen Kopf, aber nicht irgendeinen. Warum nicht 256 oder 64K?Im Prinzip hast du ja recht.
Man will ja, das der Code auch noch im Jahre 4815 zuverlässig läuft und dann könnte ein
int mittlerweile > 128 Bits haben und - !peng! - da hamwa den potentiellen Pufferüberlauf!
Vllt. sollte ich mir also nicht einmal in Beispielcodes angewöhnen zu schlampen.
Ich gelobe Besserung und die ersten Ansätze lassen meinen Willen (sogar bereits vor deiner Kritik) auch schon erkennen (14:16:07 28.11.2012):
http://www.c-plusplus.net/forum/311138-20#2275450Waldschrat schrieb:
Ich wollte eigentlich fragen, wozu die Funktion zwei Rückgabewerte hat, einmal das normale Funktionsergebnis und einmal den Zeiger als zweiten Parameter, der ja am Funktionsende zurückgegeben wird.
Genaugenommen gibt es nur einen Rückgabewert.
Wozu der ist: zum einen ist das in der Aufgabe so gefragt, zum anderen spiegelt es das Verhalten gängiger Standardbibliotheken wider und man kann den Funktionsaufruf als Parameter für eine andere Funktion verwenden.Waldschrat schrieb:
puts (nimmt man das denn immer noch?)
Ja, wieso nicht?! Ich weiß, du nimmst immer fprintf_s und Konsorten, aber soviel
ich weiß ist das kein Standard, sondern lediglich von Microsoft eingeführt.
Jedenfalls, ich habe gerade nachgeguckt, ist diese Funktion nicht im Draft von open-std.org aufgeführt, also glaube ich das einfach mal.Waldschrat schrieb:
ab 11 : : ab Drücken Sie eine beliebige Taste . .
Zeile 1 haben wir erwartet.
Zeile 2 erstaunt den Fachmann, der Laie wundert sich.Okay, offengestanden, das überrascht mich.
Ewartet hätte ichab : : 11
Das liegt daran das ich bisher noch nicht in die Situation kam, mir über irgendwelche Reihenfolgen Gedanken zu machen.
Klar, hier und da mal von Aufrufkonventionen gehört wie pascal, stdcall haste nicht gesehen ... aber dann wieder vergessen.
Nun ja, für irgendeine Reihenfolge muss sich der Compiler ja entscheiden und
wie ich gerade in verschiedenen Quellen lese, ist im C-Standard weder die Aufrufkonvention noch die Reihenfolge der Abarbeitung
von Funktionsparameter definiert(was ja 2 verschiedene Paar Schuhe sind ). Z.B. hier
http://en.wikipedia.org/wiki/X86_calling_conventions...
cdecl
The cdecl calling convention originates from the C programming language and is used by many C compilers for the x86 architecture.
...Oder im Draft von open-std.org:
3.4.4
1 unspecified behavior
...
2 EXAMPLE An example of unspecified behavior is the order in which the arguments to a function are evaluated.
3.5Waldschrat schrieb:
Wir können nun untereinander weiterstreiten, welche Lösung robuster ist. Wehe, der Anfänger macht einen solchen Fehler.
Hmm, gibts da etwas zu streiten? Ich denke nicht. Fehler kann jeder machen, ob Anfänger oder nicht.
Das kann genauso gut mit einem int oder sonst einem Datentypen passieren, der zurückgegeben wird -
gemäß der einfachen Regel: schreibt man in den Rückgabewert einer Funktion Stuss hinein, so wird von ihr Stuss zurückgegeben.
C ist nun einmal nichts für den Ponyhof http://www.c-plusplus.net/forum/311127-10#2275333
-
Die Reihenfolge wie die Paramter bei einem Funktionsaufruf abgearbeitet werden, ist nicht festgelegt.
Da innerhalb dieses Sequence Point die Variablen geändert werden, ist das Verhalten auch nicht definiert.
Siehe http://www.dclc-faq.de/kap4.htmDas die Funktion int2binstr einen anderen Wert für binstr zurückgibt als den übergebenen, ist ein Fehler des Programmierers.
-
Warum mische ich mich hier eigentlich ein? Um einerseits selbst etwas zu lernen und andererseits eigene Erfahrungen weiterzugeben.
Aha, Rangfolge, Assoziativität und Aufrufkonventionen kommen so langsam bei einigen an. Eigentlich wusste ich auch nicht, auf was ich mich bei den Experimenten einlasse. Gut, das mit der Reihenfolge in der Parameterversorgung habe ich gezielt vom Zaum gebrochen, da die Studenten in den Klausuren mit solchen (undefinierten, abartigen) Fragen sehr oft gequält werden.
CJosef schrieb:
Ja, wieso nicht?! Ich weiß, du nimmst immer fprintf_s und Konsorten, aber soviel
ich weiß ist das kein Standard, sondern lediglich von Microsoft eingeführt.
Jedenfalls, ich habe gerade nachgeguckt, ist diese Funktion nicht im Draft von open-std.org aufgeführt, also glaube ich das einfach mal.Ja, offensichtlich lese ich andere Drafts:
Hier also meine Quellen aus der Quelle
www.open-std.org\jtc1\sc22\wg14\www\docs
, die nach Deiner Meinung offensichtlich falsch sind:ISO/IEC 9899:201x Committee Draft — December 2, 2010 N1548 Seiten 486ff
ISO/IEC 9899:201x Committee Draft — April 12, 2011 N1570 Seiten 490ff
Einfach einmal nach diesen Funktionen suchen und auf einen halbwegs C11 konformen Kompiler umsteigen Hier wird über
itoa
bzw._itoa
diskutiert, was ich nun wirklich nicht in der Norm finde.Ja, dann lasse ich das erst einmal hier und ziehe mich in meinen Winterschlaf zurück. Leute, die schon bei Erwähnung des Namens Microsoft in Ohnmacht fallen und dann noch so einen "Kram" verbreiten bringen mich auf jeden Fall geistig nicht weiter.
Ich weiß nicht, wie viele Hochschulen das Visual Studio als Lernplattform benutzen, ich kenne derzeit nur zwei. Aber das wäre mal eine Umfrage wert.
Bisher hat mir weder Wutz noch CJosef und selbst der große Moderator keinen konkreten Fehler genannt. Wie wäre es einmal damit? Einfach die Zitate aus dem Quelltext nehmen und sauber zerlegen.
Die Einlassungen über fprintf_s, fscanf_s usw. waren dann wohl ein klassischer Fehlversuch. Nur weil andere anders denken, muss dieses nicht falsch sein.
-
Waldschrat schrieb:
Einfach einmal nach diesen Funktionen suchen und auf einen halbwegs C11 konformen Kompiler umsteigen Hier wird über
itoa
bzw._itoa
diskutiert, was ich nun wirklich nicht in der Norm finde.Der Name dieses Forums lautet: "C (C89 und C99)". Weder C11 noch Posix noch Microsoft können hier implizit als "Norm" vorausgesetzt werden (wie auch die von Dir erwähnten "Gurus" bei mir allerhöchstens als "Regulars" durchgehen). Also sollte ein "Helfer" auf Sprachkonstrukte aufmerksam machen, ob neu oder implementationsbedingt. Da hier viele Anfänger mit dem GCC unterwegs sind, ist sogar meistens ein Hinweis auf C99 angebracht, wobei ich mir angewöhnt habe, auf den mutmaßlichen Standard des Fragestellers einzugehen, und bei Zweifeln auf C89 zurückzufallen.
viele grüße
ralph
-
Danke für die beruhigenden Worte. Eigentlich ging es mir bei meiner vorgeschlagenen Lösung einzig darum zu zeigen, wie eine verallgemeinerte Technik denkbar ist, also automatische Anpassung an den jeweiligen Datentyp und sinnvolles Schieben. Dass mich dann jemand wegen fprintf_s statt fprint anmacht, hätte ich nicht gedacht.
Ich weiß nicht, in wie vielen Threads hier inzwischen über scanf, fflush und ähnliches diskutiert wurde, statt sinnvolles zu programmieren.
Wie man also leicht sieht, wollt Ihr im letzten Jahrtausend, also das mit der 19 vorne, verharren. Im Grunde lernen die Anfänger etwas, was sie zum Großteil in der Praxis wieder wegwerfen können.
Zum wirklich allerletzen Abschluss: Non vitae, sed scholae discimus. (Original) Umgekehrtes gilt leider nicht.
Ich werde Euch nicht mehr stören.
-
Hab das mal für ein Juxprogramm geschrieben. Ist zwar kein C und 0x80 etc. musst du auch noch 1 << bitshiften. Kriegst du schon hin, das auf C zu übertragen.
Als Konzept:CString ConvertCh2Bin( char ch ) const { int ich = static_cast<int> (ch); CString line; line += (ich & 0x80) == 0x80 ? "1" : "0"; line += (ich & 0x40) == 0x40 ? "1" : "0"; line += (ich & 0x20) == 0x20 ? "1" : "0"; line += (ich & 0x10) == 0x10 ? "1" : "0"; line += (ich & 0x08) == 0x08 ? "1" : "0"; line += (ich & 0x04) == 0x04 ? "1" : "0"; line += (ich & 0x02) == 0x02 ? "1" : "0"; line += (ich & 0x01) == 0x01 ? "1" : "0"; return( line ); }
Indem du z.B. 0x80 per bitshift erstellst hast du alle Anforderungen erfüllt, aber deinen Lehrer richtig ausgetrickst.
Ich hab sowas immer geliebt.