Probleme bei einer Hausarbeit
Probleme bei einer Hausarbeit
Hallo zusammen,
unser Prof. hat uns paar Aufgaben aufgegeben und zwar müssen wir zwei Programme schreiben. Die Programme sollen in eine Datei schreiben können oder aus einer Datei lesen können. Bei dem ersten Programm sollen diese Funktionen in der Main erledigt werden und bei dem zweiten sollen dieses Funktionen in Funktionen ausgelagert werden. Die beiden Programme habe ich hin bekommen und sie lassen sich ohne Probleme kompilieren. Nur mein Problem ist das wenn ich innerhalb der beiden Programme versuche die Eingabe zu machen, das manche Eingaben übersprungen werden. So kann ich nach dem ich meinen Namen eingegeben habe nicht den Status eingeben, weil der Punkt übersprungen wird. Vielleicht könnt ihr mir weiter helfen bin langsam mit meinem Latein am Ende.
http://nopaste.debianforum.de/17718
http://nopaste.debianforum.de/17717
unser Prof. hat uns paar Aufgaben aufgegeben und zwar müssen wir zwei Programme schreiben. Die Programme sollen in eine Datei schreiben können oder aus einer Datei lesen können. Bei dem ersten Programm sollen diese Funktionen in der Main erledigt werden und bei dem zweiten sollen dieses Funktionen in Funktionen ausgelagert werden. Die beiden Programme habe ich hin bekommen und sie lassen sich ohne Probleme kompilieren. Nur mein Problem ist das wenn ich innerhalb der beiden Programme versuche die Eingabe zu machen, das manche Eingaben übersprungen werden. So kann ich nach dem ich meinen Namen eingegeben habe nicht den Status eingeben, weil der Punkt übersprungen wird. Vielleicht könnt ihr mir weiter helfen bin langsam mit meinem Latein am Ende.
http://nopaste.debianforum.de/17718
http://nopaste.debianforum.de/17717
Re: Probleme bei einer Hausarbeit
Dieser Link [1] beschreibt genau dein Problem und liefert auch gleich einige Lösungsansätze.
mfg m
[1] http://openbook.galileocomputing.de/c_v ... 05_001.htm
mfg m
[1] http://openbook.galileocomputing.de/c_v ... 05_001.htm
-
- Beiträge: 141
- Registriert: 06.12.2007 18:03:03
- Lizenz eigener Beiträge: MIT Lizenz
- Wohnort: Kehl
Re: Probleme bei einer Hausarbeit
Hi monkey,
etwas verkürzt würde ich sagen: Das Problem liegt in der Funktion scanf().
In der bei mir vorhandenen Literatur, die bis in die späten 80er Jahre zurückreicht, habe ich dazu nie etwas Kritisches gefunden.
Wir leben bekanntlich in Europa. Wenn wir eine Zahl mit Dezimalstellen schreiben wollen, verwenden wir somit ein Komma. Versuche das doch einmal mit scanf(): Entweder verwendet der Anwender einen Punkt, oder ...
Die erste Überlegung sollte sein: Welche Arten von Daten sollen eingegeben werden. Wir unterscheiden
Alphanumerische Zeichenfolgen
ganze Zahlen (wieso hast Du im zweiten Programmbeispiel für das Geburtsdatum einen int-Wert definiert?)
Gleitkommazahlen.
Abhängig davon bieten sich unterschiedliche Verarbeitungsroutinen für die erfassten Zeichenfolgen an. Bei Texteingaben ist gets() einfach und sicher zu handhaben.
Es sollte aber immer geprüft werden, ob jemand eventuell mehr Zeichen eingegeben hat, als z.B. in der aufnehmenden char-Variable vorgesehen ist. Du prüfst z.B. die Eingabelänge des Namens nicht nach und beschränkst sie auch nicht. 20 Zeichen können reichen, müssen es aber nicht. Und dann: Fehler!
Eine Möglichkeit der Prüfung ist die Anlage eines längeren Strings, die Prüfung der Eingabelänge und dann das Kopieren von maximal 19 Zeichen in den Teil der struct, die den Namen aufnehmen muss (das 20. Byte enthält die beendende Null).
Da Du als Programmierer weißt, welche Art von Eingabe vom Benutzer erwartet wird, kannst Du z.B. einen String überprüfen und, wenn er formal die erwarteten Zeichen hat, in int oder double-Werte konvertieren. Im letzten Fall kann damit z.B. sowohl ein Punkt als auch ein Komma als Dezimalzeichen interpretiert werden, wobei das Komma durch eine Programmroutine vor der Konvertierung in einen Punkt gewandelt sein muss.
Ich selbst verwende ncurses. Dabei kann der Cursor positioniert werden, Du kannst unterschiedliche Fenster definieren, die parallel im Speicher liegen, und Farben einsetzen.
Über die Abfrage des Wertes von Eingaben der Pfeiltasten etc. kannst Du Erfassungsroutinen schreiben, bei denen nach Feststellung eines Schreibfehlers wieder in die vorausgegangene Abfrage eingestiegen werden kann (und mehr).
Ich weiß natürlich nicht, auf welchem Niveau Dein Professor die Aufgabe gelöst sehen möchte. Es sollte aber nie vergessen werden, dass das schwächste Glied in der Kette häufig der Mensch ist, der am Computer sitzt und das Programm benützt.
Gruß
Hans-Martin
etwas verkürzt würde ich sagen: Das Problem liegt in der Funktion scanf().
In der bei mir vorhandenen Literatur, die bis in die späten 80er Jahre zurückreicht, habe ich dazu nie etwas Kritisches gefunden.
Wir leben bekanntlich in Europa. Wenn wir eine Zahl mit Dezimalstellen schreiben wollen, verwenden wir somit ein Komma. Versuche das doch einmal mit scanf(): Entweder verwendet der Anwender einen Punkt, oder ...
Die erste Überlegung sollte sein: Welche Arten von Daten sollen eingegeben werden. Wir unterscheiden
Alphanumerische Zeichenfolgen
ganze Zahlen (wieso hast Du im zweiten Programmbeispiel für das Geburtsdatum einen int-Wert definiert?)
Gleitkommazahlen.
Abhängig davon bieten sich unterschiedliche Verarbeitungsroutinen für die erfassten Zeichenfolgen an. Bei Texteingaben ist gets() einfach und sicher zu handhaben.
Es sollte aber immer geprüft werden, ob jemand eventuell mehr Zeichen eingegeben hat, als z.B. in der aufnehmenden char-Variable vorgesehen ist. Du prüfst z.B. die Eingabelänge des Namens nicht nach und beschränkst sie auch nicht. 20 Zeichen können reichen, müssen es aber nicht. Und dann: Fehler!
Eine Möglichkeit der Prüfung ist die Anlage eines längeren Strings, die Prüfung der Eingabelänge und dann das Kopieren von maximal 19 Zeichen in den Teil der struct, die den Namen aufnehmen muss (das 20. Byte enthält die beendende Null).
Da Du als Programmierer weißt, welche Art von Eingabe vom Benutzer erwartet wird, kannst Du z.B. einen String überprüfen und, wenn er formal die erwarteten Zeichen hat, in int oder double-Werte konvertieren. Im letzten Fall kann damit z.B. sowohl ein Punkt als auch ein Komma als Dezimalzeichen interpretiert werden, wobei das Komma durch eine Programmroutine vor der Konvertierung in einen Punkt gewandelt sein muss.
Ich selbst verwende ncurses. Dabei kann der Cursor positioniert werden, Du kannst unterschiedliche Fenster definieren, die parallel im Speicher liegen, und Farben einsetzen.
Über die Abfrage des Wertes von Eingaben der Pfeiltasten etc. kannst Du Erfassungsroutinen schreiben, bei denen nach Feststellung eines Schreibfehlers wieder in die vorausgegangene Abfrage eingestiegen werden kann (und mehr).
Ich weiß natürlich nicht, auf welchem Niveau Dein Professor die Aufgabe gelöst sehen möchte. Es sollte aber nie vergessen werden, dass das schwächste Glied in der Kette häufig der Mensch ist, der am Computer sitzt und das Programm benützt.
Gruß
Hans-Martin
Re: Probleme bei einer Hausarbeit
Einfach vielleicht, aber keinesfalls sicher: Immer fgets() stattdessen verwenden!Hans-Martin hat geschrieben:Bei Texteingaben ist gets() einfach und sicher zu handhaben.
Eben das ist bei fgets() möglich.Es sollte aber immer geprüft werden, ob jemand eventuell mehr Zeichen eingegeben hat, als z.B. in der aufnehmenden char-Variable vorgesehen ist. Du prüfst z.B. die Eingabelänge des Namens nicht nach und beschränkst sie auch nicht. 20 Zeichen können reichen, müssen es aber nicht. Und dann: Fehler!
dazu kannst du ja einfach den Sting abschreiten und alle Kommas in Punkte umwandeln. Danach in eine Zahl umwandeln lassen.sowohl ein Punkt als auch ein Komma als Dezimalzeichen interpretiert werden, wobei das Komma durch eine Programmroutine vor der Konvertierung in einen Punkt gewandelt sein muss.
Üblicherweise ist das deutlich zu kompliziert für Übungsaufgaben die anderen Zwecken dienen. Wenn man schon programmieren kann, dann ist es etwas anderes.Ich selbst verwende ncurses. Dabei kann der Cursor positioniert werden, Du kannst unterschiedliche Fenster definieren, die parallel im Speicher liegen, und Farben einsetzen.
Ich denke dass man in den Einstiegsaufgaben davon ausgehen darf, dass korrekte Eingaben gemacht werden. So war es zumindest in meinem Studium. Aber das sollte der Prof. eigentlich gesagt haben.Ich weiß natürlich nicht, auf welchem Niveau Dein Professor die Aufgabe gelöst sehen möchte. Es sollte aber nie vergessen werden, dass das schwächste Glied in der Kette häufig der Mensch ist, der am Computer sitzt und das Programm benützt.
Somit schlage ich vor: Schau dass das Programm funkioniert, wenn immer korrekte Eingaben gemacht werden. Danach, wenn du dann noch Zeit hast, kannst du dich um Robustheit und Sicherheit kümmern.
Use ed once in a while!
Re: Probleme bei einer Hausarbeit
Danke erst mal für die ganzen Beiträge. Ich hatte mir das schon gedacht das scanf() Probleme hat unter Linux den Puffer zu leeren. Da ich mir paar Übungen von meinen Kommilitonen angeschaut habe und die hatten es auch nicht anders gemacht. Nur die hatten es auf ihren Windows Laptops ausgeführt und da gab es anscheinend keine Probleme. Als ich unseren Betreuer gefragt hatte (nicht der Prof) meinte der, das wäre eigentlich auch richtig wie ich das gemacht hätte. Aber mir sagen konnte er auch nicht, weshalb manche Eingaben übersprungen werden.
@Hans-Martin grundsätzlich hast du recht man sollte immer überprüfen was der Benutzer eingegeben hat, das predigt unser Prof. auch ständig. Aber bei den Übungsaufgaben soll es eigentlich nur drum gehen das wir verstehen was ein Stream ist und mit Datei umgehen können. Ich denke mal wenn ich die Tage noch Zeit habe werde ich versuchen deine Vorschläge umzusetzen.
PS Könnt ihr mir ein Tipp geben wie ich in das Programm eine verkettete Liste integriere. Stehe da momentan noch etwas auf dem Schlauch. Bin für jeden Tipp dankbar.
mfg monkey
@Hans-Martin grundsätzlich hast du recht man sollte immer überprüfen was der Benutzer eingegeben hat, das predigt unser Prof. auch ständig. Aber bei den Übungsaufgaben soll es eigentlich nur drum gehen das wir verstehen was ein Stream ist und mit Datei umgehen können. Ich denke mal wenn ich die Tage noch Zeit habe werde ich versuchen deine Vorschläge umzusetzen.
PS Könnt ihr mir ein Tipp geben wie ich in das Programm eine verkettete Liste integriere. Stehe da momentan noch etwas auf dem Schlauch. Bin für jeden Tipp dankbar.
mfg monkey
-
- Beiträge: 141
- Registriert: 06.12.2007 18:03:03
- Lizenz eigener Beiträge: MIT Lizenz
- Wohnort: Kehl
Re: Probleme bei einer Hausarbeit
Hi monkey,
hilft Dir auf Deine komplex zu beantwortende Frage ein Literaturhinweis?
Vielleicht kannst Du das im Verlag Markt + Technik erschienene Buch "C-Programmierung für Linux" auftreiben, Verfasser des englischen Originals sind Erik de Castro Lopo, Peter Aitken, Bradley L. Jones. Dort findet sich eine mehrseitige Erläuterung samt Programmbeispiel.
Extrem verkürzt, baust Du einen Zeiger auf eine struct Kartei in die von Dir definierte struct Kartei ein:
struct Kartei
{
char Name[20];
char Status;
int Semester;
int Geburtsdatum;
struct Kartei *zeiger_auf_das_naechste_element;
};
Was ncurses angeht: Manchmal ist das zunächst komplizierter Scheinende das Einfachere.
Schaue Dir z.B. das manual zu getch an (rein vorsorglich: Aufruf man getch - Voraussetzung Du hast die manuals komplett installiert). Mit den Rückgabewerten für Funktionstasten lassen sich ganz einfach Wünsche des Benutzers nach der Fortführung der Eingabe oder nach sonst irgend etwas abfragen (ganz genau genommen: in Bezug auf Eingaben des Standardfensters, aber das ist als default unproblematisch).
Was Meillo zu fgets() schreibt, ist zwar grundsätzlich richtig. Einen längeren String für die Eingabe zu verwenden, wie ich es vorschlage, hat den Vorteil, dass der Benutzer nicht plötzlich gestoppt wird, sondern Du als Programmierer prüfen kannst, wie viel Zeichen er mehr eingegeben hat als im char[] angelegt sind. Du kannst eine Routine zur Abkürzung schaffen. Was die Wandlung von Kommas in Punkte angeht, wie sie Meillo vorschlägt, ist es natürlich nötig, darauf zu achten, dass nur das als Dezimalstelle gedachte Komma zum Punkt wird und Leerstellen und evtl. versehentlich geschriebene andere Zeichen eliminiert werden.
Alle Kommas in Punkte zu wandeln führt zu einem Fehler.
Gruß
Hans-Martin
hilft Dir auf Deine komplex zu beantwortende Frage ein Literaturhinweis?
Vielleicht kannst Du das im Verlag Markt + Technik erschienene Buch "C-Programmierung für Linux" auftreiben, Verfasser des englischen Originals sind Erik de Castro Lopo, Peter Aitken, Bradley L. Jones. Dort findet sich eine mehrseitige Erläuterung samt Programmbeispiel.
Extrem verkürzt, baust Du einen Zeiger auf eine struct Kartei in die von Dir definierte struct Kartei ein:
struct Kartei
{
char Name[20];
char Status;
int Semester;
int Geburtsdatum;
struct Kartei *zeiger_auf_das_naechste_element;
};
Was ncurses angeht: Manchmal ist das zunächst komplizierter Scheinende das Einfachere.
Schaue Dir z.B. das manual zu getch an (rein vorsorglich: Aufruf man getch - Voraussetzung Du hast die manuals komplett installiert). Mit den Rückgabewerten für Funktionstasten lassen sich ganz einfach Wünsche des Benutzers nach der Fortführung der Eingabe oder nach sonst irgend etwas abfragen (ganz genau genommen: in Bezug auf Eingaben des Standardfensters, aber das ist als default unproblematisch).
Was Meillo zu fgets() schreibt, ist zwar grundsätzlich richtig. Einen längeren String für die Eingabe zu verwenden, wie ich es vorschlage, hat den Vorteil, dass der Benutzer nicht plötzlich gestoppt wird, sondern Du als Programmierer prüfen kannst, wie viel Zeichen er mehr eingegeben hat als im char[] angelegt sind. Du kannst eine Routine zur Abkürzung schaffen. Was die Wandlung von Kommas in Punkte angeht, wie sie Meillo vorschlägt, ist es natürlich nötig, darauf zu achten, dass nur das als Dezimalstelle gedachte Komma zum Punkt wird und Leerstellen und evtl. versehentlich geschriebene andere Zeichen eliminiert werden.
Alle Kommas in Punkte zu wandeln führt zu einem Fehler.
Gruß
Hans-Martin
Re: Probleme bei einer Hausarbeit
Was aber ist ein ``längerer Sting''? 128Byte? 1024Byte? Es wird immer einen User geben, der noch mehr Zeichen eingibt. Und dann hast du deinen Pufferüberlauf, und kannst nichts dagegen tun!Hans-Martin hat geschrieben:Was Meillo zu fgets() schreibt, ist zwar grundsätzlich richtig. Einen längeren String für die Eingabe zu verwenden, wie ich es vorschlage, hat den Vorteil, dass der Benutzer nicht plötzlich gestoppt wird, sondern Du als Programmierer prüfen kannst, wie viel Zeichen er mehr eingegeben hat als im char[] angelegt sind. Du kannst eine Routine zur Abkürzung schaffen.
Deshalb nochmal: gets() ist _grundsätzlich_ zu vermeiden! fgets() kann gets() vollständig ersetzen und ist sicher.
Das sehe ich anders. Deshalb habe ich aus bewusst geschrieben: alle Kommas in Punkte umzuwandeln.Was die Wandlung von Kommas in Punkte angeht, wie sie Meillo vorschlägt, ist es natürlich nötig, darauf zu achten, dass nur das als Dezimalstelle gedachte Komma zum Punkt wird und Leerstellen und evtl. versehentlich geschriebene andere Zeichen eliminiert werden.
Alle Kommas in Punkte zu wandeln führt zu einem Fehler.
Denn ein selektives Umwandeln benötigt eine Logik (Intelligenz) die weiß welches Komma umgewandelt werden soll und welches nicht. Und wenn du Leerzeichen und sonstige Störzeichen eliminieren willst, dann brauchst du noch mehr Logik. Wie handelst du bei ``1234 5.67'' um und wie bei ``123.4 567'' und wie bei ``1234.56 7'' oder gar bei ``12.3,4.5,67''? Soviel Logik die benötigt ist um derartige Fragen zufriedenstellend zu lösen, führt unweigerlich zu Komplexität und wird das Programm aufblähen. (Andere Stellen mit ähnlichen Problemstellungen werden folgen und weitere Komplexität hinzufügen.)
Ich würde einfach strtol() (eine sicherere Alternative zu atoi() und atol() ) die Arbeit tun lassen. Soll die Funktion doch entscheiden welche Zahlen sie findet. Und wenn sie keine findet, dann soll der User sie erneut und korrekt eingeben.
Das einzige was ich wollte, ist es auf simple Weise Zahlen mit Dezimal-Komma zu akzeptieren. Dafür benötigt es nur wenige Zeilen:
Code: Alles auswählen
int i;
/* convert ',' to '.' to support german number format */
for (i = 0; i < sizeof(buf); i++) {
if (buf[i] == ',') {
buf[i] = '.';
}
}
Empfehlenswert dazu ist: ``The Practice of Programming'' von Kernighan und Pike, die zu Recht predigen: Simplicity, Clarity, Generality!
EDIT:
Vielleicht hilft auch schon alleinig das Umstellen der Locales auf deutsch. Könnte sein, dass strtol() dann das Komma als Dezimaltrenner erkennt ... aber keine Ahnung ob das wirklich geht, oder gar portabel ist.
Use ed once in a while!
Re: Probleme bei einer Hausarbeit
Meillo hat geschrieben:EDIT:
Vielleicht hilft auch schon alleinig das Umstellen der Locales auf deutsch. Könnte sein, dass strtol() dann das Komma als Dezimaltrenner erkennt ... aber keine Ahnung ob das wirklich geht, oder gar portabel ist.
Code: Alles auswählen
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
char* end;
double d;
char input[] = "1,2345 Beispiel";
d = strtod(input, &end);
printf("number %lf parsed up to %s\n", d, end);
setlocale(LC_ALL, ""); // set default locale
d = strtod(input, &end);
printf("number %lf parsed up to %s\n", d, end);
}
Code: Alles auswählen
export LANG=de_DE.UTF-8
BTW: Auch scanf kann man mitteilen, dass es nur x Zeichen in den char* kopieren darf.
MfG GoKi
:wq
:wq
Re: Probleme bei einer Hausarbeit
thx ... so habe ich auch wieder was gelernt (nämlich wie man locales in C-Programmen verwendet )GoKi hat geschrieben:Kompilieren und dann mal mit deutscher Umgebung ausführen.
Und für alle die zu faul sind selbst zu kompilieren; hier die Ausgabe:
Code: Alles auswählen
$ LANG=de_DE.UTF-8 ./a.out
number 1.000000 parsed up to ,2345 Beispiel
number 1,234500 parsed up to Beispiel
Use ed once in a while!