string arrays



  • hallo zusammen,
    ich komme bei folgender aufgabe nich weiter,
    vll kann mir jemand nen tipp geben wie ich vorgehen muss.
    hier die aufgabe:

    schreibe ein programm, das einen ganzen Satz einliest.
    gib die worte schließlich rückwärts wieder.
    verwende dazu nur char-arrays und klassische c-funktionen.

    also wenn der satz z.b. lautet: "hallo ich bin es",
    soll das programm dies wieder ausgeben: "es bin ich hallo"



  • Nimm ein Blatt Papier und spiele selber Computer.
    Nimm deine Finger als Zeiger/Index auf die aktuellen Zeichenpositionen.

    Woran erkennst du das ein neues Wort anfängt?

    Programmier dein Verfahren nach.


  • Mod

    cp schrieb:

    verwende dazu nur char-arrays und klassische c-funktionen.

    Hmm, also ohne nicht mindestens eine Kontrollstruktur oder ein paar Zeiger wird das ganz schön schwer. Aber wenn man sich auf ein paar unspezifizierte Verhaltensweisen gängiger Compiler verlässt und die Finger von den Warnoptionen lässt, dann hat die hier eine recht gute Chance, zu funktionieren:

    #include <stdio.h>
    #include <string.h>
    
    #define MAX 374
    
    int main()
    {
      char string[MAX];
      fgets(string, MAX, stdin);
      printf("%s %s %s %s\n", strtok(NULL, " "), strtok(NULL, " "), strtok(NULL, " "), strtok(string, " "));
    }
    

    Ich vermute mal, dass ich die Aufgabenstellung aber eventuell etwas zu wörtlich genommen habe 🕶 .



  • danke seppj, hab des mal kurz umgeschrieben:

    #include <stdio.h> 
    #include <string.h> 
    
    #define MAX 374 
    
    int main() 
    { 
      char string[MAX]; 
      printf( "Gib einen String ein: ");
      gets(string); 
      printf("%s %s %s %s\n", strtok(NULL, " "), strtok(NULL, " "), strtok(NULL, " "), strtok(string, " ")); 
    }
    

    könntest du mir noch erklären wie diese "strtok" genau funktioniert?
    außerdem, mit dieser printf-anweisung werden doch nur die ersten vier
    wörter des strings zurückgegeben, wie kann ich des umschreiben damit ich
    auch mehr zurückgeben kann? mit einer for-schleifen vll?


  • Mod

    Es ist ein trauriger Tag, wenn eine Scherzlösung nicht mehr als solche erkannt wird 😞 . Und dann auch noch "verbessert" wird, indem man fgets durch gets ersetzt 🙄 .

    Nein, ich werde dir die Lösung nicht erklären. In ein paar Monaten kannst du sie dir nochmal angucken. Dann verstehst du den Witz und lachst, wie du das nicht erkennen konntest.

    Wenn du nicht weißt, was Funktionen machen, dann schau in einer Referenz nach:
    http://www.cplusplus.com/reference/clibrary/cstring/
    Dies ist allgemein eine sehr gute Idee, wenn man die Zeichenkettenfunktionen aus der Standardbibliothek benutzen darf, denn da gibt es viele äußert nützliche aber unbekannte Funktionen. strtok ist sicherlich etwas, was man zu einer vernünftigen Lösung deiner Aufgabe benutzen kann. Ist in der Benutzung für Anfänger aber nicht unbedingt einfach.
    Und ja: Eine Schleife oder andere Kontrollstruktur bietet sich sehr stark an. Ich würde Rekursion benutzen, weil du damit sehr einfach eine quasi-beliebig große Stack-Struktur (Last in, first out) erzeugen kannst, mit welcher die Rückwärtsausgabe trivial wird.

    Meine Lösung demonstriert bloß, was passiert, wenn man dumm formulierte Aufgabenstellungen zu wörtlich nimmt. Strenggenommen sollte ich noch das define rausnehmen und überall von Hand einsetzen.



  • Bitte (mir war langweilig):

    #include <stdio.h>
    
    #define MAX 374
    
    unsigned int str_length(char *str) {
      unsigned int i=0;
      while(str[i]!='\0') ++i;
      return i;
    }
    
    void print_substr(unsigned int start, unsigned int end, char *str) {
      for(unsigned int i=0; i<(end-start); ++i) {
        printf("%c", *(str+start+i));
      }
    }
    
    int main()
    {
      char string[MAX];
      gets(string);
      unsigned int last_found = str_length(string);
      for(int i=str_length(string); i>=0; --i) {
        if(string[i] == ' ') {
          print_substr(i+1, last_found, string);
          printf(" ");
          last_found=i;
        }
      }
      print_substr(0, last_found, string);
      printf("\n");
    }
    

  • Mod

    @pyhax: So wie ich das verstanden habe, darf er die string.h benutzen. Vermutlich ist das sogar der Sinn der Aufgabe, dass er lernt, damit umzugehen. Keine Not, alles selber nochmal nachzuprogrammieren, auch wenn man es von vielen schlechten Hausaufgaben schon so gewohnt ist, dass es man es automatisch macht 😃 .

    Und da es schon gelöst ist, hier noch wie ich das gemacht hätte:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define MAX 374
    
    const char delimiters[] = " \n\r\t\v\f\0";
    
    void print_reverse(char *string)
    {
      char * token_pointer = strtok(string, delimiters);
      if (token_pointer)
        {
          int length = strlen(token_pointer);
          char *token = malloc(length+1);
          strcpy(token, token_pointer);
          print_reverse(NULL);
          fputs(token, stdout);
          putchar(' ');
          free(token);
        }
    }
    
    int main()
    {
      char string[MAX];
      puts("Bitte eine Zeichenkette eingeben:");
      if (fgets(string, MAX, stdin))
        {
          puts("Wörter der Zeichenkette rückwärts sind:");
          print_reverse(string);
          putchar('\n');
          return EXIT_SUCCESS;
        }
      else
        {
          puts("Fehler bei der Eingabe.");
          return EXIT_FAILURE;
        }
    }
    

    Warum ich nicht etwas einfacheres, iteratives mit strrchr baue? Ich mag strtoks Fähigkeit, mit beliebigen Trennzeichen und beliebig vielen Trennzeichen nacheinander umzugehen. Wollte man das mit den anderen Funktionen aus string.h nachbauen, würde das schnell unschön. Und man wäre schnell wieder bei Eigenbau.

    Und ich benutze 3 verschiedene Funktionen aus string.h, Übung sollte daher gegeben sein, wenn der Threadersteller diese auch nachschlägt.



  • Noch eine Frage zu deiner Lösung: Warum kopierst du in Zeile 14, 15, 16 den String? Du könntest doch einfach token_pointer als Argument für printf nehmen? (Ich programmiere eigentlich immer nur C++ :D)



  • Ich würde es wohl einfach so lösen:

    #include <stdio.h>
    #include <string.h>
    
    #define MAX 256
    
    int main()
    {
    	char eingabe[MAX];
    	char temp[MAX];
    	int i, j, k, len;
    
    	fgets(eingabe, MAX, stdin);
    
    	len = strlen(eingabe);
    
    	for (i = len-1, j = 0; i >= 0; --i)
    	{
    		if (eingabe[i] == '\n')
    		{
    			continue;
    		}
    		else if (eingabe[i] != ' ' && i > 0)
    		{
    			temp[j++] = eingabe[i];
    		}
    		else
    		{
    			if (i <= 0)
    				temp[j++] = eingabe[i];
    
    			temp[j] = 0;
    
    			for (k = j - 1; k >= 0; --k)
    				putchar(temp[k]);
    
    			if (i > 0)
    				putchar(' ');
    
    			j = 0;
    		}
    	}
    
    	return 0;
    }
    

  • Mod

    pyhax schrieb:

    Noch eine Frage zu deiner Lösung: Warum kopierst du in Zeile 14, 15, 16 den String? Du könntest doch einfach token_pointer als Argument für printf nehmen? (Ich programmiere eigentlich immer nur C++ :D)

    Ich war fälschlicherweise davon ausgegangen, dass der Zeiger ungültig würde, sobald man strtok nochmals aufruft. Ich habe mal im Standard nachgeschlagen, aber da steht tatsächlich nichts davon.

    😕 Jetzt frage ich mich, wie strtok wohl funktioniert, ohne Speicherlöcher zu erzeugen.

    💡 Klar, jetzt sehe ich es: Das Argument ist ein char*, kein const char*! strtok zerstört also den Ursprungsstring! :p

    Wie auch immer, dadurch vereinfacht sich meine Funktion natürlich erheblich und hat auch eine viel bessere Laufzeitkomplexität 👍 . Was mit dem Ursprungsstring passiert, kann bei dieser Aufgabenstellung herzlich egal sein:

    void print_reverse(char *string)
    {
      char * token = strtok(string, delimiters);
      if (token)
        {
          print_reverse(NULL);
          fputs(token, stdout);
          putchar(' ');
        }
    }
    

Anmelden zum Antworten