Wörter alphabetisch ordnen



  • size_t woerter(char *text)
    {
    
        size_t word_count = 0;
    
        int is_space, was_space;
    
    	char **Stringarray; // neu
        Stringarray = malloc(100 * sizeof(*Stringarray));  // neu
    
        for (was_space = 1; *text; was_space = is_space)
            if (!(is_space = isspace(*text++)) && was_space)
       			Stringarray[word_count] = *text; // neu
    			printf("%s", Stringarray); // neu
    			free(Stringarray); // neu
    			// gibt mir nun z.B. beim Wort "test" nur den Buchstaben e aus. 
    		    word_count++;
                return word_count;
    
    }
    

    Visual Studio meckert bei der Zuweisung: "...."void *" kann keiner Entität vom Typ char ** zugewiesen werden bzw "char" kann keiner Entität vom Typ "char *" zugewiesen werden"

    Allerdings läuft das Programm problemlos durch.

    Durch die Änderung gibt er mir nur den Buchstaben e aus beim Wort test, bei test test auch nur e, also immer die zweite Stelle.

    Das mit dem Pointer verstehe ich, also im Moment erstelle ich eigentlich nur einen String, den es in c ja so nicht gibt, also ein char Array mit der Länge meiner Eingabe.

    Mit (Spekulation)

    strcpy(Stringarray, text)
    

    müsste ja dann immer ein Array gefüllt werden, oder denke ich da falsch?



  • Bei Fehlermeldungen ist die Angabe der dazu gehörigen Zeilen-/Spaltennummer zwingend, damit man auch weiß, wo der Fehler auftritt.

    `Stringarray ist vom Typ char**

    Stringarray[word_count] ist vom Typ char*

    text ist vom Typ char*

    *text ist vom Typ char`

    Sinnvoll ist hier eigentlich nur die Zuweisung gleicher Typen.

    size_t woerter(char *text)
    {  
        size_t word_count = 0;
    
        int is_space, was_space;
    
        char **Stringarray; 
        Stringarray = malloc(100 * sizeof(*Stringarray));  
    
        for (was_space = 1; *text; was_space = is_space)
            if (!(is_space = isspace(*text++)) && was_space)
                Stringarray[word_count] = *text; // char* = char -> passt nicht
    // hier ist die for-Schleife vorbei
        printf("%s", Stringarray);// printf erwartet char*, bekommt aber char** -> passt nicht
        free(Stringarray); 
    
        word_count++;  // sollte das nicht in der Schleife / im if sein?
        return word_count;
    }
    

    C-Tabaluga schrieb:

    Mit (Spekulation)

    strcpy(Stringarray, text)
    

    müsste ja dann immer ein Array gefüllt werden, oder denke ich da falsch?

    Typproblem siehe oben.
    Und du brauchst auch Speicher in den du kopieren darfst. Den hast du mit dem einen malloc noch nicht bekommen.

    Mit dem malloc in Zeile 8 hast du Platz für 100 Zeiger auf char*. Den Speicher wo die dann hin zeigen hast du damit noch nicht.



  • Sorry, das mit der Zeilesache, soweit hätte ich denken müssen.

    size_t woerter(char *text)
    {  
        size_t word_count = 0;
    
        int is_space, was_space;
    
        char **Stringarray;
        Stringarray = malloc(100 * sizeof(*Stringarray));  // hier befindet sich ein Fehler (falsche Typzuweisung)
    
        for (was_space = 1; *text; was_space = is_space) 
    	{
            if (!(is_space = isspace(*text++)) && was_space) 
    	     {
    
    			 word_count++;
    			 Stringarray[word_count] = text;  // damit will ich ein Wort einzeln deklarieren und in ein char Array Stringarray[i] legen bzw später kopieren
       //          free(Stringarray); //  Durch das malloc soll man das Array bei nicht benutztem Speicherplatz wieder räumen.
    
    		}
    	}
    
    		  printf("%s", Stringarray);  // das soll testweise ausgeben, ob der Compiler meinen Wunsch erfüllt
    		  return word_count;
    
    }
    

    Deklarationsprobleme bis auf das im Kommentar erwähnte nun beseitigt.

    Erwartet wird von mir als Ausgabe bei der Eingabe test also test. Bei Eingabe von test bekomme ich aber nur kryptische Zeichen und =.

    Irgendwo häng ich fest, als dass ich wegkomme von dem Fehler. Das Behandlen von Strings fällt mir schwerer als ich dachte in C, aber es immer schön solche Leute wie euch zu haben, die einem bei der größten Verzweiflung helfen. Danke dafür!



  • Deine Ausgabe ist falsch

    DirkB schrieb:

    printf("%s", Stringarray);// printf erwartet char*, bekommt aber char** -> passt nicht
    

    Dein Stringarray ist ein Feld, das 100 Zeiger auf char -Zeiger speichern kann.

    text ist ein Array von 1024 char .

    Nehmen wir mal an, text fängt an der Speicheradresse 10000 an.
    Der Speicher den malloc für Stringarray reserviert hat liegt bei 44444. In Stringarray ist also 44444 gespeichert.

    Nach deinem Programm sollte das dann so aussehen:

    char text[1024] =      "Hallo Welt, dies ist ein Text"
                            ^     ^     ^    ^   ^   ^        
    Stringarray[0] = 10000 -+     |     |    |   |   |          // bei Adresse 44444
    Stringarray[1] = 10006 -------+     |    |   |   |          // bei Adresse 44448
    Stringarray[2] = 10012 -------------+    |   |   |          // bei Adresse 44452
    Stringarray[3] = 10017 ------------------+   |   |          // bei Adresse 44456
    Stringarray[4] = 10021 ----------------------+   |          // bei Adresse 44460
    Stringarray[5] = 10025 --------------------------+          // bei Adresse 44464
    

    Wenn du jetzt das "ein" haben willst, dann musst du an printf dei Anfangsadresse (10021) übergeben.
    Diese ist in Stringarray[4] gespeichert.
    Durch das printf("%s", Stringarray); bekommt printf aber die Adresse 44444. Da stehen aber nur Adressen und kein sinnvoller Text.

    Wie du auch siehst, sind die Wörter weiterhin in text abgelegt und

    DirkB schrieb:

    Die Wöerter sind dadurch nicht Nullterminiert.

    Stringarray[4] liefert als nicht nur "ein" sondern "ein Text".



  • Okay, das mit der Ausgabe ist mir nun klar.

    printf("%s", Stringarray[1]);
    

    Beim Wort test gibt er mir dann est aus. Also noch ein kleiner Zuweisungfehler mit dem ersten Wort. Wie du auch richtig sagst, gibt er mir bei test test z.B. est test aus, also er trennt nicht, was mit der von dir erwähnten Nullterminierung zusammenhängt. Diesbezüglich habe ich mich versucht zu informieren, aber ich finde da keinen Ansatz, der mir hierbei weiterhelfen würde.

    Wenn ich z.B. sagen würde: text = 0 oder text = ""; dann gibt er mir trotzdem immer alle Wörter aus.

    Ich versteh, was du meinst und was du erreichen willst, aber ich weiß nicht, wie ichs umsetzen soll.

    Ich muss ja erst sagen

    Stringarray[word_count] = text;
    

    aber das ist ja eigentlich schon zu spät, weil da gibt er ja auf Platz 1 den ganzen Text ein. Also muss irgendwo vorher getrennt werden bzw. der Wert von text wieder auf null gesetzt werden.



  • Kann mir jemand nen Tipp geben?



  • Das mit dem "est" mag daran liegen, dass du bei *isspace(test++) schon den Postinkrement hast.

    Für die einzelnen Wörter gibt es mehrer Möglichkeiten:
    Du schreibst an die Stellen, wo ein Whitespace ist, eine '\0' in text.
    Dann ist text aber zerstört. (so macht es die Standardfunktion strtok )

    Oder du beschaffst dir für die Wörter auch Speicher mit malloc und kopierst die Wörter dann da rein.

    Nimm mal den Debugger und geh im Einzelschritt durch die Funktion. Lass dir dabei die Variablen anzeigen.
    Dann siehst du, was wann wo passiert.



  • Grundidee habe ich verstanden und würde ich so umsetzen:

    #include <stdio.h>
    #include <ctype.h>
    #include <stdlib.h>
    #include <string.h>
    #include <conio.h>
    
      size_t woerter(char *text)
    {  
        size_t word_count = 0;
        int a;
    	a = 100;
        int is_space;
    	int was_space;
    
       char **Stringarray; // neu
        Stringarray = (char**) malloc(100 * sizeof(*Stringarray));  
    
        char *woerter;
    	woerter = (char*) malloc (a * sizeof(woerter)); // hier will ich die wörter reinlegen
    
        for (was_space = 1; *text; was_space = is_space) 
    	{
            if (!(is_space = isspace(*text++)) && was_space) 
    	     {
                             *text--;
    			 strcpy(woerter, text); //würde der so richtig kopieren?
    			 word_count++;
    
    		}
    	}
    
    		  return word_count;
    
    }   
    
    int main(void)
    {
    	int i = 0;
        char text[100];
    
    	puts("Geben sie beliebige Woerter ein:");
        fgets(text, sizeof(text) / sizeof(text[0]), stdin);  // Verwendung der Funktion
        printf("Es sind %d Woerter\n", woerter(text));
    
    	getch();
       return 0;
    
    }
    

    Ich gebe mehrere Wörter ein und er gibt mir nur das erste aus. Wie kann ich das nun wiederholen, dass er im Array eins weitergeht?Also ich weiß im Moment noch nicht, wie ich das jetzt in das Stringarray reinmachen soll...



  • C-Tabaluga schrieb:

    char *woerter;
    woerter = (char*) malloc (a * sizeof(woerter)); // hier will ich die wörter reinlegen
    

    Bei dem sizeof in dem malloc wird nicht ein * weg gelassen, sondern es wird einmal dereferenziert.
    Du willst ja die Größe von dem Element bestimmen, auf den woerter zeigt.
    Also kommt da ein * hin. : *sizeof(woerter)
    Du kannst auch sizeof(woerter[0]) (und auch Stringarray = malloc(100 * sizeof(Stringarray[0])); )machen, wenn dir das einsichtiger ist.

    Du hast jetzt einen Speicherbereich für alle Wörter. Da wäre es am einfachsten du machst ein strcpy(woerter, text); und veränderst die Trennzeichen dann in woerter.

    Eigentlich war das aber so gedacht, dass du für jedes gefundene Wort Speicher anforderst und dieses dann von text in den Speicher kopierst. In der Schleife.

    C-Tabaluga schrieb:

    *text--;
                 strcpy(woerter, text); //würde der so richtig kopieren?
    

    Ein

    strcpy(woerter, text-1);
    

    macht es auch, ohne dass du an text rum spielst.

    Du kommst hier mit nur einem char* nicht mehr weiter. Du musst dir den Anfang vom Wort merken und dann noch ein char* haben, der die Zeichen untersucht (dein bisheriges text).

    Die Wortlänge ergibt sich dann aus der Differenz der beiden Zeiger.

    Wenn du für den Wortspeicher calloc nimmst, kannst du die Wörter auch mit strncpy (oder strncat ) da hin kopieren.
    calloc löscht den Speicher gleich. strncpy kopiert keine '\0', wenn die Anzahl der Zu kopierenden Zeichen erreicht ist. Wenn das Ziel leer ist, ist strcat wie strcpy . strncat hängt aber immer eine '\0' an.
    (Ich hoffe du hast die n bei den strncpy und strncat bemerkt)



  • C-Tabaluga schrieb:

    Ich gebe mehrere Wörter ein und er gibt mir nur das erste aus. Wie kann ich das nun wiederholen, dass er im Array eins weitergeht?Also ich weiß im Moment noch nicht, wie ich das jetzt in das Stringarray reinmachen soll...

    Na mit dem word_count. Das stand doch schon da.
    Stringarray ist ein Array mit Zeigern auf char*

    char text[1024] =       "Hallo Welt, dies ist ein Text"
                             vvvvv ||||| |||| ||| ||| ||||           
    Stringarray[0] = 20000  "Hallo"vvvvv |||| ||| ||| ||||          
    Stringarray[1] = 20032        "Welt,"vvvv ||| ||| ||||          
    Stringarray[2] = 20064              "dies"vvv ||| ||||           
    Stringarray[3] = 20096                   "ist"vvv ||||             
    Stringarray[4] = 20128                        "ein"vvvv
    Stringarray[5] = 20150                            "Text"     
    Stringarray[6] = NULL   // als Endekennung      
    Die Adressen ab 20000 (Beispiel) werden alle einzeln mit malloc/calloc beschafft. Die vvvv stellen das kopieren mit strncpy dar
    

    Du musst hier die Indizes von Stringarray durch word_count ersetzen.



  • Ganz schön gewöhnungsbedürftig mit 2D Arrays und Pointern zu arbeiten.

    size_t woerter(char *text)
    {  
        size_t word_count = 0;
        int is_space;
    	int was_space;
    	int a = 100;
    	char *woerter; 
    	char **Stringarray;
    	int i = 100;
    	int zeichenzahl = 0; //zum buchstaben zählen
    
        Stringarray = (char**) malloc(100 * sizeof(*Stringarray));  //sizeof(Stringarray[0])
    	woerter = (char*) calloc (100, 100 * sizeof(*woerter)); // sizeof(woerter[0]) calloc, weil nach kopiervorgang wieder leer
    
        for (was_space = 1; *text; was_space = is_space) 
    	{
    		 zeichenzahl++;
    
    		 if (!(is_space = isspace(*text++)) && was_space) 
    	     {
    			 strcpy(woerter, text-1); // kopiert das Wort in woerter
    			 strncpy(Stringarray[word_count], woerter, zeichenzahl); //von woerter ins stringarray, woerter ist danach wieder frei
    			 zeichenzahl = 0; //zeichenzahl wieder auf 0 setzen
    			 word_count++;
    		 }
    	}
    
    		printf("%s", Stringarray[1]);
    		  return word_count;
    
    }
    

    Ich zähl also die Zeichen bis zum Leerzeichen, dann kopier ich den darin befindlichen Inhalt in woerter. Von woerter gehts weiter ins Stringarray. woerter ist danach wieder leer. Stopp.
    Nun müsste ich mir gemerkt haben, wo ich war. Also evt noch einen zusätzlichen Counter einbauen. Da soll strncpy dann wieder kopieren. Dann sollte das befüllen klappen. Im Moment gehe ich nur noch etwas unsanft mit den Schreibrechten um, aber das sollte sich danach noch beheben lassen.



  • C-Tabaluga schrieb:

    Von woerter gehts weiter ins Stringarray. woerter ist danach wieder leer.

    Wie kommst du darauf, dass woerter wieder leer ist?

    C-Tabaluga schrieb:

    strncpy(Stringarray[word_count], woerter, zeichenzahl);
    

    klappt nicht, da bei Stringarray[word_count] kein Speicher hinterlegt ist. Dieser Speicher sollte eigentlich woerter sein.

    Stringarray enthält nur die Zeiger auf den Speicher, wo die Wöerter abgelegt sind.
    Den Speicher musst du aber erst besorgen. Für jedes Wort neu. Da passiert nichts automatisch.

    Zudem zeigt text auf das Ende vom Wort. Das ist für das kopieren etwas schlecht.
    Pseudo-

    Speicher für die Wortliste holen // das ist Stringarray
    
    solange noch Zeichen im Text sind
      Ist das ein Wortanfang? dann Stelle merken
      Ist das ein Wortaende? dann 
        Länge vom Wort berechnen            // zeichenzahl oder Wortanfang-Wortende
        Speicher für Wort holen (Länge +1)  // calloc
        Wort in Speicher kopieren           // strncpy(Speicher,Wortanfang,Länge)
        Wort terminieren                    // Speicher[Länge] = '\0';
        Speicher in Stringarray eintragen   // Stringarray[word_count] = Speicher_den_du_von_calloc_hast
        word_count erhöhen.
      nächstes Zeichen im Text nehmen
    
    Stringarray[word_count] = NULL // Endemarkierung
    

    Was noch fehlt ist die Überprüfung, ob Stringarray voll ist (mehr als 99 Wörter)

    Wenn du das mit der Endemarkierung machst, dann ist die Ausgabe auch ganz einfach:

    for(i=0;Stringarray[i];i++)
        puts(Stringarray[i]);
    

    Nochmal zu calloc. Du hast da Platz für 100*100 Zeichen reserviert.
    Der erste Parameter gibt die Anzahl der Elemente an, der zweite die Größe der Elemnte.
    Diese beiden Werte werden multipliziert.

    calloc (Länge, sizeof(*woerter)); // so ist es gedacht
    //oder
    calloc (sizeof(*woerter),Länge);  // geht auch
    

    Schnapp dir endlich mal den Debugger.


Log in to reply