Zeichenketten Verarbeitung hilfe



  • Hallo zusammen,
    ich sitze gerade an einem Programm, welches eine Zeichenkette einlesen soll, die Zeichenkette umdreht und dann wieder ausgibt, wenn dies dann so klappt wie ich es mir vorstelle,soll noch geprüft werden, ob es sich um ein Palindrom handelt.
    Leider funktioniert mein Programm nicht so wie gewünscht und ich hoffe hier, dass mir jemand weiterhelfen kann.
    mein Code:

    #include<stdio.h>
    #include<string.h>
    #include<ctype.h>
    
    void klein(char *zk)
    {
    	int laenge = strlen(zk)-1;
    	int counter = 0;
    
    	while (*zk)									  //macht jeden Buchstaben nacheinander klein
    	{
    
    		*zk = tolower(*zk);
    		zk++;
    
    	}
    
    	for (; laenge+1 >= counter; counter++) {		//setzt den Zeiger auf die Anfangsadresse
    		zk--;	
    	}
    
    	return;
    }
    void umdrehen(char *wort, char *uwort) {
    
    	char *indexvorne = uwort;
    	char *indexhinten = wort + strlen(wort) - 1;
    	int f = 0;
    
    	for (; f <= strlen(wort) - 1; f++) {			
    		*indexvorne = *indexhinten;
    		indexhinten--;
    		indexvorne++;
    	}
    	*indexhinten = '/0';							//Zeiger ende
    	return;
    }
    
    int main() {
    
    	char wort[20], wortu[20];
    	int lange;
    
    	scanf("%s", &wort);
    	lange = strlen(wort);
    
    	klein(wort);
            printf("wort klein: %s",wort);
    	umdrehen(wort, wortu);
    
    	printf("wort:%s und wortumgedreht ist: %s\n", wort, wortu);
    
    }
    

    Folgende Probleme habe ich jedoch bei meinem Programm:

    1. Das Programm wird ausgeführt, jedoch bekomme ich ein Runtime error, woran das liegt kann ich nicht finden.

    2. Die Ausgabe meines Programmes (http://www.fotos-hochladen.net/view/wortumdrehen2a9wgu67nf.png)
    ist eigentlich richtig, nur warum wird mir wortumgedreht nicht richtig angezeigt?

    Ich hoffe, dass mir jemand weiterhelfen kann.


  • Mod

    Der erste Fehler ist beim scanf. Du übergibst den falschen Typen (%s erwartet char* , du übergibst char(*)[20] ) und nimmst keine Sicherung gegen Überläufe vor.

    In Zeile 37 kommst du durcheinander, welche deiner Variablen wofür steht. Ist vielleicht ein Zeichen, dass deine Bezeichner nicht so toll gewählt sind.

    Andere Schwächen des Programms:
    -Die Einrückung ist nicht einheitlich, daher schwer zu lesen.

    -Niemals strlen in einer for-Schleifenprüfung benutzen! Mag zwar sein, dass ein guter Compiler dies optimieren kann, aber im Allgemeinen ist strlen eine super-teure Funktion; die willst du möglichst nur einmal ausführen, so lange das Ergebnis sich nicht andern kann.

    -Überhaupt wimmelt das Programm vor lauter strlens, deren Ergebnis nicht einmal genutzt werden. Es ist durchaus ok, sich auf die Nullterminierung zu verlassen, anstatt mit strlen zu arbeiten. strlen macht auch nix anderes als die Nullterminierung zu suchen. Deine Zeilen 11-17 sind ein gutes Beispiel, wie man es richtig macht.

    -Ebenso ist Zeile 19-21 unendlich umständlich. Du hättest dir entweder den Startwert merken können oder du kannst einfach so rechnen wie in Zeile 28. Aber das ganze ist sowieso total sinnlos, zk ist eine lokale Variable. Sämtliche Änderungen da dran sind sowieso total hinfällig, sobald die Funktion vorbei ist. Also kurz: Einfach weglassen!

    -Die Bezeichner sind nicht so gut. Programmieren tut man normalerweise auf Englisch, aber ist ok, wenn das nicht deine Sache ist. Viel schwerer wiegt die Form der Namensgebung. Funktionsnamen sollten beispielsweise entweder im Imperativ stehen (wenn du betonen möchtest, dass sie etwas tun) oder im Perfekt (wenn du betonen möchtest, dass sie etwas umformen). Sei nicht knauserig mit Buchstaben. Ist es wirklich so viel Aufwand umgedrehtes_wort zu schreiben, anstatt wortu? Weiterhin sollte man einheitlich sein, mal nennst du deine Längen laenge, mal lange. Verwirrend und schwer zu lesen.
    Wenn man es gut macht, liest sich ein Computerprogramm fast so wie ein normaler Text.



  • Hey,
    erstmal vielen Dank für deine Antwort, ich habe das Program nun nochmal geschrieben und hoffe es ist jetzt besser (leserlich).

    #include<stdio.h>
    #include<string.h>
    #include<ctype.h>
    
    void wordsmall(char *word) 
    {
    
    	while (*word) 
    	{
    
    		*word = tolower(*word);
    		word++;
    	}
    
    		return;
    }
    void reverse(char*word, char*reverseword) 
    {
    
    	char* indexfront = reverseword;
    	char* indexend = word + strlen(word) - 1;
    	int length = strlen(word)-1;
    	int counter = 0;
    
    	for(;length>=counter;counter++)
    		{
    
    			*indexfront = *indexend;
    			indexfront++;
    			indexend--;
    		}
    
    	*indexfront = '/0';
    
    	return;
    }
    
    int main() 
    {
    
    	char word[20], word_reverse[20];
    	int lenght;
    
    	fgets(word, 20, stdin);
    	printf("your word: %s", word);
    
    	wordsmall(word);
    	printf("word small is: %s", word);
    
    	reverse(word, word_reverse);
    	printf("word:%s and word_reverse:%s", word, word_reverse);
    
            return(0);
    
    }
    

    Die Fehlermeldung ist nun auch verschwunden und ich werde mich wohl von scanf("%s") verabschieden und lieber fgets nutzen.

    Nun ist leider immer noch nicht das Problem mit dem umgekehrten Wort geklärt, es wird zwar richtig ausgeben, jedoch kommt nachdem Wort noch komische Zeichen (überlauf?), was mich eben wundert ist z.B bei der Eingabe "Hallo" wird es richtig umgedreht also: "ollah"jetzt folgt aber noch die /0(was ja eigentlich meine Terminierung für ende sein soll)und dann einige Komischezeichen.
    An was liegt das, wie bekomme ich das weg?



  • Das muss '\0' oder einfach 0 heißen und nicht '/0'.
    fgets liest (meistens) das '\n' der Eingabe mit in den String.



  • oh man, nur das /0 war der Fehler gewesen 😡 .
    Vielen Dank für die Hilfe, ich werde später noch die Funktion fürs Palindrom hinzufügen und dann dass gesamte Programm hochladen, vielleicht wird es ja mal einen anderen Anfänger helfen. 😃

    Edit: Hab mich nun doch für scanf entschieden, da ja fgets noch das \n einliest
    Das mit den falschen Datentyp von scanf kann ich leider nicht nachvollziehen, weil sonst ja das Programm auch nicht gehen dürfte?

    volles Programm schaut nun so aus:

    #include<stdio.h>
    #include<string.h>
    #include<ctype.h>
    
    void wordsmall(char *word) 
    {
    
    	while (*word) 
    	{
    
    		*word = tolower(*word);
    		word++;
    	}
    
    		return;
    }
    void reverse(char*word, char*reverseword) 
    {
    
    	char* indexfront = reverseword;
    	char* indexend = word + strlen(word) - 1;
    	int length = strlen(word)-1;
    	int counter = 0;
    
    	for(;length>=counter;counter++)
    		{
    
    			*indexfront = *indexend;
    			indexfront++;
    			indexend--;
    		}
    
    	*indexfront = 0;
    
    	return;
    }
    void Palindrom(char *word, char*reverseword) {
    
    	if (strcmp(word, reverseword) == 0)
    	{
    		printf("Ein Palindrom!");
    		return;
    	}
    
    		else {
    			return; 
    			 }
    
    }
    
    int main() {
    
    	char word[20], word_reverse[20];
    	int lenght;
    
    	scanf("%19s",word);
    	printf("your word: %s\n", word);
    
    	wordsmall(word);
    	printf("word small is: %s\n", word);
    
    	reverse(word, word_reverse);
    	printf("word:%s and word_reverse:%s\n", word, word_reverse);
    
    	Palindrom(word, word_reverse);
    	return(0);
    
    }
    

  • Mod

    Einfach scanf("%19s", word); . Denn der Ausdruck &word ist die Adresse von word, also ein Zeiger auf das 20-Zeichen-Array. Einfach nur word wird hingegen nach üblicher C-Konvention als ein Zeiger auf das erste Element des Arrays interpretiert, hier also auf das erste Zeichen. Entsprechend ist &word vom Typ "Zeiger auf 20-Zeichen-Array" und word vom Typ "Zeiger auf Zeichen". Letzteres ist, was scanf erwartet, wenn man mit %s liest. Die Adresse eines Arrays und die Adresse seines ersten Elements sind zwar vom Zahlenwert her gleich (daher wird es in aller Regel trotzdem funktionieren), aber logisch unterschiedliche Dinge.

    Eine Zahl zwischen einem Prozentzeichen und einem Formatspezifizierer gibt bei scanf an, wie viele Zeichen für diesen Spezifizierer maximal gelesen werden sollen. Da scanf immer auch eine Nullterminierung für Zeichenketten schreibt, muss dies mindestens ein Zeichen weniger sein als in das Zielfeld passt.

    Nur weil etwas funktioniert, heißt das nicht, dass es richtig ist und immer funktionieren wird. Erfahrungsgemäß geht es genau dann schief, wenn man es dem Lehrer vorführt 😉



  • Lavicola schrieb:

    Das mit den falschen Datentyp von scanf kann ich leider nicht nachvollziehen,

    scanf bei %s und fgets erwarten denselben Datentyp für den Speicherbereich.
    Schau dir mal an, was du bei fgets angegeben hast und was bei scanf .

    Lavicola schrieb:

    weil sonst ja das Programm auch nicht gehen dürfte?

    Da bist du aber voll auf dem Holzweg!
    C läßt viele falsche Sachen durchgehen, die (wenn man Pech hat) auch funktionieren.

    Das '/0' kann der Compiler übrigens erkennen und gibt es als Warnung an. (Wenn die Warnung erlaubt ist)



  • Vielen Dank für eure Hilfe und auch mit der Erklärung für scanf jetzt leuchtet es mir ein, danke dafür!

    Programm habe ich nochmal editiert.



  • Da das word in main ein Array ist, liefern word und &word dieselbe Adresse liefern. Darum hat das funktioniert.

    Wenn du das aber mit einem word aus deinen Funktionen machst, kommen unterschiedliche Adressen heraus, da word kein Array ist sondern ein Pointer.


Log in to reply