Crossreferenzliste die 3. - Doppelte Wörter entfernen



  • Hallo, ich komme wiedermal nicht weiter xD

    Es funktioniert eigentlich alles. Nur möchte ich gerne alle doppelten Wörter löschen. Und die zeilenAnzahl mithilfe von arrays speichern, so dass ich ein Wort habe und dann in einer for-schleife, die Zeilenangaben hintereinander ausliest (habe ich noch nicht einegbaut, die for-Schleife).

    Nun gut, wenn man den folgenden Quellcode compiliert, kommt ein Segmentation fault. Liegt an der Funktion int delete_doubles_etc();. Was ich erreichen möchte mit der Funktion ist, das er sich in einer Schleife den ganzen Struct durchläuft und nach jedem Eintrag wird das wort in search gespeichert. Search durchläuft dann wiederum nochmal das struct, und die schleife wird abgebrochen, wenn search gleich dem Wort im Struct ist, dann möchte ich das Struct löschen und die Zeilennummer in das zeilenAnzahl-array speichern ... noch ist der Löschvorgang nicht da, würde ich dann später machen wenns funktioniert ^^

    Ist ein bisschen kompliziert das ganze, ich hoffe ihr verstehts^^

    /* Bibliotheken */
    
    #include  <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <malloc.h>
    
    #define MAX 10000
    
    /* Struct-Deklaration */
    
    struct zewo {
    	char wort[100];
    	int zeilenAnzahl[MAX];
    	struct zewo *next;
    };
    
    struct zewo *p, *k, *nach,*top,*tmp;
    
    /* Prototyping */
    
    struct zewo ab;
    void insert_into(char *, int);
    void print_struct(char *, char *, char *);
    void cross_reference(FILE *, char *);
    void check_words(FILE *, char , char *, char *, int, int);
    void exist_data(char *);
    void drop_down_menue();
    int delete_doubles_etc();
    void create_html_document();
    void create_csv_document();
    
    /* check_words(); - Funktion */
    
    void check_words(FILE *f, char c, char *w, char *wort, int trennzeichen, int zeilenAnzahl)
    {
    	while(c!=EOF)
    	{
    		c=fgetc(f);
    		if(c=='\n') zeilenAnzahl++;
    
    		if(c>='A' && c<='Z' || c>='a' && c<='z' || c=='$' || c=='_' || c>='0' && c<='9')
    		{
    			*w=c;
    			w++;
    			trennzeichen=0;
    		}
    
    		else if(trennzeichen==0)
    		{
    			*w=0;
    			if(strlen(wort)>1)
    			{
    				insert_into(wort, zeilenAnzahl);
    			}
    			w=wort;
    			trennzeichen=1;
    		}
    	}
    
    	fclose(f);
    }
    
    /* insert_into(); - FUunktion */
    
    void insert_into(char *wort, int zeilenAnzahl)
    {
    	p=top;
    	nach=top;
    
    	tmp=(struct zewo *)malloc(sizeof(struct zewo));
    	strcpy(tmp->wort,wort);
    	tmp->zeilenAnzahl[0] = zeilenAnzahl;
    
    	if (p==NULL)
    	{
    		top=tmp;
    		top->next=NULL;
    	}
    	else
    	{
    		// richtige Stelle suchen
    		while ((p!=NULL && wort[0]>p->wort[0]) || (p!=NULL && wort[0]==p->wort[0] && wort[1]>p->wort[1]) || (p!=NULL && wort[0]==p->wort[0] && wort[1]==p->wort[1] && wort[2]>p->wort[2]) || (p!=NULL && wort[0]==p->wort[0] && wort[1]==p->wort[1] && wort[2]==p->wort[2] && wort[3]>p->wort[3]))
    		{
    			nach=p;
    			p=p->next;
    		}
    		// am Anfang einfuegen
    		if (p==top)
    		{
    			tmp->next=top;
    			top=tmp;
    		}
    		else
    		{
    			tmp->next=p;
    			nach->next=tmp;
    		}
    	}
    
    }
    
    /* delete-doubles-etc(); - Funktion */
    
    int delete_doubles_etc()
    {
    	char search[100];
    
    	int n   = 1;
    	int min = 0;
    	int x   = 0;
    
    	p=top->next;
    	k=top;
    
    	while(p!=NULL)
    	{
    		strcpy(search, p->wort);
    
    		p=top;
    
    		x = 0;
    
    		do{
    		     p=p->next;
    		     x++;
    		}while(!(strcmp(search, p->wort)));
    
    		if(min == 0){
    			min = x;
    		}else if(x > min){
    			min = x;
    		}
    
    		k->zeilenAnzahl[n] = p->zeilenAnzahl[0];
    		n++;
    
    		k = k->next;
    	}
    
    	return x;
    }
    
    /* print_struct(); - Funktion */
    
    void print_struct(char *name, char *zeile, char *datei)
    {
    
    	int n = 0;
    
    	printf("+------------------------------------------------------------+\n"
    	       "|                     Crossreferenzliste                     |\n"
    	       "+------------------------------------------------------------+\n"
    	       "| Dateiname: %47s |\n"
     	       "+---------------------------------------+--------------------+\n"
    	       "| %37s |"
    	       "%19s |\n"
    	       "+---------------------------------------+--------------------+\n", datei, name, zeile);
    
    	p=top;
    
    	while(p!=NULL)
    	{
    		printf("| %37s |", p->wort);
    		printf("%19d |", (p->zeilenAnzahl[0])+1);
    
    		printf("\n");
    		p=p->next;
    	}
    
    	printf("+---------------------------------------+--------------------+\n\n");
    }
    
    /* cross_reference(); - Funktion */
    
    void cross_reference(FILE *f, char *datei)
    {
    
    	char wort  [100];
    
    	int zeilenAnzahl  = 0;
    	int trennzeichen  = 1;
    	int maxAnzahl     = 0;
    	int x             = 0;
    
    	char name[30]  =  "Wort";
    	char zeile[30] = "Zeile";
    
    	char c  = 0;
    	char *w = wort;
    
    	check_words(f, c, w, wort, trennzeichen, zeilenAnzahl);
    
    	x = delete_doubles_etc();
    
    	print_struct(name, zeile, datei);
    
    	drop_down_menue();
    
    }
    
    /* exist_data(); - Funktion */
    
    void exist_data(char *datei)
    {
    	FILE *f;
    
    	if(!(f=fopen(datei,"r")))
    	{
    		printf("This Data doesnt exist!\n");
    		return;
    	}else
    		cross_reference(f, datei);
    }
    
    /* drop_down_menue(); - Funktion */
    
    void drop_down_menue()
    {
    	int main_aktion = 0;
    
    	do{
    		printf("+--------------------------------------------------+---------+\n"
    		       "| Generate a HTML - document                       |    1    |\n"
    		       "+--------------------------------------------------+---------+\n"
    		       "| Generate a CSV - document                        |    2    |\n"
    		       "+--------------------------------------------------+---------+\n"
    		       "| Exit                                             |    0    |\n"
    		       "+--------------------------------------------------+---------+\n"
    		       "Your Choice: ");
    		scanf("%d", &main_aktion);
    
    		if(main_aktion == 1) create_html_document();
    		else if(main_aktion == 2) create_csv_document();
    		else main_aktion = 0;
    
    	}while(main_aktion != 0);
    
    }
    
    /* create_html_document(); - Funktion */
    
    void create_html_document()
    {
    	FILE *h;
    
    	char html[40];
    
    	printf("+------------------------------------------------------------+\n"
    	       "|          Choose a documentname (without datatype)          |\n"
    	       "+------------------------------------------------------------+\n"
    	       "Your Choice: ");
    	scanf("%s", html);
    	strcat(html, ".html");
    
    	h = fopen(html, "w+");
    
    	fclose(h);
    
    }
    
    /* create_csv_document(); - Funktion */
    
    void create_csv_document()
    {
    	FILE *c;
    
    	char csv[40];
    
    	printf("+------------------------------------------------------------+\n"
    	       "|          Choose a documentname (without datatype)          |\n"
    	       "+------------------------------------------------------------+\n"
    	       "Your Choice: ");
    	scanf("%s", csv);
    	strcat(csv, ".csv");
    
    	c = fopen(csv, "w+");
    
    	fclose(c);
    
    }
    
    /* main(); - Funktion */
    
    int main(int argc, char *argv[])
    {
    
    	int u = 1;
    	char datei[100];
    
    	if(argc>1){
    
    			for (u=1; u<argc; u++){
    				printf("wayne");
    				strcpy(datei, argv[u]);
    				exist_data(datei);
    				return 0;
    			}
    	}else{
    		return 0;
    	}
    
    }
    


  • Beim Überfliegen des Codes fällt mir folgendes auf: du liebst anscheinend unsinnige Tipparbeit, die nur zu Fehler führen kann. Eine if Abfrage, die 1 KM lang ist, ist nicht lesbar und dort schleichen sich schnell fehler ein:

    void check_words(FILE *f, char c, char *w, char *wort, int trennzeichen, int zeilenAnzahl)
    {
        while(c!=EOF)
        {
            c=fgetc(f);
            if(c=='\n') zeilenAnzahl++;
    
            if(c>='A' && c<='Z' || c>='a' && c<='z' || c=='$' || c=='_' || c>='0' && c<='9')
            {
                *w=c;
                w++;
                trennzeichen=0;
            }
    
            else if(trennzeichen==0)
            {
                *w=0;
                if(strlen(wort)>1)
                {
                    insert_into(wort, zeilenAnzahl);
                }
                w=wort;
                trennzeichen=1;
            }
        }
    
        fclose(f);
    }
    

    lässt sich so vereinfachen:

    void check_words(FILE *f, char c, char *w, char *wort, int trennzeichen, int zeilenAnzahl)
    {
        while(c!=EOF)
        {
            c=fgetc(f);
            if(c=='\n') zeilenAnzahl++;
    
            if(isalnum(c) || c=='$' || c=='_')
            {
                *w=c;
                w++;
                trennzeichen=0;
            }
    
            else if(trennzeichen==0)
            {
                *w=0;
                if(*wort)
                {
                    insert_into(wort, zeilenAnzahl);
                }
                w=wort;
                trennzeichen=1;
            }
        }
    
        fclose(f);
    }
    

    So, und nun die Fehler dieser Funktion.

    1. Wenn du eine Variable nur als Platzhalter verwendest und der Wert, dem übergeben wird, völlig egal ist (wie bei dem c Parameter), dann gehört es einfach nicht in der Parameter Liste. Dafür gibt es lokale Variablen.

    2. Man nimmt nicht char , wenn man fgetc verwendet, sondern int , weil fgetc einen int zurückliefert und das kann mit EOF zu Problemen führen, also:

    void check_words(FILE *f, char *w, char *wort, int trennzeichen, int zeilenAnzahl)
    {
        int c;
        do {
           c = fgetc(f);
           ...
        } while(c != EOF);
    ...
    

    2. Dein else if finde ich sinnlos. Wenn das gelesene Zeichen z.b. ein '+' ist, dann arbeitet dein Code weiter abhängig von trennzeichen . Bist du sicher, dass du ein 'else if' stehen haben willst anstatt nur 'if'?

    1. w wird zwar Zeichen für Zeichen beschrieben, aber nie mit '\0' abgeschlossen. Und außerdem überprüfst du niergends, ob du auf *w zugreifen darfst. Was ist, wenn w auf 10 Byte-Puffer zeigt, du aber 15 Zeichen iiest?

    4. Die Zeile w=wort; ist Schwachsinn. Damit verlierst den originallen Zeiger auf w und könntest dann auf ungültigen Speicher landen.

    5. das fclose gehört nicht in dieser Funktion, sondern dort, wo fopen aufgerufen wurde.

    Nächste Fkt;

    void insert_into(char *wort, int zeilenAnzahl)
    {
        p=top;
        nach=top;
    
        tmp=(struct zewo *)malloc(sizeof(struct zewo));
        strcpy(tmp->wort,wort);
        tmp->zeilenAnzahl[0] = zeilenAnzahl;
    
        if (p==NULL)
        {
            top=tmp;
            top->next=NULL;
        }
        else
        {
            // richtige Stelle suchen
            while ((p!=NULL && wort[0]>p->wort[0]) || (p!=NULL && wort[0]==p->wort[0] && wort[1]>p->wort[1]) || (p!=NULL && wort[0]==p->wort[0] && wort[1]==p->wort[1] && wort[2]>p->wort[2]) || (p!=NULL && wort[0]==p->wort[0] && wort[1]==p->wort[1] && wort[2]==p->wort[2] && wort[3]>p->wort[3]))
            {
                nach=p;
                p=p->next;
            }
            // am Anfang einfuegen
            if (p==top)
            {
                tmp->next=top;
                top=tmp;
            }
            else
            {
                tmp->next=p;
                nach->next=tmp;
            }
        }
    
    }
    

    wow, wenn man den Wald vor lauter Bäume nicht sieht ...

    1. also, p, top, nach werden nie initialisiert und trotzdem greifst du auf sie zu, als wären sie.

    2. Thou shalt not cast malloc, yet you didst

    3. deine while Zeile ist fürchtbar. In jedem Schritt überprüfst, ob p!=NULL . Wenn das überall gelten muss, dann zieh es gar vor

    if(p != NULL)
    {
       while(der kram)
       {
           ...
       }
    }
    

    oder

    while(p!= NULL && (der kram))
    {
         ...
    }
    

    4. Strings kann man nicht mit == vergleichen, denn damit vergleichst du die Adressen, worauf die Zeiger zeigen, und nicht den Inhalt, worauf sie zeigen. Um Strings zu vergleichen gibt es man: strcmp(3)

    4. Du kannst diese Anweisung sicherlich in eine Funktion auslagern, oder? Und wenn ich es richtig interpretiert habe, dann überprüfst du, ob wort in der lexikographischen Reihenfolge nach p->wort vorkommt. Dann

    while(p != NULL && (strcmp(wort, p->wort) > 0))
    {
        ...
    }
    

    Meine Güte, wie kann man so viele Fehler in so wenig Code haben? Weil du einfach Code schreibst, ohne zu überlegen, was du da eigentlich schreibst. Lerne erstmal die C Grundlagen richtig, bevor du dich an größere Sachen waagst.



  • Danke erstmal für die HIlfe, die meisten Sachen habe ich gerade geändert. Das Strings über strcmp verglichen werden ist mir schon bekannt, nur hab ich es vergessen, weil ich so mit dem Programm beschäftigt war ^^

    Das mit dem fclose habe ich dort eingebaut, weil ich ja schon bei exist_date(); die fopen-anwesung stehen habe. Und mein ganzes programm über die funktion cross_referenz läuft. Daher hab ich es da geschlossen. Ich wüsste auch sonst nicht wo ich es schliessen lassen hätte sollen. Die check._words-Funktion haben wir vom Lehrer bekommen, das da eigentlich Fehler drinne sind hätte ich jetzt nicht gedacht 😕

    Nun gut, aber was ist bei meiner Funktion delete_doubles_ect() falsch. Ich bin nicht so der Ass in Listen, so eine kleine Hilfe wäre nicht schlecht ^^

    Zudem, wieso soll ich malloc nicht casten? Unser Lehrer behauptet nämlich das es wichtig ist malloc zu casten! Ich bin leicht verwirrt ^^

    Danke nochmal für die schnelle HIlfe 😉



  • BraCay1 schrieb:

    Zudem, wieso soll ich malloc nicht casten? Unser Lehrer behauptet nämlich das es wichtig ist malloc zu casten! Ich bin leicht verwirrt ^^

    dein Lehrer hat keine Ahnung: http://www.c-plusplus.net/forum/viewtopic.php?t=206606

    ich werde aus deinem Code nicht schlau, was du eigentlich erreichen willst. Was ist deine Aufgabestellung?



  • Das Programm soll eine Textdatei einlesen, die Wörter analysieren (keine Buchstaben), und sie dann in eine Liste packen mit den Attributen Wort und Zeile.
    Zudem sollen alle doppelten Wörter zu einem zusammengefasst werden und die Zeilenlänger jeweils ergänzt werden.



  • also, hier mal was on the fly

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    struct zewo
    {
    	char        *word;
    	int         line;
    	struct zewo *next;
    };
    
    /* new_line == 1 wenn \n gelesen wurde, sprich letztes Wort einer Zeile */
    char *get_next_word_out_of_file(FILE *fp, int *new_line)
    {
    	char *word, *tmp;
    	int c, len, ignore_blank;
    
    	if(fp == NULL || new_line == NULL)
    		return NULL;
    
    	word = NULL;
    	len = 0;
    	ignore_blank = 1; /* um eine Folge von Leerzeichen zu ignorieren */
    	*new_line = 0;
    	for(;;)
    	{
    		c = fgetc(fp);
    
    		if(c == EOF) /* Ende der Datei / Fehler */
    			return word;
    
    		if(c == '\n')
    		{
    			*new_line = 1;
    			return word;
    		}
    
    		if(isblank(c))
    		{
    			if(ignore_blank)
    				continue;
    			return word;
    		}
    		ignore_blank = 0;
    
    		*new_line = 0;
    		tmp = realloc(word, len + 2);
    		if(tmp == NULL)
    			return word;
    		word = tmp;
    
    		word[len++] = c;
    		word[len] = 0;
    	}
    }
    
    struct zewo *get_next_zewo_word(FILE *fp, int *new_line)
    {
    	char *word;
    	struct zewo *zewo_word;
    
    	if(fp == NULL || new_line == NULL)
    		return NULL;
    
    	zewo_word = calloc(1, sizeof *zewo_word);
    	if(zewo_word == NULL)
    		return 0;
    
    	zewo_word->line = 0;
    	zewo_word->next = NULL;
    	zewo_word->word = get_next_word_out_of_file(fp, new_line);
    
    	if(zewo_word->word == NULL)
    	{
    		free(zewo_word);
    		return NULL;
    	}
    
    	return zewo_word;
    }
    
    void free_zewo_list(struct zewo *zewo_list)
    {
    	struct zewo *tmp;
    	if(zewo_list == NULL)
    		return;
    
    	for(;;)
    	{
    		tmp = zewo_list;
    		if(tmp == NULL) return;
    		tmp = tmp->next;
    
    		if(zewo_list->word)
    			free(zewo_list->word);
    		free(zewo_list);
    		zewo_list = tmp;
    	}
    }
    
    void print_zewo_list(struct zewo *zewo_list)
    {
    	if(zewo_list == NULL)
    		return;
    
    	for(; zewo_list->next; zewo_list = zewo_list->next)
    		printf("line: %d; %s\n", zewo_list->line, zewo_list->word);
    
    	printf("line: %d; %s\n", zewo_list->line, zewo_list->word);
    }
    
    int main(int argc, char **argv)
    {
    	FILE *fp;
    	struct zewo *zewo_list, *tmp, *last;
    	int lnum, nl;
    
    	fp = stdin;
    
    	if(argc >= 2 && strcmp(argv[1], "--help") == 0)
    	{
    		fprintf(stderr, "usage: %s [filename]\n", argv[0]);
    		fprintf(stderr, "\nif filename is omited then stdin is read\n");
    		return 1;
    	}
    
    	if(argc >= 2)
    	{
    		fp = fopen(argv[1], "r");
    		if(fp == NULL)
    		{
    			perror("fopen");
    			return 1;
    		}
    	}
    
    	zewo_list = NULL;
    	last = NULL;
    	lnum = 1;
    	nl = 0;
    	while((tmp = get_next_zewo_word(fp, &nl)))
    	{
    		if(nl)
    			lnum++;
    		tmp->line = lnum;
    		tmp->next = NULL;
    		if(zewo_list == NULL)
    			zewo_list = tmp;
    		else
    			last->next = tmp;
    
    		last = tmp;
    	}
    
    	if(fp != stdin)
    		fclose(fp);
    
    	print_zewo_list(zewo_list);
    	free_zewo_list(zewo_list);
    
    	return 0;
    }
    

    anstatt alles 1:1 zu übernehmen, versuch mal den Code zu verstehen, wenn du etwas nicht verstehst, dann stell eine Frage. Es gibt eine Schwachstelle im Code: bei einer leeren Zeile liefert get_next_zewo_word NULL zurück. Erweitere den Code, so dass das nicht passiert.



  • kann ich dir gleich sagen, das ich das nicht verstehe. Funktionen wie realloc hatten wir noch nicht. Ich hatte jetzt eigentlich gedacht, du kannst mir meine fehlerhafte Funktion die ich dahabe, beheben. Und zwar diese:

    void delete_doubles_etc()
    {
    	char search[100];
    	int n = 1;
    
    	p=top;
    	k=top;
    
    	while(p!=NULL)
    	{
    		strcpy(search, p->wort);
    
    		p=top;
    
    		do{
    		     p=p->next;
    		}while(!(strcmp(search, p->wort)));
    
    		k->zeilenAnzahl[n] = p->zeilenAnzahl[0];
    		n++;
    
    		k = k->next;
    	}
    }
    

    Zudem ich in c auch kein Profi bin. Für euch mag das alles simpel sein, aber für mich eure Algorithmen römische Buchstaben .

    Trotzdem danke für die Mühe, ich versuchs aufjedenfall mal durchzusteigen, und bei Fragen poste ich sie^^

    EDIT: Ich habe ebend mal das Programm kompiliert, er gibt mir die ersten 5 Zeilen aus. Das wars dann aber auch schon^^



  • BraCay1 schrieb:

    kann ich dir gleich sagen, das ich das nicht verstehe. Funktionen wie realloc hatten wir noch nicht.

    du sagst, du kennst man: realloc(3) nicht, aber mit malloc scheinst du angeblich umzugehen 😕

    BraCay1 schrieb:

    Ich hatte jetzt eigentlich gedacht, du kannst mir meine fehlerhafte Funktion die ich dahabe, beheben.

    das werde ich ganz sicher nicht tun, denn das ist nicht meine Aufgabe. Dazu müsste ich mir deinen gesamten Quellcode genauer anschauen und ihn erstmal verstehen, und dazu habe ich weder Zeit noch Lust.

    Aus meinem Code kannst du lernen:

    - wie man Wort für Wort eine Datei liest
    - wie man eine einfache single-linked-list baut

    darus kannst du letztlich dein Programm aufbauen. Deine Probleme werden wir sicherlich nicht für dich lösen.

    edit:
    grad ist mir aufgefallen

    Zudem ich in c auch kein Profi bin. Für euch mag das alles simpel sein, aber für mich eure Algorithmen römische Buchstaben .

    welches Alphabet denkst du, dass wir gerade verwenden? 😉


Anmelden zum Antworten