?
Uhhh, jetzt bin ich noch einmal schweißgebadet in meiner Kuschelhöhle aufgewacht.
Ich schäme mich für die Fehler bei der Umstellung auf Funktionen.
Ich schäme mich etwas weniger, da sich die Fehler gegenseitig aufheben.
Eigentlich muss ich mich nicht schämen, da keiner bis hier gelangt.
Böse Zungen behaupten, dass ich das mit Absicht eingebaut habe, um noch eine Meldung zu schreiben.
Leider ist der Operator in der Funktion falsch umkopiert worden. Richtig ist
int ctoi(char c) { /*gibt numerischen Wert einer Ziffer zurueck*/
return c&0xF;
} /*ctoi*/
Man sieht eigentlich sehr schön, dass diese Funktion total überflüssig ist.
Da die Funktion nicht aufgerufen wird, hatte der Fehler keine Wirkung. Also muss Zeile 32 geändert werden in
nErgebnis=nErgebnis*10+ctoi(*cZeiger); /*Horner-Schema und numerischer Wert statt Zeichen*/
Nun hat Herr Man_tis noch das Ausgabeproblem. Zuerst die einfache Lösung zur Ausgabe in oktal und sedezimal (hexadezimal ist englischer Mischmasch: hexa griechisch, dezimal lateinisch)
int main(void) {
unsigned char cZahl[80+1]; /*Zeichenkette fester Laenge*/
int nZahl;
fprintf_s(stdout,"Zahl wird als Zeichenkette eingelesen: ");
fscanf_s(stdin,"%80s",cZahl,sizeof(cZahl)-1);
fprintf_s(stdout,"Sie haben eingegeben: %s\n",cZahl);
nZahl=stoi(cZahl);
fprintf_s(stdout,"Der numerische Wert ist %d oktal: %o sedezimal: %X\n",nZahl,nZahl,nZahl);
return 0;
} /*main*/
Da cout letztendlich intern dieselben Funktionen wie printf benutzt, kann man auch dort mit den Ausgabemanipulatoren
cout<<dec, cout<<oct, cout<<hex
die automatische Umwandlung in C++ erzeugen.
Das Ergebnis sieht dann am Zahlenüberlauf von C folgendermaßen aus:
Zahl wird als Zeichenkette eingelesen: 2147483647
Sie haben eingegeben: 2147483647
Der numerische Wert ist 2147483647 oktal: 17777777777 sedezimal: 7FFFFFFF
Drücken Sie eine beliebige Taste . . .
Zahl wird als Zeichenkette eingelesen: -2147483648
Sie haben eingegeben: -2147483648
Der numerische Wert ist -2147483648 oktal: 20000000000 sedezimal: 80000000
Drücken Sie eine beliebige Taste . . .
Wenn der Dozent die Benutzung der automatischen Formatierung nicht so gerne sieht oder seine schwarze Seele auf die Idee kommt, die Zahlen im Fünfer- oder Zwölfersystem anzeigen zu lassen, hilft nur noch ein Basiswandler
/*A031C_Basiswandler.cpp: Einstiegspunkt der Konsolenanwendung.*/
/*Einfacher Basiswandler fuer Ganzzahlen*/
#include <stdio.h>
#include <stdlib.h> /*fuer system*/
#include <string.h> /*fuer _strrev*/
#ifdef __cplusplus
#pragma message("mit C++")
#else
#pragma message("mit C")
#endif
void wandleIterativ(unsigned long nD,unsigned long nBasis) {
char cErgebnis[80+1];
/*_strset(cErgebnis,NULL); /*Angstanweisung*/
unsigned char cZ,nI=0;
while (nD>0) { /*Iteration*/
cZ=(unsigned char)((nD%nBasis)+48); /*Ziffer*/
if (cZ>57) cZ+=7; /*Buchstabe*/
nD/=nBasis;
cErgebnis[nI++]=cZ; /*hinten anhängen*/
} /*while*/
cErgebnis[nI]='\0';
fprintf_s(stdout,"\nErgebnis zur Basis %lu: %s\n\n",nBasis,_strrev(cErgebnis));
} /*wandleIterativ*/
void wandleRekursiv(unsigned long nD,unsigned long nBasis) {
unsigned char cZ;
if (nD!=0) {
cZ=(unsigned char)((nD%nBasis)+48); /*Ziffer*/
if (cZ>57) cZ+=7; /*Buchstabe*/
fprintf_s(stdout,"%c",cZ);
wandleRekursiv(nD/nBasis,nBasis);
} /*if*/
} /*wandleRekursiv*/
int main() {
unsigned long nD,nBasis;
fprintf_s(stdout,"Dezimale Ganzzahl: ");scanf_s("%ul",&nD);
do {
fprintf_s(stdout,"Zielbasis 2-36: ");fscanf_s(stdin,"%ul",&nBasis);
} while (nBasis<2||nBasis>36);
wandleIterativ(nD,nBasis); /*Reihenfolge wird intern korrigiert*/
fprintf_s(stdout,"Rekursions-Ergebnis in umgekehrter Reihenfolge: ");
wandleRekursiv(nD,nBasis); /*Rekursion erzeugt die Ziffern in umgekehrter Reihenfolge*/
fprintf_s(stdout,"\n\n");
system("Pause");
return 0;
} /*main*/
Der Variationsbereich der Basen ist von 2 bis 36 (10 Ziffern plus 26 Buchstaben). Wer mehr will, muss mit Sonderzeichen in der Ausgabe rechnen.
Noch einmal zurück zur eher bescheidenen Aufgabenstellung. Sie muss richtig lauten:
Schreiben Sie eine Funktion
int stoi(const char *cZahl, int *nZahl)
die eine Zeichenkette cZahl in eine numerische Ganzzahl nZahl umwandelt.
Der Rückgabewert ist -1 , wenn kein Fehler aufgetreten ist. Falls ein Fehler auftritt, gibt der Rückgabewert (>=0) die Position des ersten fehlerhaften Zeichens an. nZahl enthält dann den Wert des als Zahl erkannten Kopfes.
Herr Man_tis wird folgende Probleme haben:
1. Im ersten Semester hört man nichts über const , also einfach weglassen.
2. Die Parameterübergabe per Referenz kommt im Unterricht wohl noch. Also muss er die Lösung bis auf die Weihnachtsferien verschieben
Ohne die Forderung nach der Ausgabe der Fehlerstelle erreichen wir das Ergebnis im aktuellen Programm durch einen Aussprung
if (*cZeiger<'0'||*cZeiger>'9') {
fprintf_s(stderr,"Falsche Eingabe\n");
fprintf_s(stderr,"Ich ende ganz einfach.\n");
return nErgebnis;
} /*if*/
Eine Alternative besteht darin, alle fehlerhaften Zeichen auszulassen
while (*cZeiger!='\0') { /*Zeigertechnik*/
if (*cZeiger<'0'||*cZeiger>'9') {
fprintf_s(stderr,"Falsche Eingabe\n");
fprintf_s(stderr,"Ich lasse das Zeichen einfach weg.\n");
} else {
nErgebnis=nErgebnis*10+ctoi(*cZeiger); /*Horner-Schema und numerischer Wert statt Zeichen*/
} /*if*/
Ürigens, durch die Ausgabe auf den Fehlerstrom stderr kann das eigentliche Ergebnis ohne Meldungen aus dem Ausgabestrom stdout abgeholt werden.
Der Zahlenüberlauf ist ein "ernster Fehler" (severe error), der so nicht repariert werden kann. Das Ergebnis einfach auf 0 zu setzen ist mehr als fragwürdig, da 0 natürlich auch als normale Zahl existiert.
Noch ein Tipp für Neugierige:
Schauen Sie doch einfach einmal in limits.h hinein. Sie finden
#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */
Warum nicht -2147483648 ?? Sieht wie eine "Angsanweisung" aus, falls der Kompiler nur -2147483647