Hallo zusammen,
ich möchte Euch mal mein kleines Projekt vorstellen, das ich mir zur
Prüfungsvorbereitung entsprechend dem Inhalt der Informatik Teil 1
Vorlesung heute Nachmittag zusammengebaselt habe.
Das Programm umfasst einen Buchstabenzähler, der die Anzahl der
Großbuchstaben und Kleinbuchstaben erfasst.
Eine Funktion zur Inversion von Wörtern.
Und schließlich noch ein kleines Buchstabensuchspiel, das in einem
eingegebenen Wort einen gewünschten Buchstaben sucht und ausgibt an
welcher Stelle im Wort sich dieser befindet.
Das Programm ist durch ein kleines Hauptmenü gesteuert, mit dem sich
alle Funktionen nacheinander aufrufen lassen und das Programm auch
beenden kann.
Ich hoffe, ein paar Anregungen zu meinem Programmierstil, Verbesserungen
und sonstige Ratschläge zu erhalten.
Außerdem soll es ein paar "Neueinsteigern" dienen, die sich mit der
Sprache C befassen und Anregungen suchen.
Nur zur Info. Das Programm wurde mit MS Visual Studio 2010 erstellt.
MfG
Manuel
Ich hätte noch ein paar Kommentare eingefügt. Vor allem über den
Funktionen.
Kurze Beschreibung, was die Funktion macht und welche Parameter
übergeben werden.
Kritik:
a. deine Variablen sind nich selbsterklärend. Ich hätte da schon keinen
Bock mehr zu lesen.
b. Du verwendest magische Nummern. Das zerstört die Lesbarkeit komplett.
printf("Der %d. Buchstabe ist ein %c\n", i+1, *p_such);
Was bedeutet "+1"?
c. Warum sind die Strings statisch?
char eingabe[20]; //Buchstabensuchspiel-Eingabewort
char suche; //Buchstabensuchspiel-Suchbuchstabe
char wortzaehl[30]; //Buchstabenzählspiel
char wortinv[30]; //Wortversion
Nicht mehr als 20 Buchstaben? Ich wuerde mit malloc() oder welches sich
auch immer anbietet, dynamisch allozieren.
d. Das hier ist Frickelcode
if((*(p_wort+i)<=175)&&*(p_wort+i)>=41)
Pointer, Additionen, Vergleiche.. what!? Code soll sich selbst
erklaeren, das tut er nicht.
Hätte ich den Code Reviewen müssen, hätt dich dir eine dicke Rechnung um
die Ohren geschlagen für das Leid das man ertragen musste.
Viel scheint ja in der Vorlesung nicht rumgekommen zu sin.
* system("cls") ist blöd weil Windows/DOS,
* system("pause") auch
* ctype.h mit isupper() und islower() sind schon erfunden,
* Arrays indiziert man nicht mit *() sondern mit []...
Gibt es eigentlich ein C-Lernbuch das sich irgendwie im Stil an
"Accelerated C++" orientiert?
Das Lernsystem dort ist ziemlich genial:
Bevor man sich an die Implementierungsdetails wagt, wird ohne
Hinterfragen die Funktionen aus den Standard-Bibliotheken verwendet.
Erst zum Schluss beginnt man diese von Hand nachzuimplementieren.
Kritik an der Kritik
atmeltierchen schrieb:> Kritik:>> a. deine Variablen sind nich selbsterklärend. Ich hätte da schon keinen> Bock mehr zu lesen.
Das passt eigentlich soweit. Ich hatte damit keine Probleme.
> b. Du verwendest magische Nummern. Das zerstört die Lesbarkeit komplett.>> printf("Der %d. Buchstabe ist ein %c\n", i+1, *p_such);>> Was bedeutet "+1"?
Wenn man sich die paar Codezeilen anschaut, dann versteht man es auch.
> c. Warum sind die Strings statisch?>> char eingabe[20]; //Buchstabensuchspiel-Eingabewort> char suche; //Buchstabensuchspiel-Suchbuchstabe> char wortzaehl[30]; //Buchstabenzählspiel> char wortinv[30]; //Wortversion>> Nicht mehr als 20 Buchstaben? Ich wuerde mit malloc() oder welches sich> auch immer anbietet, dynamisch allozieren.
Kann man ruhig so lassen, aber auch anders lösen
> d. Das hier ist Frickelcode>> if((*(p_wort+i)<=175)&&*(p_wort+i)>=41)>> Pointer, Additionen, Vergleiche.. what!? Code soll sich selbst> erklaeren, das tut er nicht.
Daneben steht ein Kommentar. Das ist verständlich
> Hätte ich den Code Reviewen müssen, hätt dich dir eine dicke Rechnung um> die Ohren geschlagen für das Leid das man ertragen musste.
Dazu sag ich mal nix...
Wenn Du nach Groß-/Kleinbuchstaben prüfst, dann kann man auch islower()
und isupper() verwenden.
scantf() ist zwar schön und gut, aber kann einen Überlauf erzeugen. Das
würde ich anders lösen.
Erst mal Dankeschön für die schnellen Antworten
Nase schrieb:> Arrays indiziert man nicht mit *() sondern mit []...
Arrays haben ja []. Bei den Pointern in den Unterfunktionen muss ich ja
dann *() nehmen, da es ja nur auf die Anfangsadresse der Arrays zeigt.
Alternativen zu den system-Befehlen kenne ich leider bisher noch nicht
,da in der Vorlesung immer nur die von mir verwendeten genutzt werden.
atmeltierchen schrieb:> c. Warum sind die Strings statisch?
Der Grund, wieso sie statisch sind, liegt darin, dass dynamische
Speicherverwaltung erst im 2. Semester vorgetragen wird und ich daher
noch keinen Dunst davon habe.
Dies hier ist ja kein Softwareprojekt für ein Programm, mit dem Geld
verdient werden soll, sondern lediglich ein Spiegelbild meiner
Fähigkeiten, die ich nun nach einem Semester Informatik an einer
Fachhochschule gesammelt habe.
Dass ich mehr hätte kommentieren müssen ist mir jetzt im Nachhinein auch
bewusst geworden.
atmeltierchen schrieb:> b. Du verwendest magische Nummern. Das zerstört die Lesbarkeit komplett.
Die magischen Nummern entsprechen in aller Regel ASCII-Codes. Die 1, die
Du mir ankreiden würdest, soll heißen, dass "n" bei der Ausgabe "der n.
Buchstabe" richtig berechnet wird. Das erste Zeichen im Array hat die
[0], wobei in meiner Ausgabe eine 1 statt 0 stehen soll.
mar IO schrieb:> Wenn Du nach Groß-/Kleinbuchstaben prüfst, dann kann man auch islower()> und isupper() verwenden.>> scantf() ist zwar schön und gut, aber kann einen Überlauf erzeugen. Das> würde ich anders lösen.
Das mit dem scanf()-Problem könnte ich anders lösen, erschien mir aber
auf dem ersten Blick am verständlichsten, aber die Funktionen islower()
und isupper() habe ich bisher noch nicht gekannt.
Der Inhalt meiner Informatik Vorlesung ist ohnehin etwas mager, da es
nur ein Nebenfach darstellt. Funktionen die über die von mir im Programm
verwendeten hinausgehen kommen erst in den nächsten Semestern.
atmeltierchen schrieb:> Ich will nicht nur kritisieren, sondern auch einmal schönen Code zeigen.
Dankeschön für die Anregung ;)
Die Links werde ich mir wohl dann gleich mal zu Gemüte führen.
Ich weiß, dass mein Programm wenig übersichtlich gestaltet wurde, da ich
a) kaum "richtigen" Code gesehen habe, der sich auf Höhe meiner
Fähigkeiten befindet und
b) in meiner Vergangenheit mit Mikrocontrollern immer nur richtigen
"Wildschweincode" produziert habe und ich mich jetzt erst langsam davon
abgewöhnen kann
Manuel schrieb:> Arrays haben ja []. Bei den Pointern in den Unterfunktionen muss ich ja> dann *() nehmen, da es ja nur auf die Anfangsadresse der Arrays zeigt.
Aha. Und wo hast du das her?
Du hast C-Strings nicht verstanden.
Ein C-String ist beim Zeichen mit dem Wert 0 zu Ende ('\0')
Du überprüfst alle Zeichen vom Array. Das können auch mehr sein als du
eingegeben hast.
Das ist falsch.
Zudem ist deine Buchstabensuche auf 30 Zeichen fixiert und dein Zaehler
auf 50. Das ist großer Mist.
Dein Array zum Suchen ist auch nur 30 Zeichen lang. Das ist gefährlich.
Und entweder Arrayschreibweise oder richtig mit Zeigern
Nase schrieb:> Aha. Und wo hast du das her?
Ein Zeiger zeigt logischerweise auf die Adresse einer Variablen.
Verwende ich ein Array ist die Anfangsadresse die des ersten Zeichens
des Arrays z.B ptr=&char[0] ist das gleiche wie ptr=char .
Beim Dereferenzieren gehe ich dann eben genauso vor.
Dirk B. schrieb:> Zudem ist deine Buchstabensuche auf 30 Zeichen fixiert und dein Zaehler> auf 50. Das ist großer Mist.> Dein Array zum Suchen ist auch nur 30 Zeichen lang. Das ist gefährlich.
Zefix, das hab ich ja völlig übersehen... Sehr guter Kritikpunkt!
Manuel schrieb:> Nase schrieb:>> Aha. Und wo hast du das her?>> Ein Zeiger zeigt logischerweise auf die Adresse einer Variablen.> Verwende ich ein Array ist die Anfangsadresse die des ersten Zeichens> des Arrays z.B ptr=&char[0] ist das gleiche wie ptr=char .> Beim Dereferenzieren gehe ich dann eben genauso vor.
Ja, und was spricht nun dagegen, die von allen C-Programmierern weltweit
seit über 40 Jahren praktizierte Array-Indizierung mit eckigen Klammern
zu verwenden?
Manuel schrieb:> Nase schrieb:>> Aha. Und wo hast du das her?>> Ein Zeiger zeigt logischerweise auf die Adresse einer Variablen.> Verwende ich ein Array ist die Anfangsadresse die des ersten Zeichens> des Arrays z.B ptr=&char[0] ist das gleiche wie ptr=char .> Beim Dereferenzieren gehe ich dann eben genauso vor.
Und
1
*( a + i )
ist in C in allen Punkten identisch zu
1
a[i]
Ganz im Gegenteil: die Indexoperation ist sogar exakt genau so
definiert.
Tatsächlich wandelt daher der Compiler intern die Form a[i] als
allererstes erst mal in die Form *(a+i) um. Alles was du also mit deiner
komplexen Schreibweise gemacht hast ist, dem Compiler ein bischen Arbeit
zu ersparen. Programmtechnisch bzw. an dem was hinten raus kommt, ändert
sich dadurch aber nichts.
Damit könntest du
1
if((*(p_zaehl+i)<='Z')&&*(p_zaehl+i)>='A')
in der völlig gleichwertigen Form
1
if(p_zaehl[i]<='Z'&&p_zaehl[i]>='A')
formulieren und damit schon mal einiges an visueller Komplexität aus dem
Code herausnehmen.
Aber eigentlich bevorzugt man als C-Programmierer die Form, in der
komplett ohne Indexvariable gearbeitet wird, so wie Dirk das in seiner
'buchstabenzaehler' zeigt. Warum? Ganz einfach. Wenn man keinen Index
hat, muss man sich auch nicht über den Datentyp einer derartigen
Indexvariablen Gedanken machen (der korrekt eigentlich ein size_t wäre).