Hallo liebes Forum,
wir haben in der Technikerschule(ET) mit C angefangen, da ich schon
Grundkenntnisse habe, also die ganzen Programmierstrukturen(while,for,if
etc..) und mich das ganze sehr interessiert, habe ich meinen Lehrer nach
einer anspruchsvolleren Aufgabe gefragt. Und zwar sollte ich eine
einfache Login Maske bauen, die folgende Funktionen haben soll:
- Eingabe darf nur Zahlen und Buchstaben(klein+groß) enthalten,
ansonsten Fehler ausgeben
- Ist Eingabe korrekt, soll User + Passwort getrennt abgefragt werden
und entsprechend ein Fehler ausgegeben werden(Falscher User, Falsches
Passwort)
- Bei einem Fehler soll der User die Möglichkeit haben, das ganze zu
wiederholen.
- Wenn alles korrekt ist, soll eine Erfolgreich Meldung ausgegeben
werden, und das Programm abgebrochen werden.
- Zuerst soll der Username abgefragt werden, dann das Passwort
Mein Programm funktioniert auch mehr oder weniger, denke ich. Aber ich
habe ein größeres Problem. Ich definiere char arrays mit 20 Elementen
und lese über fgets die Eingaben ein.
Sobald ich aber bei einer Eingabe, mehr als 20 Zeichen eingebe, führt
das zu einem "undefinierten Verhalten"...
Bsp.: Wenn ich beim Username über 20 Zeichen eingebe, wird danach direkt
zur Überprüfung(checkEqual()) gepsrungen, Passwort Abfrage wird
übersprungen.
Wenn ich beim Username unter 20 Zeichen eingebe und danach beim Passwort
mehr als 20 Zeichen(und ein falsches) eingebe, wird beim nächsten
Durchlauf, die Abfragen komplett übersprungen.
Ich habe schon versucht über memset zu löschen, aber das setzt direkt
bei Element im Prinzip den Nullterminator, und überspringt dann im
zweiten Durchlauf die Abfragen...
Hat jemand eine Idee?
Die OMP Sachen sind nur Spielerei. Könnt ihr ignorieren ;)
Achja der Code:
1
#include <stdio.h>
2
#include <string.h>
3
#include <ctype.h>
4
#include <omp.h>
5
6
typedef enum { false, true } bool;
7
8
// Funktion um Eingabe zu prüfen, Nur Buchstaben und Zahlen erlaubt!
Stell Dir vor, strlen() gibt 0 zurück. Dann überschreibst Du Speicher
vor dem Array.
Ansonsten hast Du doch sicher eine Entwicklungsumgebung mit einem
Debugger, mit dem Du Dir anschauen kannst, was passiert?
fgets liest maximal die Anzahl Zeichen -1 ein. Wenn da noch kein '\n'
dabei war, ist die Eingabe noch nicht abgeschlossen.
Dies wird bei dir dann beim nächsten fgets eingelesen.
Das '\n' im String ist also nicht ganz überflüssig.
Herzlichen Dank für das Feedback!
Das newline hat mir diverse Probleme beim vergleichen eingebracht. Wenn
ich das entfernen der Newline in der checkEqual Funktion einfüge,
schmiert das Programm bei der ersten Abfrage(checkEqual) ab. Deswegen
hab ich das in der Mainfunktion drinne.
@Peter 2
Danke, werd ich ändern.
@Peter 1
Du hast recht, ich mache eine kleine Abfrage davor.
Gruß
Hallo zusammen,
ich habe das Programm nun angepasst und eine Abfrage eingefügt, in der
abgefragt wird, ob das Newline vorhanden ist(checkEingabe) und prüfe
auch die Zeichenlänge. Jedoch bleibt weiterhin das Problem bestehen,
dass wenn ich absichtlich mehr als 20 Zeichen eingebe, dass dies zu
undefinierten Verhalten führt, weil die Variablen dann noch gespeichert
bleiben...
Hier der angepasste Code:
1
#include<stdio.h>
2
#include<string.h>
3
#include<ctype.h>
4
#include<omp.h>
5
6
typedefenum{false,true}bool;
7
8
// Funktion um Eingabe zu prüfen, Nur Buchstaben und Zahlen erlaubt!
ein Zeiger ist immer gleich groß, die abfrage macht überhaupt keinen
sinn.
viel zu kompliziert und falsch (length-1 warum nicht das letzte zeichen
prüfen!):
Müller schrieb:> size_t length = strlen(string)>> if(string[length] != '\0'
Was soll denn da raus kommen.
So ist ein C-String definiert. Das geht da nicht anders.
Müller schrieb:> Jedoch bleibt weiterhin das Problem bestehen,> dass wenn ich absichtlich mehr als 20 Zeichen eingebe, dass dies zu> undefinierten Verhalten führt
Weil du das Problem nicht behoben hast, das dann noch Zeichen im
Eingabestrom stehen.
(Du musst dann solange Zeichen lesen, bis ein '\n' auftaucht)
Hallo Peter 2,
erstmal danke für die Hinweise. Habe das erstmal umgesetzt. Wie gesagt
die Open-MP Sache, ist nur eine Spielerei. Die wird ja wohl nicht dafür
verantwortlich sein, dass es nicht so recht funktioniert, denke ich.
Parallele Sektionen dürfen nicht unterbrochen(break/return) werden,
deshalb sieht in erster Linie etwas kompliziert aus. Aber das weist du
ja schon.
Ich habe die angepasste Datei angehängt, da dass etwas zu voll wird,
denke ich.
Gruß
Müller schrieb:> erstmal danke für die Hinweise. Habe das erstmal umgesetzt. Wie gesagt> die Open-MP Sache, ist nur eine Spielerei.
naja, ich halte das sogar für eine Resourcenverschwendung.
Wenn das 1.Zeichen schon ungültig ist, arbeiten dann die andere
Cores/Threads noch den String bis zum ende ab. Obwohl schon lange
feststeht, das er ungültig ist.
Nicht jedes Problem lässt sich optimieren.
Lerne doch erst mal mit einem Debugger umzugehen, dann kannst du das
Programm schrittweise durchgehen und sehen was genau passiert und wo es
zu einem Problem kommt.
Danke an alle für die Hilfe, ich denke ich habe das Problem jetzt
behoben.
@DirkB
Dass du mir nicht direkt gesagt dass ich den Eingabestream leeren muss,
dann hätte ich das auch eher kapiert :-(
Kurze Frage hierzu, ist es sinnvoll wenn man etwas Einliest, am Ende
oder im Fehlerfall dem Eingabestream zu leeren? Oder ist das generell
nötig? Auch wenn man sowas wie scanf oder so benutzt?
Gruß
Hallo Müller,
schön, dass du dich für das Progammieren mit C interessierst. :-)
Falls Du Interesse hast, hier ein paar Kommentare:
(1) Schau dir mal die Beschreibung von fgets() genau an. Was passiert
bei
- EOF (^D,^D^D oder ^Z)
- einer Zeichenkette mit EOF
- einer Zeichenkette mit Return
- einer Zeichenkette mit 20 oder mehr Zeichen und EOF
- einer Zeichenkette mit 19 oder mehr Zeichen und Return
(2) Die Wirkung von fflush(stdin) ist im Standard nicht definiert. Wenn
es bei dir macht was du willst (alle "offenen" Zeichen in stdin
löschen), ist das nicht portabel. Bei "mir" funktioniert das bspw.
nicht.
(3) "Komplizierte" Ausdrücke vermeiden.
Das ist nicht "falsch", aber was passiert da eigentlich genau?
(4) Du hast dir "bool" mit "true" und "false" definiert. Warum, wenn du
true und false gar nicht benutzt?
Grüße, mikro
S. J. schrieb:> (4) Du hast dir "bool" mit "true" und "false" definiert. Warum, wenn du> true und false gar nicht benutzt?
Und warum überhaupt selber definieren? Ein #include <stdbool.h> sollte
reichen.
Hallo zusammen,
1) mach ich morgen mal in aller Ruhe
2) was wäre denn Standard? fseek(stdin,0,SEEK_END) ?
3) ich find das nicht kompliziert.
Wenn jemand AWL kennt, wäre das wie:
U(
O e ist Zahl?
O e ist Buchstabe?
)
UN e ist Kein Leerzeichen
Also es darf kein Leerzeichen sein und ( es darf eine Zahl sein oder ein
Buchstabe ). Habe es nicht eingesehen gleich 3 Abfragen zu bauen.
4) naja damit man auf Anhieb sehen kann, dass es eine boolsche Funktion
ist.
Lieben Gruß
Hallo,
> 2) was wäre denn Standard? fseek(stdin,0,SEEK_END) ?
Nein.
Ich kenne leider keinen einfachen und zuverlässigen Weg einen
Input-C-File-Stream nicht-blockierend und platformunabhängig
(Win/DOS/Linux) zu "flushen".
Vielleicht kennt ja hier jemand solch eine Möglichkeit.
> 3) ich find das nicht kompliziert.
Das ist ok. Aber denk dran, dass vielleicht auch andere deinen Quelltext
lesen.
Und was wäre denn wenn man den letzten Teil der Bedingung (!isspace(c))
wegläßt und statt dessen...
1
if(isdigit(c)||isalpha(c))continue;
> 4) naja damit man auf Anhieb sehen kann, dass es eine boolsche Funktion> ist.
Gut. Ich selbst würde dann auch false und true statt 0 und 1 benutzen.
Grüße, mikro
Müller schrieb:> ich habe das Programm nun angepasst und eine Abfrage eingefügt, in der> abgefragt wird, ob das Newline vorhanden ist(checkEingabe) und prüfe> auch die Zeichenlänge. Jedoch bleibt weiterhin das Problem bestehen,> dass wenn ich absichtlich mehr als 20 Zeichen eingebe, dass dies zu> undefinierten Verhalten führt, weil die Variablen dann noch gespeichert> bleiben...
Sheeva P. schrieb:> fflush(stdin);>> ist Dein Freund. ;-)
Ist für input streams nur leider undefiniertes Verhalten.
Wenn man 'Glück' hat, klappt es auf bestimmten Systemen, aber drauf
verlassen sollte man sich nicht...
Müller schrieb:> erstmal danke für die Hinweise. Habe das erstmal umgesetzt. Wie gesagt> die Open-MP Sache, ist nur eine Spielerei. Die wird ja wohl nicht dafür> verantwortlich sein, dass es nicht so recht funktioniert, denke ich.
"Premature optimization is the root of all evil." (Donald E. Knuth:
"Computer Programming as an Art", 1974)
Erstens: das Programm verbringt mindestens 99,9% seiner Laufzeit damit,
auf auf Benutzereingaben zu warten, die naturgemäss nicht parallelisiert
werden können. Die übrigen 0,1% des Programms durch Parallelisierung
beschleunigen zu wollen, ist, vorsichtig gesagt, Quatsch.
Zweitens erzeugt eine Parallelisierung zunächst einen Overhead, der
durch das Verwalten der Prozesse, Threads oder Microthreads entsteht.
Wenn Du so einfache und winzige Teile Deines Programmes parallelisierst,
übersteigt dieser Overhead jeden Gewinn bei Weitem.
Es wäre nicht schlimm, wenn Deine Optimierung einfach nur unsinnig wäre.
Daß sie kontraproduktiv und Dein Programm stattdessen komplizierter und
ineffizienter machen: das ist schlimm.
Auch in einem anderen Kontext ist OMP hier kontraproduktiv, denn
immerhin bist es ja Du, der hier nach Unterstützung sucht -- und der
deswegen die Aufgabe hat, das Problem möglichst genau und unkompliziert
darzustellen, damit andere sich das anschauen.
S. J. schrieb:> (2) Die Wirkung von fflush(stdin) ist im Standard nicht definiert. Wenn> es bei dir macht was du willst (alle "offenen" Zeichen in stdin> löschen), ist das nicht portabel. Bei "mir" funktioniert das bspw.> nicht.
Entschuldige bitte, aber was für eine Plattform ist denn das dort bei
Dir, wo das nicht funktioniert?
Zu mal man von OpenMP die Finger lassen sollte bevor man C richtig
verstanden hat. Man muss schon sehr genau wissen was da passiert welche
Variablen auf dem Stack / Heap liegen welche geshared werden müssen
welche es auf keinen Fall dürfen. Ansonsten führt OpenMp nur zu falschen
Ergebnissen oder ist sehr viel langsamer als sequentieller Code.
Sheeva P. schrieb:> Laut [1] ist "fflush(stdin)" in POSIX.1-2008 definiert. Was nicht> definiert ist, ist "fflush()" (ohne Parameter).>> [1] http://man7.org/linux/man-pages/man3/fflush.3.html
For input streams associated with seekable files (e.g., disk files,
but not pipes or terminals), fflush() discards any buffered data that
has been fetched from the underlying file, but has not been consumed
by the application.
Hallo zusammen,
Wenn ich später mal Zeit habe, werde ich die OMP Sachen heraus nehmen.In
dem Kontext macht es natürlich wenig Sinn, da habt ihr recht :) Ich
fange im Prinzip damit an, damit ich im Laufe des nächsten Jahres, wenn
wir quasi darin(bis zum Ende des Schuljahres) ein kleines Projekt machen
müssen, vorbereitet bin. Ich wollte dann irgendwann einen Taschenrechner
Parser machen.
Zum Thema Leerung:
fflush(stdin) ist unter Windows zulässig und sollte funktionieren, Msvrt
unterstützt das wohl...
fseek(stdin,0,seek_end) funktioniert auch unter Windows.
Bei Linux soll wohl fpurge(stdin) klappen.
Da wir in der Schule eh nur Window 7 Rechner haben und ich persönlich
Windows 8, nehme ich weiterhin fflUsh(stdin).
Es sei denn es gibt etwas was zu 100% funktioniert. Und Standard ist,
Dieses snippet:
1
Intc;
2
While(c=getchar()!='\n'&&c!=EOF);
Soll wohl auch leeren, aber das versteh ich nicht ganz, was passiert da
genau?
Es wird so lange eingelesen bis newline und EOF kommt, aber was entleert
den stdin dann?!
Da wird doch nix entleert?!
Vielen Dank
Gruß
rüdiger schrieb:> Sheeva P. schrieb:>> fflush(stdin);>>>> ist Dein Freund. ;-)>> Ist für input streams nur leider undefiniertes Verhalten.
Ergibt ja eigentlich auch keinen Sinn. fflush() dient dazu, den Inhalt
des internen Puffers an sein Ziel rauszuschreiben. Bei Input-Streams ist
das Ziel aber dein Programm. Den Pufferinhalt zu verwerfen ist
eigentlich eine andere Funktionalität.
> Es sei denn es gibt etwas was zu 100% funktioniert. Und Standard ist,> Dieses snippet:> Int c;> While(c = getchar() != '\n' && c != EOF);> Soll wohl auch leeren, aber das versteh ich nicht ganz, was passiert da> genau?>> Es wird so lange eingelesen bis newline und EOF kommt, aber was entleert> den stdin dann?!>> Da wird doch nix entleert?!
Warum nicht? Warum sollte ein Zeichen beim Lesen nicht aus dem Puffer
entfernt werden?
Finde es schon ein bisschen komisch, dass man den input-buffer eines
c-file-streams nicht portabel löschen kann, ohne zu blockieren. Da gibt
es auch haufenweise matches im Web. Sehr irritierend. :-(
S. J. schrieb:> Finde es schon ein bisschen komisch, dass man den input-buffer eines> c-file-streams nicht portabel löschen kann, ohne zu blockieren. Da gibt> es auch haufenweise matches im Web. Sehr irritierend. :-(
Das liegt einfach daran, daß es auch Betriebssysteme gibt, bei denen
diese Puffer vor dem Programm verborgen sind und wo das Programm keinen
Einfluss darauf hat. Man hat dort einfach keine Möglichkeit, den
Puffer-Inhalt zu löschen. Aber auch dafür soll es möglich sein, einen
konformen C-Compiler zu schreiben.
Es gibt (und gab seit Erfindung von C) ja schließlich noch ein paar mehr
Systeme neben Linux und Windows.
Rolf M. schrieb:> Das liegt einfach daran, daß es auch Betriebssysteme gibt, bei denen> diese Puffer vor dem Programm verborgen sind
Naja, der C-File-Stream (FILE) ist Teil der C-Lib und nicht Teil des BS.
Er könnte also immer von der Lib geflushed (gelöscht) werden.
Das jenseits des System Interfaces liegende Terminal, Pipe, Socket, File
(whatever) wird im nächsten Schritt interessant. (Da kann man ggf.
select/poll auf den FD des FILEs anwenden).
S. J. schrieb:> Rolf M. schrieb:>> Das liegt einfach daran, daß es auch Betriebssysteme gibt, bei denen>> diese Puffer vor dem Programm verborgen sind>> Naja, der C-File-Stream (FILE) ist Teil der C-Lib und nicht Teil des BS.
FILE (und stdin) ist nur ein Frontend für die Funktionalität des
Betriebssystems.
> Das jenseits des System Interfaces liegende Terminal, Pipe, Socket, File> (whatever) wird im nächsten Schritt interessant. (Da kann man ggf.> select/poll auf den FD des FILEs anwenden).
Aber das ist dann eben nicht mehr portabel.
Hallo zusammen,
ich habe mein Programm etwas "optimiert", ihr werdet es eh
auseinanderreißen, aber egal =)
Kleine Sache noch:
Wenn ich über fflush oder fseek leere, kann ich auch STRG+D,Z,\n
eingeben, da arbeitet er anstandslos weiter. Wenn ich nur über dieses
Snippet leere, dann macht muss ich nach einer Eingabe von diesen Zeichen
oder mehr als 20 Zeichen, nochmal eine Taste drücken, damit die
Programmausfürhung weitergeht.
Lieben Gruß
Rolf M. schrieb:> FILE (und stdin) ist nur ein Frontend für die Funktionalität des> Betriebssystems.
Meinst Du buffered I/O? Als "Frontend" kann man jede Funktion
bezeichnen. Ist nicht falsch. Bringt aber auch nicht viel. ;-)
Aja, und die buffered I/O wird durch die C-Lib bereitgestellt, oder
siehst du das anders?
>> Das jenseits des System Interfaces liegende Terminal, Pipe, Socket, File>> (whatever) wird im nächsten Schritt interessant. (Da kann man ggf.>> select/poll auf den FD des FILEs anwenden).>> Aber das ist dann eben nicht mehr portabel.
Man kommt zumindest mit POSIX C ohne curses aus. Das ist ja schon was.
Mit IONBF klappt das dann auch.
Müller schrieb:> Achja der Code:Müller schrieb:> Hier der angepasste Code:
Zur Schonung von Mouse-Rädern und sonstigen Navigationshilfen gibt es
hier im Forum extra die Funktion "Dateianhang". Die ist wie geschaffen
für längeren Code und verschont diejenigen mit nicht gewünschtem
Lesestoff, die erstmal die Beiträge lesen möchten. ;-)
> Soll wohl auch leeren, aber das versteh ich nicht ganz, was passiert da> genau?
Es entfernt² die aktuelle Zeile aus dem Eingabestrom.
²wenn ein Zeichen gelesen wird, steht es nicht mehr im Eingabestrom. Es
ist also daraus entfernt.
Das fflush(stdin) entfernt (wenn es funktioniert) alle bisher
eingegebenen Zeichen. Auch mehrere Zeilen.
Man sollte dabei bedenken, dass auch eine Umleitung der Ein/Ausgabe
mittels Pipe möglich ist.
Da macht ein fflush(stdin) wenig Sinn.
Müller schrieb:> ich habe mein Programm etwas "optimiert", ihr werdet es eh> auseinanderreißen, aber egal =)
Weil das fflush(stdin) auf Win wohl funzt, würde ich die beiden
Alternativen weg lassen. Es sei denn Du hast es durchgetestet und weißt
wann fflush() fehlschlägt, wann fseek fehlschlägt() und dass dann die
getc() Schleife das Problem löst. Hast du dafür ein Testszenario?
Ansonsten, nur fflush().
Als Argument für die Funktion zur Fehlerausgabe würde ich statt eines
Typs eher die Zeichenkette mit der Diagnose an die Funktion übergeben.
Der Typ macht es nur komplizierter und bringt keine Vorteile (zumindest
hier in diesem Fall).
Welchen speziellen Fall löst du mit... ?
1
if(length==1&&!isalnum(string[0]))returnfalse;
Zum Vergleich von Zeichenketten gibt es die strcmp() Funktion. (Das
"Problem" mit dem '\n' läßt sich einfach lösen.)
Folgendes ist doppelt gemoppelt
...weil du in checkEingabe() ebenfalls auf NULL prüfst.
Ich mag das verschachtelte Konstrukt nicht:
1
if(a)
2
if(b)
3
if(c)
4
if(d)
5
...
6
else
7
...
8
else
9
...
10
else
11
...
12
else
13
...
Ich hatte mal einen Entwickler der hat das über mehrere hundert LOC
getrieben. Schrecklich. [sic]
So, das fällt mir so auf Anhieb auf. Zum Aufhübschen. Du hast es so
gewollt! ;-)
Grüße, mikro
Hallo,
Ich kann sagen das fflush auf meinem Rechner daheim funktioniert bei w8.
Aber nicht bei anderen Versionen, deswegen einfach zur Sicherheit.
Zu dem Einlesen, du hast recht.
Zu der anderen Geschichte, wenn die eingelesene String nur 1 Element
hat, soll er nicht extra in die for Schleife reinspringen.
Ob ich die Abfragen verschachtele oder alles in Funktionen auslagere,
spielt doch keine Rolle?! Außerdem finde ich das so besser lesbarer, ich
hab ja schon Probleme dein Program vernünftig nachvollziehen zu können
:) da wäre eine Art Beiblatt mit ablaufdiagramm echt nützlich. Erst
recht wenn ich mir hier so manche Sachen anschaue, wo Leute wirklich
jede Mini Operation in eine Funktion ausgelagern ;) schrecklich :)
Herzlichen Dank, werde morgen mal weiter korrigieren.
Gruß
Müller schrieb:> Ob ich die Abfragen verschachtele oder alles in Funktionen auslagere,> spielt doch keine Rolle?!
Mir geht es um Lesbarkeit.
Wenn da viele if sind und ich für jedes if das else suchen muss, wird
der Code schlecht lesbar (und dadurch fehleranfällig). Häufig bieten
sich statt dessen early returns an.
Grüße, mikro
beric schrieb:> Müller schrieb:>>> // ErweiterteFunktion um 2 Strings unterschiedlicher Größe zu vergleichen>> bool checkEqual(char *string1, const char *string2)>> Wegschmeißen und strcmp() benutzen.
... und statt dessen diese Funktionalität
in eine Funktion zusammenfassen, die
* mittels fgets eine Eingabe holt
* ein eventuell vorhandenes Newline aus der Eingabe entfernt
* überprüft ob die Eingabe nicht leer oder sonst irgendwie ungültige
Zeichen enthält.
PS: Du willst deinem Benutzer keinen Hinweis geben, ob jetzt der
Benutzername oder doch das Password falsch ist. Entweder beide sind
richtig, dann wird er akzeptiert oder eines von beiden ist falsch und er
kriegt eine in beiden Fällen gleiche Fehlermeldung. Denn du willst einem
blind probierendem keinen Hinweis geben, dass er jetzt zufällig einen
gültigen Benutzernamen erraten hat.
Müller schrieb:> Zu der anderen Geschichte, wenn die eingelesene String nur 1 Element> hat, soll er nicht extra in die for Schleife reinspringen.
Ganz ehrlich.
Machs erst mal richtig und kümmere dich dann um Optimierungen.
So oft wie du strlen aufrufst, ... da ist erst mal jegliche sogenannte
Optimierung vollkommen für die Würscht.
> Ob ich die Abfragen verschachtele oder alles in Funktionen auslagere,> spielt doch keine Rolle?!
Doch tut es. Nicht für den Rechner, aber für den Programmierer, der das
alles irgendwann nicht mehr nachvollziehen kann.
> Außerdem finde ich das so besser lesbarer
Was ist an
1
....
2
3
AccountDataValid=FALSE;
4
do{
5
// auf Benutzereingabe warten,
6
// feststellen ob sie gültige Zeichen enthielt war und
jetzt besonders unleserlich?
Denk dir ein paar Füllwörter wie zb Artikel und sonstigen Kleinkram
dazu, dann steht da mehr oder weniger im Kartext, was an dieser Stelle
im Code passiert.
Hallo zusammen,
ich habe noch ein paar Aktualisierungen vorgenommen, u.a. den Main Loop
etwas "übersichtlicher" gestaltet, denke ich. Außerdem habe ich die
Passwort Eingabe mit Sternchen versehen.
Nochmal kurz zur Info:
Es soll darauf hingewiesen werden, dass Nutzer ODER Passwort falsch
sind, ebenso soll darauf hingewiesen werden, falls die Eingabe ansich
nicht korrekt ist(nur Zahlen und Buchstaben erlaubt).
checkEqual habe ich verworfen, und mache jetzt alles in getNutzername
und getPasswort, ich denke dass ist jetzt doch übersichtlicher oder?!
checkEingabe besteht weiterhin, ich denke das ist ok, oder?
@Karl Heinz
Dein Vorschlag ist toll, aber dann kann ich ja direkt bei 0 anfangen ;(
@Alle
Ich habe nicht vor später als Softwerker zu arbeiten =) Wie gesagt ich
mache meinen Techniker in Elektrotechnik/Automatisierungstechnik auf
Abendschule. Es interessiert mich nur.
Vielen Dank für die Hilfe, weiterhin ist Kritik erwünscht ;)
Lieben Gruß
Müller schrieb:> @Karl Heinz>> Dein Vorschlag ist toll, aber dann kann ich ja direkt bei 0 anfangen ;(
Ja, das soll vorkommen, wenn man sich selbst in die Ecke programmiert
hat.
Mach dir nichts draus. Ist uns am Anfang allen so gegangen. Sieh es mal
so: Wer mit einer Tätigkeit anfängt, kann nicht erwarten von Anfang an
gleich alles einigermassen richtig zu machen. Das macht nichts.
Entscheidend ist, dass man daraus lernt. Niemand von uns ist zur Welt
gekommen und hat bei einer Problemstellung von Anfang an intuitiv die
Richtung eingeschlagen bei der er
a) sich selbst das Leben möglichst einfach macht
b) auf Anhieb sieht, welche Aufteilung in Funktionen sinnvoll ist
c) gleichzeitig eine leicht lesbare Codeform erhält
Gerade am Anfang hängt auch viel daran, dass man auch experimentiert,
wie diverse Änderungen den Code an sich verändern; ob er einfacher wird;
ob er komplexer wird; ob er leichter lesbar wird, etc. ...
Und ganz ehrlich: soooo umfangreich ist das, was du bisher hast nun auch
wieder nicht. Das ist schnell geändert und so wie das aussieht, kannst
du die Übung gut gebrauchen.
Karl H. schrieb:
...
Also, für einen C-Einsteiger, der freiwillig für sich selbst eine
zusätzliche Aufgabe gesucht hat, fand ich das nicht übel. Nachgefragt
und umgesetzt. Dass das nicht optimal ist, damit kann ich leben. Habe in
der Berufswelt weit schlimmere Sachen gesehen.
S. J. schrieb:> Karl H. schrieb:> ...>> Also, für einen C-Einsteiger, der freiwillig für sich selbst eine> zusätzliche Aufgabe gesucht hat, fand ich das nicht übel.
Full Ack: Absolut nicht. So war das auch nicht gemeint.
Jetzt muss er nur noch das typische Neuling-'Problem' ablegen: einmal
geschriebener Code ist in Stein gemeisselt und wird auf keinen Fall
geändert.
Hallo zusammen,
ich werde mal schauen, ob ich heute mich hinsetze und nochmal von vorne
anfange. Ich muss noch etwas anderes für die Schule fertig machen.
Momentan sind ja Ferien und ich hab Urlaub, deswegen bin ich da rel.
Flexibel ;)
Ich habe da noch ein paar Fragen:
- Mirko du verwendest in Deiner Musterlösung mehrmals
statischefunktionen, welchen Vorteil bringt das im Bezug auf das
Program? ( soll das vor externen Zugriffen schützen? )
- Du benutzt überhaupt kein printf, warum?? Die kann doch nicht unsicher
sein oder? Die gibt's doch auch bestimmt bei Linux
- dieses Poll gibt's bei mir gar nicht, zumindestens meckert mein GCc
wenn ich versuche die einzubinden.
- was ist das überhaupt? Klingt für mich frei übersetzt wie Umfrage ;)
Ich benutze codeblocks als Editor und als linker und Compiler aber das
GCc von devcpp, fragt nicht warum, devcpp kompiliert Mir Programme, die
in nem segfault enden, auch wenns nur hallo World ist.
Gruß
S. J. schrieb:> Ich kenne leider keinen einfachen und zuverlässigen Weg einen> Input-C-File-Stream nicht-blockierend und platformunabhängig> (Win/DOS/Linux) zu "flushen".
Ich weiß nicht, wie Du darauf kommst, dass fflush(stdin) unter Linux den
Input blockt oder Dir bei Redirection den Input zerstört.
S. J. schrieb:> Rolf M. schrieb:>> Das liegt einfach daran, daß es auch Betriebssysteme gibt, bei denen>> diese Puffer vor dem Programm verborgen sind>> Naja, der C-File-Stream (FILE) ist Teil der C-Lib und nicht Teil des BS.> Er könnte also immer von der Lib geflushed (gelöscht) werden.
Das Problem liegt darin, dass es in C kein Terminal und keine Tastatur
gibt. In C wird alles als Stream angesehen, egal was da dahinter steckt.
Ausgabeseitig ist es noch recht einfach einen flush anzuleiern. Es
werden einfach alle Output Buffer geleert und einer möglicherweise
dahinter stehenden Hardware übermittelt. Egal was die dann damit macht.
Aber eingabeseitig ist das nicht so einfach. Denn auf eine UART hast du
kaum einen Einfluss. Während die Softwarebuffer geleert werden trudelt
schon das nächste Zeichen ein. Was soll mit dem geschehen? Wie verhalten
sich Tastaturbuffer, die in Terminals verbaut sind? Selbiges mit
Netzwerk.
Daher geht C den kleinsten gemeinsamen Nenner und definiert fflush nur
für Ausgabestreams. Ob und wie ein fflush auf einen Eingabestream wirkt,
das wird vom C Standard weder definiert noch gefordert.
Frank M. schrieb:> $ cc fflush.c -o fflush && ./fflush> Input:> abc> abc> $ cat hello.txt> Hello, World> $ ./fflush <hello.txt> Input:> Hello, World> [/pre]
Wie genau unterscheidet sich dieses Verhalten jetzt davon, dass fflush
nichts tut? Das ist mit diesem Test nämlich nicht erkennbar.
Karl H. schrieb:> Wie genau unterscheidet sich dieses Verhalten jetzt davon, dass fflush> nichts tut? Das ist mit diesem Test nämlich nicht erkennbar.
Es tut auch nichts. Wenn ich eingebe:
1
$ sleep 5; ./fflush
2
abc
3
Input:
4
abc
5
def
6
def
... dann wird "abc" ebenso ausgegeben, obwohl ich es vor dem Aufruf von
fflush(stdin) eingegeben habe. Der Input wird also nicht geleert.
Es ging mir nur um die falsche Aussage, dass fflush(stdin) den Input
blockieren (bei Terminal) bzw. den Inhalt leeren (bei Redicretion) soll.
Das stimmt so nicht, denn es tut unter Linux.... einfach nichts! :-)
Unter Unix/Linux muss man da mit termios bzw. ioctl() dran. Dann geht
das sicher.
Frank M. schrieb:> Es ging mir nur um die falsche Aussage, dass fflush(stdin) den Input> blockieren (bei Terminal) bzw. den Inhalt leeren (bei Redicretion) soll.> Das stimmt so nicht, denn es tut unter Linux.... einfach nichts! :-)
OK.
Dann blasen wir ins selbe Horn.
Das Verhalten von fflush ist nicht garantiert. Auf deinem System tut es
nichts, auf so manchem Windows System macht es das gewünschte.
Dazwischen liegt noch eine weite Spanne, was sonst noch so alles
passieren könnte.
Frank M. schrieb:> Ich weiß nicht, wie Du darauf kommst, dass fflush(stdin) unter Linux den> Input blockt oder Dir bei Redirection den Input zerstört.
Habe ich nicht behauptet.
> S. J. schrieb:>> Ich kenne leider keinen einfachen und zuverlässigen Weg einen>> Input-C-File-Stream nicht-blockierend und platformunabhängig>> (Win/DOS/Linux) zu "flushen".
Nur der Vollständigkeit halber: So gehts unter Linux:
1
$ cat fflush.c
2
#include <stdio.h>
3
#include <termios.h>
4
#include <unistd.h>
5
6
int
7
main (void)
8
{
9
int ch;
10
11
(void) tcflush (fileno(stdin), TCIFLUSH);
12
13
puts ("Input:");
14
15
while ((ch = getchar ()) != EOF)
16
{
17
putchar (ch);
18
}
19
20
return 0;
21
}
22
$ cc fflush.c -o fflush && ./fflush
23
Input:
24
abc
25
abc
26
def
27
def
28
$ sleep 5; ./fflush
29
abc
30
Input:
31
def
32
def
Hier wird der Input ("abc"), der vor dem tcflush()-Call eingetippt
wurde, vorher gelöscht und daher auch nicht wieder ausgegeben.
Trotzdem geht der Input bei Redirection nicht verloren:
1
$ ./fflush <hello.txt
2
Input:
3
Hello, World
Das ist natürlich alles Unix-/Linux-spezifisch. Mit select() bekäme man
auch noch eine portable Lösung hin, die unter Unix/Linux und Windows
laufen würde. Aber lohnt das den Aufwand?
Karl H. schrieb:> Das Problem liegt darin...
Ist klar. Das von mir "geforderte" flush hat sich (erstmal) nur auf den
buffer in der C-Lib bezogen.
-> Beitrag "Re: C - Char array löschen"Karl H. schrieb:> Daher geht C den kleinsten gemeinsamen Nenner und definiert fflush nur> für Ausgabestreams. Ob und wie ein fflush auf einen Eingabestream wirkt,> das wird vom C Standard weder definiert noch gefordert.
Nicht ganz.
Für seekable files ist es in POSIX.1-2008 definiert.
-> Beitrag "Re: C - Char array löschen" (hilft beim
Terminal aber nicht)
> ... Mit select() bekäme man auch noch eine portable Lösung hin,> die unter Unix/Linux und Windows laufen würde...
Denke eher nicht.
-> Beitrag "Re: C - Char array löschen"
S. J. schrieb:>> ... Mit select() bekäme man auch noch eine portable Lösung hin,>> die unter Unix/Linux und Windows laufen würde...>> Denke eher nicht.> -> Beitrag "Re: C - Char array löschen"
Viel zu kompliziert, wo hast Du denn den Source aufgetrieben?
Hier Lösung mit select():
Frank M. schrieb:> Viel zu kompliziert, wo hast Du denn den Source aufgetrieben?
Im Sinne der Aufgabenstellung des TS.
> Hier Lösung mit select():
Das ist ohne Benutzung des C-file-streams (STDIN).
Auslesen/Select auf den FD klappt, das ist klar.
> You could also use direct> non-blocking file descriptor access (poll/read) -- and don't use the> stdin-file-stream at all.
Unter Windows habe ich in Erinnerung (lange ist's her) das Anonymous
Pipes benutzt werden, die nicht asynchron gelesen werden können.
S. J. schrieb:> Das ist ohne Benutzung des C-file-streams (STDIN).
Du meinst den stdio filepointer stdin - um mal bei der Unix-Sprache zu
bleiben.
> Auslesen/Select auf den FD klappt, das ist klar.
Den fd holt man sich portabel mit fileno(stdin), siehe oben. Ich habe
KEIN fd=0 benutzt.
Frank M. schrieb:> Den fd holt man sich portabel mit fileno(stdin), siehe oben. Ich habe> KEIN fd=0 benutzt.
...und hast zum Lesen nicht den "stdio filepointer stdin" benutzt.
Das Problem, dass im C-Lib buffer des "stdio filepointer stdin" noch
character liegen können, hast du also gar nicht abgehandelt.
S. J. schrieb:> Das Problem, dass im C-Lib buffer des "stdio filepointer stdin" noch> character liegen können, hast du also gar nicht abgehandelt.
Da ist was dran. Vor dem ersten getchar() kann jedoch kein Zeichen im
stdio buffer liegen. ;-)
Es bleibt jedenfalls dabei, was Karl Heinz, Du und ich auch schon
sagten: man kann den stdio Input-Buffer nicht leeren.
Ich habs übrigens eben mal unter Windows mit fflush(stdin) ausprobiert:
Es funktioniert (im Gegensatz zu dem oben behaupteten) auch NICHT unter
Windows. Getestet mit Microsoft Visual C++ 2010 Express.
Im Helpfile meines Compilers (Watcom C) steht:
"If the file fp is open for output or update, the fflush function causes
any unwritten data to be written to the file. If the file fp is open
for input or update, the fflush function undoes the effect of any
preceding ungetc operation on the stream. If the value of fp is NULL,
then all files that are open will be flushed."
Joachim D. schrieb:> If the file fp is open> for input or update, the fflush function undoes the effect of any> preceding ungetc operation on the stream.
Okay, das ist aber nicht, was hier generell gewünscht wird. In der
Watcom-Beschreibung geht es darum, ein per ungetc() zurückgestelltes
Zeichen vom input-Buffer zu nehmen.
Nicht gerade das, was man in der Regel braucht ;-)
Hallo,
Könnte man nicht den Eingabebuffer nicht "umleiten"? Quasi ich definiere
in Meinem Programm eine Char buffer, sage dann über setbuf(stdin,
persönlicherbuffer), und wenn ich leeren will dann Buffer über memset
löschen? Gehts das theoretisch? Bin grad nicht am Rechner, sonst würde
ich es mal probieren.
Hruß
Müller schrieb:> Könnte man nicht den Eingabebuffer nicht "umleiten"?
Kann sein. Aber irgendwann kommst Du auch dahinter, dass die stdio-lib
für Console-Input/Output gar nicht so geeignet ist und wirst nach
Alternativen schauen.
Müller schrieb:> habe es mal getestet, scheint zumindestens bei zu funktionieren...
Zwei Sachen habe ich anzumerken:
1
>#include<stdio.h>
2
>
3
>intmain()
4
>{
5
>...
6
>charbuffer3[BUFSIZ];
Wichtig: Der Buffer muss über die Lebenszeit von main() hinaus
existieren. Das hat damit zu tun, dass exit() je nach Betriebssystem
noch mit dem Buffer arbeitet.
Daher:
1
staticcharbuffer3[BUFSIZ];
Sieht zwar in diesem Kontext komisch aus, ist aber notwendig.
Auszug aus der Dokumentation dazu:
"You must make sure that the space that buf points to still exists by
the time stream is closed, which also happens at program termination."
1
>// Ausgabe
2
>printf("Buffer 1: %s\n",buffer1);
3
>printf("Buffer 2: %s\n",buffer2);
4
>}
Hier fehlt ein "return 0;" am Ende.
Deshalb sieht man so willkürliche Zahlen bei Dir:
Process returned 19 (0x13) execution time : 8.782 s
bzw.
Process returned 16 (0x10) execution time : 31.111 s
Frank M. schrieb:> Hier fehlt ein "return 0;" am Ende.>> Deshalb sieht man so willkürliche Zahlen bei Dir:>> Process returned 19 (0x13) execution time : 8.782 s>> bzw.>> Process returned 16 (0x10) execution time : 31.111 s
5.1.2.2.3 Program termination
[…] reaching the } that terminates the main function returns a value of
0. […]
apr schrieb:> Frank M. schrieb:>> Process returned 19 (0x13) execution time : 8.782 s>> Process returned 16 (0x10) execution time : 31.111 s>> 5.1.2.2.3 Program termination> […] reaching the } that terminates the main function returns a value of> 0. […]
Das mag für C11, C99 und C++ gelten, sonst aber nicht. Wie anders
möchtest Du die willkürlichen Return-Werte 19 bzw. 16 erklären?
Frank M. schrieb:> Das mag für C11, C99 und C++ gelten, sonst aber nicht. Wie anders> möchtest Du die willkürlichen Return-Werte 19 bzw. 16 erklären?
Das liegt aber doch an dem Compiler, den du verwendest. Wenn der so
alt ist, dass er nicht einmal C99 kennt, kannst du das in diesem Fall
nicht dem Quellcode anlasten. Selbst der MS-Compiler macht hier keine
Probleme, obwohl der bei C nicht gerade immer ... ganz up-to-date ist
(Euphemismus).
Trotzdem ist "return 0" natürlich besser (besonders, wenn man ansonsten
gar keine C99 oder C11-Features verwendet).
@Müller
Ich habe mir den Code nicht im Detail angesehen, aber mir sind ein paar
Kleinigkeiten aufgefallen:
1. Du schreibst zu viele Kommentare dieser Art:
// Variablen
int zeichen;
// Länge 0?
if(length < 1)
// Länge 1?
if(length == 1
// Weiterzählen
counter++;
Das steht ja alles schon da.
2. Benutze anstelle von "8", "13" etc. besser Konstanten.
// Schleifendurchlauf Bei ENTER beenden
while((zeichen = getch()) != 13)
{
// Wurde backspace gedrückt && vorher ein Zeichen eingegeben?
if(zeichen == 8 && counter > 0)
{
Auch auf den ersten Kommentar könnte man dann verzichten. Wenn statt
"counter" ein spezifischerer Name verwendet werden würde, auch gleich
auf den zweiten.
3. Kleiner "Trick" (ist aber nicht auf meinem Mist gewachsen)
nutzername[strcspn(nutzername, "\n")] = '\0';
bzw.
nutzername[strcspn(nutzername, "\r\n")] = '\0';
Müller schrieb:> Erst recht wenn ich mir hier so manche Sachen anschaue, wo Leute wirklich> jede Mini Operation in eine Funktion ausgelagern ;) schrecklich :)
Wir reden hier doch über prozedurale Programmierung ... ;-)
Ich hätte gar kein Problem damit, z.B.
void removeNewline(char* buffer)
{
buffer[strcspn(buffer, "\n")] = '\0';
}
zu schreiben, wenn der Code dadurch lesbarer wäre und/oder die Funktion
mehrmals benutzt werden würde.
BTW: Die Gesamtstruktur deines Programms sieht inzwischen deutlich
besser aus als in der ersten Version, da ist auch mal ein Lob
angebracht.
Frank schrieb:> Frank M. schrieb:>> Das mag für C11, C99 und C++ gelten, sonst aber nicht. Wie anders>> möchtest Du die willkürlichen Return-Werte 19 bzw. 16 erklären?>> Das liegt aber doch an dem Compiler, den du verwendest.
Nein, die Return-Werte hat der TO gepostet.
Und ich meine herausgelesen zu haben, dass TO unter Windows seine
Sources kompiliert.
> Wenn der so> alt ist, dass er nicht einmal C99 kennt, kannst du das in diesem Fall> nicht dem Quellcode anlasten. Selbst der MS-Compiler macht hier keine> Probleme, obwohl der bei C nicht gerade immer ... ganz up-to-date ist> (Euphemismus).
Soviel ich weiß, kann der MS-Compiler kein C99. Und erst recht kein C11.
> Trotzdem ist "return 0" natürlich besser (besonders, wenn man ansonsten> gar keine C99 oder C11-Features verwendet).
Eben, damit bricht man sich keinen Zacken aus der Krone.
Frank M. schrieb:> Nein, die Return-Werte hat der TO gepostet.
Hatte ich übersehen (war bei dir auch nicht "gequotet").
> Soviel ich weiß, kann der MS-Compiler kein C99.
Doch, neuerdings schon - zumindest größtenteils:
"However, with the introduction of Visual C++ 2013 Microsoft implemented
a limited subset of C99, then Visual C++ 2015 achieved a level of the
C99 standard compliance that is similar to other C compilers."
https://en.wikipedia.org/wiki/C99
Müller schrieb:> Hallo zusammen,>> ich hab mich jetzt nochmal hingesetzt, und neu angefangen. Wie findet> ihr es?>> Lieben Gruß
Sry kleiner Fehler drinne gehabt: