Sequenzielle Suche



  • Hallo,

    Es wird eine Fehler.txt eingelesen, der Benutzer soll dann nach einem Datum suchen können (seqentielle Suche) und die entsprechenden Einträge der Fehlerdatei sollen angezeigt werden. Vorerst macht mir aber überhaupt die Rückgabe des Index zu schaffen.

    Hier der Header:

    //Funktionen zur Handhabung von Fehlerprotokollen
    //***********************************************
    
    //Datenstruktur für einen Fehlerprotokolleintrag
    //**********************************************
    
    //Untertyp Kalenderdatum
    typedef struct { 
    	int tag;
    	int monat;
    	int jahr; 
    } KDatum;
    
    //Untertyp Uhrzeit
    typedef struct {
    	int std;
    	int min; 
    } Uhrzeit;
    
    //Länge einer Kurzbeschreibung
    #define KLEN 51
    
    //Struktur für Fehlerprotokolleintrag
    typedef struct
    {
    	KDatum kdat;		//Kalenderdatum
    	Uhrzeit zeit;		//Uhrzeit
    	int errnr;			//Fehlernummer
    	char ftext[KLEN];	//Kurzbeschreibung
    } Fehler;
    
    //Fehlerprotokolleintrag im Konsolenfenster anzeigen
    //**************************************************
    void showFDat(const Fehler *fdatP);
    //fdatP: Zeiger auf den anzuzeigenden Fehlerdatensatz
    
    //Fehlerprotokolldatei in Speicher einlesen
    //*****************************************
    int readFDat(const char *pfad, Fehler *fdata, int nmax);
    //pfad: Pfadname der Fehlerdatei
    //fdata: Zeiger auf Array der einzulesenden Fehlerdaten im Speicher
    //nmax: Max.Anzahl der einzulesenden Fehlerdaten
    //Rückgabe: Anzahl der erfolgreich gelesenen Datensätze im Bereich 0..nmax,
    //-1, falls Fehler beim Öffnen der Datei
    
    //Funktion zum Überprüfen der Gültigkeit eines Kalenderdatums
    //***********************************************************************
    //datP: Zeiger auf das zu überprüfende Kalenderdatum
    //Rückgabe: 1, falls Kalenderdatum ok, 0 sonst
    int checkKDatum(const KDatum *datP);
    
    //Funktion zum Überprüfen der Gleichheit zweier Kalenderdaten
    static int equalKDatum(const KDatum *kd1P, const KDatum *kd2P)
    {
    	if(kd1P->jahr==kd2P->jahr && kd1P->monat==kd2P->monat && kd1P->tag==kd2P->tag)
    	{
    		return 1;
    	}
    	else return 0;
    }
    
    //sequenzielle Suche
    int seqSearchKDat(const Fehler fdata[], const KDatum *kdP, int n1, int n2);
    

    1. c-File (hier ist die sequenzielle Suche implementiert)

    #include <stdio.h>
    #include "FehlerProtokoll.h"
    
    //Fehlerprotokolleintrag im Konsolefenster anzeigen
    //*************************************************
    void showFDat(const Fehler *fdatP)
    {
    	printf("%02d.%02d.%4d-%02d:%02d %d %s\n",
    		fdatP->kdat.tag, fdatP->kdat.monat, fdatP->kdat.jahr,
    		fdatP->zeit.std, fdatP->zeit.min,
    		fdatP->errnr, fdatP->ftext);
    }
    
    //Funktion zum Überprüfen der Gültigkeit eines Kalenderdatums
    //***********************************************************************
    int checkKDatum(const KDatum *datP)
    {
        //Tabelle der Monatslängen
        static int MonatsLaenge[] = {31,29,31,30,31,30,31,31,30,31,30,31};
        //Monatszahl prüfen
        if(datP->monat < 1 || datP->monat > 12) 
            return 0;
        //Tageszahl prüfen mit rudimentärer Schaltjahrberücksichtigung
        if(datP->tag < 1 || datP->tag > MonatsLaenge[datP->monat-1] ||
            (datP->monat == 2 && datP->tag == 29 && datP->jahr % 4 != 0)) 
            return 0;
        return 1;
    }
    
    //Lokale Hilfsfunktion zum Überprüfen der Gültigkeit einer Uhrzeit
    //****************************************************************
    //Rückgabe: 1, falls Uhrzeit ok, 0 sonst
    static int checkUhrzeit(const Uhrzeit *zeitP)
    {
    	if(zeitP->min < 0 || zeitP->min >= 60 || zeitP->std < 0 || zeitP->std >= 24)
    		return 0;
    	return 1;
    }
    
    //Fehlerprotokolldatei in Speicher einlesen
    //*****************************************
    
    int readFDat(const char *pfad, Fehler *fdata, int nmax)
    {
        int ret;
    	int n = 0;
        FILE *file = fopen(pfad, "rt");
        if(file == NULL) return -1;
        while(n < nmax )
        {
            ret = fscanf(file, "%d.%d.%d-%d:%d %d %s", 
                &fdata[n].kdat.tag, &fdata[n].kdat.monat, &fdata[n].kdat.jahr,
                &fdata[n].zeit.std, &fdata[n].zeit.min,
                &fdata[n].errnr, fdata[n].ftext);
    		if(!(ret == 7 && fdata[n].errnr >= 1 
    			&& checkKDatum(&fdata[n].kdat) 
    			&& checkUhrzeit(&fdata[n].zeit)))
                break;
            n++;
        }
        fclose(file);
        return n;
    }
    
    int seqSearchKDat(const Fehler data[], const KDatum *kdP, int n1, int n2) 
    {
    	int k;
    	for (k=n1-1; k<=n2-1; k++)
    		if(equalKDatum(&data[k].kdat, kdP))
    			return k+1;
    		else return -1;
    
    }
    

    2. c-File für Kontrollausgabe der Fehlerdatei, sowie Eingabe nach dem zu suchenden Datum.
    Ab Zeile 67 wird die Funktion für die sequenzielle Suche aufgerufen. Mehrmalig in einer for-Schleife im Falle mehrmalig vorkommender Daten.

    #include <stdlib.h>
    #include <stdio.h>
    #include <ctype.h>
    #include "FehlerProtokoll.h"
    
    #define NMAX   10000
    
    int main(void)
    {
    
        int k, nread, n1, n2, m, w;
        char pfadname[_MAX_PATH];
        Fehler err[NMAX];
    
    	KDatum *dat=NULL;
    
    	//speicher freigeben
    	dat=(KDatum *) malloc(sizeof(KDatum));
    
    	if(dat==NULL)
    	{
    		printf("Speicher konnte nicht allokiert werden!");
    		system("pause");
    		return;
    
    	}
    
        //Fehlerdatei öffnen
        printf("Pfadname der Fehlerprotokolldatei: ");
        scanf("%s", pfadname);
        nread = readFDat(pfadname, err, NMAX);
        if(nread < 0) {
            printf("Datei kann nicht geoeffnet werden\n");
    		system("pause");
    		return 1;
    	}
    
        //Kontrollausgabe
        printf("Kontrollausgabe:\n");
        for(k = 0; k < nread; k++)
        {
            printf("%3d: ", k+1);
            showFDat(&err[k]);
        }
    
    		printf("Bitte geben Sie ein Datum TTMMJJJJ ein: \n");
    		do
    		{
    
    		scanf("%d", &(dat->tag));
    		scanf("%d", &(dat->monat));
    		scanf("%d", &(dat->jahr));
    
    		}
    
    		while(!checkKDatum(dat));
    
    		if(checkKDatum(dat))
    		{
    			printf("Geben sie das Suchintervall ein: \n");
    			scanf("%d bis %d", &n1, &n2);
    
    			for(k=n1-1;k<=n2-1;k++)
    			{
    				w=seqSearchKDat(&err[k], dat, n1, n2);
    				printf("%d", w);
    			}
    	}
    
    	system("pause");
    	return 0;
    }
    

    Die for-Schleife im letzten c.File gibt aber überhaupt nichts zurück, was übersehe ich? Vielen Dank fürs Drüberschauen.



  • Die for-Schleife in seqSearchKDat wird nur 1-mal durchlaufen, denn entweder gibt es den if-Zweig oder else.
    Und in Beiden steht return.

    Warum hast du in seqSearchKDat eine for-Schleife und drum herum noch einmal mit den selben Parametern?

    Die Funktion equalKDatum hat in dem Header nichts zu suchen. Sie wird für jedes .c das den Header einbindet angelegt.

    Steck sie in ein .c und mach das static davor weg.



  • Habe mir schon gedacht, dass das so nicht funktioniert...
    Aber wie komme ich dann an alle Rückgabewerte von seqSearch?

    Steh grad auf der Leitung.
    Danke für den Hinweis mit equalKDat, war vermutlich ein Versehen.



  • TrappedUnderIce schrieb:

    Aber wie komme ich dann an alle Rückgabewerte von seqSearch?

    Lass doch einfach das else weg (nur das Wort). Dann gibt es das return -1 nur wenn die Schleife ganz durchgelaufen ist.



  • Und die äußere for-Schleife um seqSearch lassen?!



  • So genau habe ich mir das jetzt auch nicht angesehen.

    Es ist dein Programm. Du musst wissen was es machen soll.

    Bau in den Schleifen ein paar printf ein in denen du die Werte ausgibst (Datum, k ,n1,n2,...).
    Dann siehst du doch ob das doppelt vorkommt.

    Es gibt übrigens auch noch den Debugger

    Damit kannst du das Problem auch finden.



  • Was ich nicht ganz verstehe ist folgendes...

    int seqSearchKDat(const Fehler fdata[], const KDatum *kdP, int n1, int n2) 
    {
    		int k;
    		for (k=n1-1; k<=n2-1; k++) {
    		if(equalKDatum(&fdata[k].kdat, kdP))
    
    			return k+1;
    		}
    
    		return -1;
    
    }
    

    Wenn ich diese Funktion folgendermaßen aufrufe, müsste doch k+1 als Ausgabe erscheinen, falls denn k+1 dieses Datum beeinhaltet.

    printf("%d", seqSearchKDat(&err[k], dat, n1, n2));
    

    Die gibt aber jetzt immer -1 zurück. Wieso?


  • Mod

    1. Wirf einen Debugger an
    2. step durch die Funktion und die Unterfunktion
    3. Sobald etwas von dir unerwartetes geschieht guckst du dir an, warum (z.B. mal die Werte der Variablen an der Stelle angucken)
    4. ???
    5. Profit!



  • Dann nimm doch mal den Debugger.
    Oder

    printf("equalKDatum  : %3d: %02d.%02d.%4d <-> %02d.%02d.%4d\n", k, kd1P->jahr, kd1P->monat, kd1P->tag , kd2P->jahr, kd2P->monat, kd2P->tag);
    

    und

    printf("seqSearchKDat: %3d: %02d.%02d.%4d <-> %02d.%02d.%4d\n", k, fdata[k].kdat.jahr, fdata[k].kdat.monat, fdata[k].kdat.tag , kdP->jahr, kdP->monat, kdP->tag);
    

    Und schau nach ob es wirklich gleiche Daten sind.



  • Die Daten sind definitiv gleich, wie ich mit diesem Code überprüft habe:

    for(k=n1-1; k<=n2-1; k++){
    printf("%d", equalKDatum(&err[k].kdat, dat));
    }
    

    Hier erhalte ich als Ausgabe 0 und im Falle der Gleichheit eine 1.

    Ich will aber die Indices also bei welchem k sich die gesuchten Fehlerdaten befinden, deshalb die Funktion seqSearchKDat, die mir k+1 ( +1 wg. Initialisierung von 0 beginnend). @seppj: 4. und 5. ?



  • Das ist aber trotzdem etwas anderes.
    Du interpretierst/übergibst die Daten in seqSearchKDat anders als in equalKDatum
    Genauer: beim ersten Paramter.

    An seqSearchKDat wird die Anfangsadresse von Feld übergeben. Dann stimmen auch die Indizes.
    An equalKDatum übergibst du aber die Adresse von einem Element. Behandelst es aber wie die Anfangsadresse. Dann stimmen die Indizes nicht mehr.
    Das Problem mit den zwei for-Schleifen.



  • Deshalb wohl auch dieses hier im Debugger:
    &fdata[k].kdat 0x00076b50 {tag=-858993460 monat=-858993460 jahr=-858993460 }

    Wie biege ich das gerade?



  • Indem du seqSearchKDat mit dem gesamten Feld aufrufst oder in seqSearchKDat nur das übergebene Element vergleichst.

    w=seqSearchKDat(&err[0], dat, n1, n2);
    

    oder

    if(equalKDatum(&(fdata->kdat), kdP))
    

    Was du dadurch noch ändern solltest, musst du mal selber schauen.



  • Das verstehe ich nicht.
    Hast du Stichworte für diese Thematik, dann informiere ich mich dadrüber lieber nochmal.



  • Arrays und Zeiger.



  • Bisschen genauer vllt?



  • Indizes fangen immer bei 0 an.

    Eine Funktion kann nicht feststellen wie groß das Array ist.

    Da ich dein Buch nicht kenne, kann ich dir leider nicht die Seite nennen.


Anmelden zum Antworten