C Programmierung: Char Array mit For-Schleife füllen und auslesen?

2 Antworten

Was hast Du denn da eigentlich für 'ne Plattform? Irgendwas Linux-ähnliches?

Dein Hauptproblem könnte sein, dass Du sowieso mal in ein buffering-Problem der stdio reinläufst. D. h. Du kannst gar nicht zeichenweise lesen, sondern bekommst das ganze schon vom System her zeilenweis angeliefert.

Siehe auch setbuf() auf der libc-Ebene einerseits, und "man 3 termios" andererseits.

Wenn Du zeichenweise einlesen willst, solltest Du auf libc-Ebene Buffering abschalten, auf Terminalebene CBREAK-Modus setzen. Und nicht vergessen, das nachher wieder rückzusetzen!

Der fflush() in der Schleife drin ist übrigens kontraproduktiv und sorgt in Deiner derzeitigen Implementierung dafür, dass Eingabe verloren gehen kann.

Hi,

lass mal das void bei der main weg, man muss das nicht explizit sagen, ich verstehe auch nicht ganz warum du den string initial füllst, es reicht doch zu sagen, dass du Speicher für 6 chars allokieren willst, zudem braucht ein char string auch immer ein Stringendezeichen ('\0'), bei der Vorschleife würde er vollgeschrieben werden.

Und allgemein, das Passwort muss jetzt ja immer genau 6 chars lang sein, verkürzen z.B. mit Leertaste geht bei scanf auch nicht...

Ich habe dir mal ein kleines Skript geschrieben, das besser funktionieren sollte:

char *passwort;
int i=0;
char eingabe;

printf("Bitte Passwort eingeben: ");
passwort=calloc(1, sizeof(char));

while((int)eingabe!=13){
eingabe=getche();
fflush(stdin);
passwort[i]=eingabe;
i++;
passwort=(char*)realloc(passwort, i+1);
}
passwort[i]='\0';

printf("\nPasswort: %s\n", passwort);
return 0;

Ich weiß nicht wie weit du mit c fortgeschritten bist, falls du etwas nicht verstehst, einfach fragen.


KolnFC  04.06.2017, 00:12

Also, im Prinzip, du erstellst einen String mit Pointer (*passwort), allokierst über calloc 1 Bit (1, sizeof(char)) und läufst dann in eine while Schleife mit der Endbedingung 'enter' (13 ist der ASCI Wert für enter, deshalb den char 'eingabe' als (int) gecastet in der Bedingung).

mit jeden Schleifendurchgang beschreibst du jetzt den String und erweiterst den Speicher mit realloc immer jeweils um den Durchgang plus eins für das Stringendezeichen (i+1).

Das "passwort[i]='\0'" braucht man nicht unbedingt, das sollte der Kompiler selber machen, ich habe das nur zur Sicherheit gesetzt.

Wenn du jetzt noch Bedingungen möchtest, kannst du sie einfach in if Bedinungen packen (z.B. if((int)eingabe=32){} für Eingabe von Leerzeichen oder if(i>=6){} für ein zu langes Passwort etc.).

1
TeeTier  04.06.2017, 04:31

lass mal das void bei der main weg, man muss das nicht explizit sagen, ...

Leider nicht ganz richtig! Die Main Funktion (die ja genau genommen keine Funktion ist, aber das nur am Rande ...) ist als eine von beiden folgenden Varianten definiert:

int main(void);
int main(int, char **);

Einige Compilerhersteller erlauben auch noch Konstrukte wie:

void main(void);
int main(int, char**, char**);
int main(int, char**, char**, char**);

... aber die sind teils plattformspezifisch und nicht portabel.

Um auf deinen Einwand zurück zu kommen:

void foo();

... ist etwas anderes als:

void foo(void);

