Eigene Zeichenkettenbearbeitungsfuntion -> Endlosschleife



  • Hallo,

    ich habe ein kleines Programm zu Übungszwecken geschrieben, das mithilfe einer eigens geschriebenen Funktion einen eingegeben Satz insofern bearbeitet, dass das Vorhandensein eines während des Ablaufs definierten Buchstabens untersucht.

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int anzahl(char satz[],char x,int bin) {
    	int anzahl=0,i;
    	char y,wahl;
    
    	if(bin != 0 && x>64 && x<91 || bin != 0 && x>96 && x<122) {
    		do {
    			printf("Zwischen Klein- und Großbuchstaben unterscheiden? [J]a oder [N]ein:\n> ");
    			wahl=getchar();
    		} while(wahl != 'J' || wahl != 'N');
    	}
    
    	if(wahl=='J') {
    		if(x>64 && x<91)
    		y=tolower(x);
    		else if(x>96 && x<122)
    		y=toupper(x);
    		for(i=0;i<strlen(satz);i++) {
    			if(satz[i]==x)
    			anzahl++;
    			}
    	}
    
    	else{
    		for(i=0;i<strlen(satz);i++) {
    			if(satz[i]==x || satz[i]==y)
    			anzahl++;
    			}
    	}
    
    	return(anzahl);
    }
    
    main() {
    	char test[81],satz[81],x;
    
    	do {
    		printf("\nBitte einen Satz eingeben (max. 80 Zeichen):\n> ");
    		gets(test);
    		if(strlen(test)<=80)
    		strcpy(satz,test);
    	}while(strlen(test)>80);
    
    	printf("Bitte den Buchstaben definieren:\n> ");
    	x=getchar();
    
    	int ergebnis=anzahl(satz,x,1);
    	printf("\nDer Satz \"%s\" enthaelt %i Mal den Buchstaben \"%c\".\n",satz,ergebnis,x);
    	double prozent=100/strlen(satz)*ergebnis;
    	printf("Der Buchstabe \"%c\" hat einen prozentualen Anteil von %.2lf %% am Satz.\n",x,prozent);
    }
    

    Der erste Teile, also Eingabe eines Satzes und Buchstabens, funktioniert einwandfrei. Dann gibt es jedoch eine Endlosschleife, es wird mich ständig gefragt, ob ich zwischen Groß- und Kleinschreibung unterscheiden möchte.

    Der hierfür verantwortliche Programmteil:

    if(bin != 0 && x>64 && x<91 || bin != 0 && x>96 && x<122) {
    		do {
    			printf("Zwischen Klein- und Großbuchstaben unterscheiden? [J]a oder [N]ein:\n> ");
    			wahl=getchar();
    		} while(wahl != 'J' || wahl != 'N');
    	}
    

    Eine andere Frage nebenbei:

    Ich habe eine Abfrage eingebaut, die überprüfen soll, ob der eingegebene Satz die Zeichengrenze von 80 Zeichen überschreitet. Leider habe ich das Problem, dass ich die Zeichenkette erst in einem Zeichenfeld fester Größe schreiben muss; ich würde nur ungern ein Array mit einer festen, im höheren Bereich liegenden Größe definieren und hier durch unnötig Speicher verschwenden. Wie kann ich das also variabel gestalten ?

    do {
    		printf("\nBitte einen Satz eingeben (max. 80 Zeichen):\n> ");
    		gets(test);
    		if(strlen(test)<=80)
    		strcpy(satz,test);
    	}while(strlen(test)>80);
    


  • Zur ersten Frage: Was gibst du denn als Antwort auf diese Frage ein? Die Schleife erwartet entweder ein großes J oder ein großes N - keine Kleinbuchstaben.

    Zur zweiten Frage: Bei der String-Verarbeitung mußt du vorher wissen, wie groß der erwartete String sein wird - aber eventuell kannst du mit fgets() und realloc eine Routine zusammenbauen, die die Eingabe etappenweise liest und stückweise immer mehr Speicher anfordert.

    Ansonsten:
    - verwende lieber char-Literale anstelle der numerischen Werte für die ASCII-Codes (noch besser ist natürlich isalpha() und Co.)
    - die Variable y wird im if(wahl=='J') Zweig mit einem Wert gefüllt, aber im else Zweig für Vergleiche genutzt
    - verwende besser keine Funktionen, die Strings einlesen ohne eine Maximalgröße angeben zu können (das betrifft hier besonders gets(): wenn die Eingabe zu lang ist, überschreibst du Daten außerhalb deines Arrays - das könnte das benachbarte Array 'satz' sein, aber auch die Rücksprungadresse der Funktion)



  • Danke für die schnelle Antwort 🙂

    Manche deiner Tipps kann ich leider nur teilweise nachvollziehen, einfach weil ich noch Anfänger bin und manche Dinge nicht kenne, aber vielleicht werde ich das später einmal verwerten können 😉

    Zur ersten Frage: Unabhängig davon, was ich eingebe (J oder N oder einen anderen beliebigen Buchstaben), wird wieder und wieder die gleiche Frage gestellt.

    Zum Rest:
    - Inwiefern sollte ich die dezimal notierten ASCII-Codes ersetzen?
    - Welche Funktion könnte gets ersetzen, die vorher überprüft, ob der eingegebene Satz die Arraygröße übertrifft?
    - Ich habe nicht feststellen können, wo ich y in einem Vergleich nutze. Kannst du mir eine genaue Zeile nennen?

    lg



  • NP1 schrieb:

    Zur ersten Frage: Unabhängig davon, was ich eingebe (J oder N oder einen anderen beliebigen Buchstaben), wird wieder und wieder die gleiche Frage gestellt.

    Stimmt, das hatte ich übersehen - die Abbruchbedingung ist ja immer wahr - außer du findest ein Zeichen, das sowohl 'J' als auch 'N' ist. Setz dort lieber ein && rein (logisch und)

    - Inwiefern sollte ich die dezimal notierten ASCII-Codes ersetzen?

    Ich habe die ASCII-Tabelle jetzt nicht sicher im Kopf, aber afair entspricht 64..91 isupper(), 96..122 islower - und beide zusammen kannst du mit isalpha() überprüfen.

    if(bin != 0 && x>64 && x<91 || bin != 0 && x>96 && x<122)
    ->
    if(bin != 0 && isalpha(x))
    

    - Welche Funktion könnte gets ersetzen, die vorher überprüft, ob der eingegebene Satz die Arraygröße übertrifft?

    fgets() - das bricht mit dem Einlesen ab, wenn die übergebene Größe erreicht ist.

    - Ich habe nicht feststellen können, wo ich y in einem Vergleich nutze. Kannst du mir eine genaue Zeile nennen?

    in Zeile 18 bzw. 20 wird ein Wert eingetragen, in Zeile 29 steht der Vergleich.



  • Hey,

    danke, es funktioniert 😉

    Eine letzte Frage zum Programm:

    Die Ausgabe sieht immer wie folgend aus:

    Zwischen Klein- und Großbuchstaben unterscheiden? [J]a oder [N]ein:
    > Zwischen Klein- und Großbuchstaben unterscheiden? [J]a oder [N]ein:

    Weshalb druckt er den Fragesatz doppelt?

    lg



  • NP1 schrieb:

    - Inwiefern sollte ich die dezimal notierten ASCII-Codes ersetzen

    Du machst das doch schon bei while(wahl != 'J' || wahl != 'N');

    So kannst du statt x > 64 besser x >= 'A' schreiben.
    Das ist portabler (es gibt noch was anderes als ASCII) und besser lesbar.

    Du kannst damit auch rechnen.

    printf("%c\n", 1+'0'); //gibt eine '1' aus
    

    NP1 schrieb:

    Weshalb druckt er den Fragesatz doppelt?

    Weil von deinem x=getchar(); das Newline noch im Tastaturpuffer ist.
    Das wird zuerst mit dem wahl=getchar(); gelesen.



  • NP1 schrieb:

    Weshalb druckt er den Fragesatz doppelt?

    Du hast immer noch nicht verstanden, dass eine auf deine (fehlerhafte) Art abgefragte Standardeingabe diese so hinterlässt, dass folgende Eingabeabfragen fehlerhaft arbeiten werden.
    Baue dir statt =getchar() bzw. gar gets() was besseres, z.B.:

    char liesEinZeichen()
    {
      char s[BUFSIZ];
      fgets( s,BUFSIZ,stdin );
      return *s;
    }
    

    und

    const char *liesString()
    {
      static char s[BUFSIZ];
      fgets( s,BUFSIZ,stdin );
      if( strchr(s,'\n') ) *strchr(s,'\n')=0;
      return s;
    }
    

    Die sind zwar auch noch nicht ganz optimal, sollten aber für dich erstmal reichen.



  • Wutz schrieb:

    Baue dir statt =getchar() bzw. gar gets() was besseres, z.B.:

    const char *liesString()
    {
      static char s[BUFSIZ];
      fgets( s,BUFSIZ,stdin );
      if( strchr(s,'\n') ) *strchr(s,'\n')=0;
      return s;
    }
    

    Super, dann kann ich mein getline endlich durch etwas einfacher handzuhabendes ersetzen.



  • Danke, das meiste habe ich soweit verstanden. Entschuldigt, wenn einiges noch nicht "optimal" ist, aber ich arbeite ein Buch, das einen guten Einstieg ermöglichen soll durch, und bei manchen Dingen bin ich einfach noch nicht so weit bzw. ich habe auch einiges einfach wie gelernt übernommen, bspw. getchar() oder gets(). Aber zu Übungszwecken ist es ja, wie ich finde, auch in Ordnung.

    lg



  • Wenn dein Buch gets empfiehlt/verwendet, ist es Schrott und die Wahrscheinlichkeit, dass es noch mehr Schrott enthält, groß.



  • Sehr wage Theorie. Das Buch ist nun mal für Einsteiger und ich muss zugeben, an manchen Stellen ist es womöglich qualitativ minderwertig oder zu kurz erläutert. Im Großen und Ganzen finde ich jedoch, dass es der Autor schafft, die Grundlagen gut verständlich zu erklären (ich rede übrigens von http://www.amazon.de/C-Programmieren-Anfang-Helmut-Erlenkötter/dp/3499600749/ref=pd_sim_b_3, das ich auf die erstaunlich vielen guten Bewertungen der anderen Kunden kaufte). Insofern denke ich, dass ich das vermittelte Wissen durch jenes aus anderen Quelle ergänze, vertiefe und gar korrigiere, aber dass ich mich darauf einlassen muss war mir bereits im Vorneherein klar, so dass diese Tatsache kein Problem für mich darstellt 😉 (Übrigens kann es auch sein, dass der Autor vorsieht, die bessere Alternative zu gets, also fgets bspw., an einer anderen, später auftretenden Stelle zu erwähnen, aber wie erwähnt, soweit bin ich noch nicht, kann ja dann berichten. Übrigens findet sich auch ein Hinweis im Buch zur Gefahr des Überschreibungs der gets-Funktion, abgesehen davon, dass jeder mit gesundem Menschenverstand daran denken sollte, gerade wenn er diesen Hinweis liest, dass er gets() nicht in einem "echten" Programm verwenden sollte.)



  • Das ist keine Theorie sondern allgemeiner Wissensstand in der C Programmierung, d.h. also Praxis. Das hat sich sogar bis zu der Truppe, die sich mit einem neuen C Standard C1X befasst, herumgesprochen: es steht zur Debatte, gets aus dem Standard herauszunehmen. Und wenn du noch Anfänger bist, solltest du dich doch mit Mutmaßungen darüber, was richtig und sinnvoll ist, zurückhalten. Nach jahrelanger Praxis reift bei dir dann vielleicht auch die Erkenntnis.
    Vage schreibt man übrigens vage und nicht wage und das ist ebenso keine Theorie sondern Praxis und sogar Standard.



  • NP1 schrieb:

    Sehr wage Theorie. Das Buch ist nun mal für Einsteiger und ich muss zugeben, an manchen Stellen ist es womöglich qualitativ minderwertig oder zu kurz erläutert. Im Großen und Ganzen finde ich jedoch, dass es der Autor schafft, die Grundlagen gut verständlich zu erklären (ich rede übrigens von http://www.amazon.de/C-Programmieren-Anfang-Helmut-Erlenkötter/dp/3499600749/ref=pd_sim_b_3, das ich auf die erstaunlich vielen guten Bewertungen der anderen Kunden kaufte). Insofern denke ich, dass ich das vermittelte Wissen durch jenes aus anderen Quelle ergänze, vertiefe und gar korrigiere, aber dass ich mich darauf einlassen muss war mir bereits im Vorneherein klar, so dass diese Tatsache kein Problem für mich darstellt 😉 (Übrigens kann es auch sein, dass der Autor vorsieht, die bessere Alternative zu gets, also fgets bspw., an einer anderen, später auftretenden Stelle zu erwähnen, aber wie erwähnt, soweit bin ich noch nicht, kann ja dann berichten. Übrigens findet sich auch ein Hinweis im Buch zur Gefahr des Überschreibungs der gets-Funktion, abgesehen davon, dass jeder mit gesundem Menschenverstand daran denken sollte, gerade wenn er diesen Hinweis liest, dass er gets() nicht in einem "echten" Programm verwenden sollte.)

    Das Du es bis hier geschafft hast, also irgendein Buch lesen und dann ein größeres Programm selber entwerfen, schreiben, testen, entwanzen, liegt nicht am Buch, sondern an Dir. Das ist deine Leistung nicht die des Authors. Du hättest das auch mit einem schnöden Tut in pdf Form hinbekommen.

    Wenn Wutz auf das Thema allergisch reagiert, ist das nicht Deine Sorge und erst recht kein Vorwurf gegen Dich. Wenn Du beim Programmieren, unter Verwendung von ich sage mal fragwürdigen Standardfunktionen, einen vermeintlichen Fehler zum 1000sten mal debuggen darfst, bis du feststellst das es effektiver ist die Funktion selber zu schreiben, wirst Du irgendwann genauso denken. Und sollte Dir Programmieren Spaß machen und Du Dich damit weiter befassen, garantiere ich Dir, das dieser Fall eintreten wird.

    Programmiersprachen werden ja nicht von Göttern sondern von Menschen ersonnen, die ebenfalls gerne mal Fehler machen.

    Deine Fortschritte sind okay, kein Grund sich zu entschuldigen.

    Keep on hacking 😃



  • @Wutz: Verstehe mich bitte nicht falsch, ich wollte nicht sagen, dass ich es besser als du wissen würde, das ganz sicher nicht. Wie sollte ich denn auch 😉 Ich wollte nur sagen, dass ich das Buch aus Sicht eines Anfängers insofern gut finde, dass es einen guten Einstieg ermöglicht, da es das Wissen verständlich vermitteln kann. Außerdem habe ich ja auch angemerkt, dass ich sicher mit der Zeit mein Wissen und meine Erfahrung erweitern und selbst zu Erkenntnissen kommen werde, die es mir ermöglichen, ein Problem anders, womöglich besser zu lösen. Danke auch für die Korrektur, wieder etwas gelernt (bezogen auf vage) 😉

    @forenseeker: Danke für die Ermutigung 😉 Ich sehe das genauso wie du 😉


Anmelden zum Antworten