Denn erstere Funktion kann man (abhängig vom jeweiligen C-Standard) mit einer beliebigen Anzahl von Argumenten aufrufen, letztere hingegen nicht. (Bei C++ ist das aber wiederum anders, aber hier geht es ja nicht um C++!)

ich verstehe auch nicht ganz warum du den string initial füllst, es reicht doch zu sagen, dass du Speicher für 6 chars allokieren willst, ...

Darüber kann man durchaus geteilter Meinung sein. Ich würde das Char-Array ebenfalls wie der Fragensteller initialisieren, aus Gründen der strikten defensiven Programmierung. Dann natürlich mit '\0' und nicht '0', aber ich denke, das war nur ein Tippfehler vom Fragensteller.

Es sei denn, es gibt sehr sehr gute Gründe - wie z. B. Performance - dafür, dies nicht zu tun, aber die liegen hier ja nicht vor.

zudem braucht ein char string auch immer ein Stringendezeichen ('\0'), bei der Vorschleife würde er vollgeschrieben werden.

Da hast du evtl. Recht, falls der Fragensteller tatsächlich einen Tippfehler gemacht hat. Natürlich sollte man mit '\0' initialisieren. Durch diese Initialisierung - die du ja teilweise zu Recht im vorigen Absatz bemängelt hast - wäre sichergestellt, dass das Passwort immer mit einem Null-Character abschließt, sofern denn tatsächlich '\0' gemeint wäre. :)

Und allgemein, das Passwort muss jetzt ja immer genau 6 chars lang sein,

Nein, muss es nicht. Es darf maximal 5 Zeichen lang, kann aber auch leer sein. :)

Ich habe dir mal ein kleines Skript geschrieben, das besser funktionieren sollte: ...

Ein Skript ist eigentlich etwas anderes, aber davon abgesehen ist ein realloc in einer Schleife - und dann auch noch mit nur einem einzigen weiteren Byte als Größe - ein absolutes No-Go, zumal jegliche Fehlerbehandlung fehlt.

Warum nicht einfach auf dem Stack ...

#define BUFSZ 256
char buf[BUFSZ] = {0};

... anlegen, und die maximale Passwort-Länge auf (BUFSZ - 1) festlegen? Dabei entfällt die Notwendigkeit jeder Fehlerbehandlung, er Code ist deutlich kürzer und übersichtlicher und - auch wenn das hier kaum eine Rolle spielt - deutlich performanter, da nicht bei jedem Schleifendurchlauf das Speichermanagement bemüht werden muss. :)

Das "passwort[i]='\0'" braucht man nicht unbedingt, das sollte der Kompiler selber machen, ich habe das nur zur Sicherheit gesetzt.

Nein, das ist sogar unbedingt notwendig. Wieso sollte der Compiler ein '\0' anfügen? Das wird er dir nicht abnehmen! :)

1
Maddin337 
Fragesteller
 04.06.2017, 09:39
@TeeTier

Super gute Antworten! Die erste finde ich schon sehr gut und bei der 2. kommt noch bissle mehr Detail mit ins Spiel! Ich werde das in Ruhe mal durchgehen. Doch eine Frage hätte ich: Warum klappt das nicht so, wie ich es vor hatte? Klar, ihr habt recht. Ich hätte direkt auch am Anfang passwort[5]='\0' machen sollen. Aber mit meinem Programm kann ich auch nur 3 durchlaufen und ist fertig. Ich hatte auch schon mit passwort[i]=_getche() gearbeitet aber das wollte nicht so recht funktionieren. Ich wollte im Anschluss diesen eingegeben String dann mit einem anderen String mit der Funktion strcmp (Bibliothek: string.h) vergleichen aber da war kompletter Abschuss. Habt ihr da ne Idee?

1
michiwien22  05.06.2017, 09:58
@Maddin337

wenn du eine Eingabe mit "Enter" abschließt, was bedeutet das denn? *ggg*

Klar, dass du dann nach 3 Eingaben fertig bist. ;-)

0