Miniklausur 25.10.12

getSortedEntries

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

Miniklausur 25.10.12
Habe mal versucht, Aufgabe 2 zu implementieren. Allerdings versagt meine Lösung (spätestens) beim Sortieren.
Erkennt da jemand, was ich falsche mache?

#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#define abs(a) ( ( (a) < 0 ) ? (-a) : (a) )

// Tupel-Struktur
struct Entry {
	char name[NAME_MAX + 1];
	off_t size;
};

int entryCompare(const void* a, const void* b) {
	// Hilfsfunktion fuer qsort
	struct Entry* first = (struct Entry*) a;
	struct Entry* second = (struct Entry*) b;
	
	if (first->size > second->size) {
		return 1;
	} else if (first->size == second->size) {
		return 0;
	} else {
		return -1;
	}
}


int getSortedEntries(struct Entry entries[], unsigned int maxEntries) {
	
	int count = 0;
	DIR* dir = NULL;
	
	if (NULL == (dir = opendir("."))) {
		return 0;
	}
	
	struct dirent* entry;
	struct stat buf;
	errno = 0;
	
	while (NULL != (entry = readdir(dir))) {
		if (count >= maxEntries) {
			// Array war zu klein
			count = -count; // = -maxEntries
			break;
		}
		char* name = entry->d_name;
		if (-1 == lstat(name, &buf)) {
			return 0;
		}
		entries[count].size = buf.st_size;
		strcpy(entries[count].name, name);
		
		count++;
		errno = 0;
	}
	
	// Fehlerueberpruefung von readdir
	if (errno != 0) {
		return 0;
	}
	
	qsort((void*) entries, abs(count), sizeof(struct entry*), entryCompare);
	
	closedir(dir);
	return count;
}

Und zum Testen:

int main(int argc, char* argv[]) {
	
	unsigned int maxEntries = 10;
	struct Entry entries[10];
	int found = getSortedEntries(entries, maxEntries);
	
	for (int i=0; i<maxEntries && i < abs(found); i++) {
		printf("%lld\t%s\n", (long long) entries[i].size, entries[i].name);
	}
	
	return EXIT_SUCCESS;
}

#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
 
#define abs(a) ( ( (a) < 0 ) ? (-a) : (a) )
 
// Tupel-Struktur
struct Entry {
	char name[NAME_MAX + 1];
	off_t size;
};
 
int entryCompare(const void* a, const void* b) {
	// Hilfsfunktion fuer qsort
	struct Entry* first = (struct Entry*) a;
	struct Entry* second = (struct Entry*) b;
   
	if (first->size > second->size) {
		return -1;
	} 
	
	if (first->size < second->size) {
		return 1;
	}
	
	return strcmp(first->name, second->name);	
}
 
 
int getSortedEntries(struct Entry entries[], unsigned int maxEntries) {
   
	int count = 0;
	int retVal = 0;
	DIR* dir = NULL;
   
	if (NULL == (dir = opendir("."))) {
		return 0;
	}
   
	struct dirent* entry;
	errno = 0;
   
	while (NULL != (entry = readdir(dir))) {
		struct stat buf;
		
		if (count >= maxEntries) {
            // Array war zu klein
            retVal = -maxEntries; // = -maxEntries
            break;
        }
		
		if (lstat(entry->d_name, &buf) == -1) {
			return 0;
		}
		
		entries[count].size = buf.st_size;
		strcpy(entries[count].name, entry->d_name);
		count++;
		retVal = count;
		errno = 0;
	}
   
	// Fehlerueberpruefung von readdir
	if (errno != 0) {
		return 0;
	}
   
	qsort((void*) entries, count, sizeof(struct Entry), entryCompare);
	   
	closedir(dir);	
	return retVal;
} 

int main(int argc, char* argv[]) {
   
	unsigned int maxEntries = 10;
	struct Entry entries[10];
	int found = getSortedEntries(entries, maxEntries);
	printf("Found Entries: %d\n\n", found);
	
	for (int i=0; i<maxEntries && i < abs(found); i++) {
		printf("%lld\t%s\n", (long long) entries[i].size, entries[i].name);
	}
   
	return EXIT_SUCCESS;
}  

sizeof(struct Entry) nicht sizeof(struct entry*). Außerdem hat das alphabetische sortieren gefehlt und aufsteigend statt absteigend.


#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define p printf("%d\n",


//Tupel-Struktur
struct Entry{
	char name[NAME_MAX + 1];
	off_t size;
};
typedef struct Entry Entry;
//Hilfsfunktion fuer qsort()


static int compare(const void *c, const void *d){
	Entry* a = (Entry *)c;
	Entry* b = (Entry *)d;
	if(a-> size < b->size) return 1;
	if(a-> size > b->size) return -1;
	return (strcmp (a->name, b->name));
}

//Funktion getSortedEntries()

int getSortedEntries(struct Entry entries[], unsigned int maxEntries){
	char *cWD = NULL;
	
	if(NULL ==(cWD = getcwd(cWD, 0)))
		return 0;	

	DIR *oDir;
	if(NULL == (oDir = opendir(cWD)))
		return 0;

	struct dirent *rD;
	unsigned int count = 0;
	while(errno = 0, (rD = readdir(oDir)) != NULL){
		if(maxEntries <= count) break;
		
		char newPath [300];
		sprintf(newPath, "%s/%s", cWD, rD->d_name);
		struct stat statCheck;
		if(lstat(newPath, &statCheck))
			return 0;
			
		strcpy(entries[count].name, rD->d_name);
		entries[count++].size = statCheck.st_size;
	}
	if(errno || closedir(oDir))	return 0;

	qsort((void*)entries, count, sizeof(Entry), compare);

	if(maxEntries <= count) return -count;
	return count;
}


int main(int argc, char* argv[]) {
   
    unsigned int maxEntries = 30;
    struct Entry entries[maxEntries];
    int found = getSortedEntries(entries, maxEntries);
    printf("Found Entries: %d\n\n", found);
   
    for (int i=0; i<maxEntries && i < abs(found); i++) 
        printf("%lld\t%s\n", (long long) entries[i].size, entries[i].name);
     
    return EXIT_SUCCESS;
} 

Wenn ich nicht irre entspricht CurrentWorkingDirectory nicht zwingend “.” ! Wenn die Datei beispielsweise über ein Link aufgerufen wird.
Lstat benötigt auch den kompletten Pfad und nicht nur den Dateinamen.
Weiterhin kann man wenn man lustig ist auch closedir noch auf Fehler abfragen.

Edit: Hilfsmethoden: static!


[m]getcwd(x, NULL)[/m] ist nicht in POSIX spezifiziert, also nicht erlaubt. Außerdem fehlt danach das [m]free(3)[/m].

Hier musst du noch die [m]errno[/m] auf 0 setzen, da der Wert der [m]errno[/m] nach einem erfolgreichen Bibliotheksfunktionsaufruf nicht definiert ist.

Ich hab mir die Aufgabe nicht durchgelesen, aber ist die Pfadlänge wirklich auf 300 Zeichen limitiert? Sinnvoller wäre es hier, [m]newPath[/m] passend lang zu erzeugen:

    char newPath[strlen(cWD) + 1 + strlen(rD->d_name) + 1];

Allerdings liegt die Datei ja sowieso im aktuellen Arbeitsverzeichnis, also brauchst du das nicht. Einfach nur der Dateiname reicht hier, da es ja immer relativ zum aktuellen Arbeitsverzeichnis gehandhabt wird.

Doch, das aktuelle Arbeitsverzeichnist ([m]getcwd(3)[/m]) ist immer „.“! Wie die Datei aufgerufen wird ist egal. [m]getcwd(3)[/m] braucht man eigentlich nur, wenn man das Arbeitsverzeichnist ausgeben will, aber nicht wenn man relativ dazu Pfade braucht.

Nein, da die Dateien im aktuellen Verzeichnis sind, reicht der Dateiname.

Kann man, braucht man aber nicht.

1 Like

bedeutet das nicht auch ich kann es so lassen?

Natürlich ist sie nicht auf 300 limitiert. Das war lediglich provisorisch damits kompiliert und habs dann vergessen auszubessern.

Awesome! danke dir!
Edit: nochmal die manpage gecheckt: etwas schlampig ist das bzgl. der relativen Pfade ja schon spezifiziert.


Nein. Du prüfst nach der Schleife die [m]errno[/m] und da diese auch im Erfolgsfall != 0 sein kann, wird das [m]return 0[/m] ausgeführt, obwohl kein Fehler aufgetreten ist.

1 Like

Ah ja, genau lesen/denken will gelernt sein. :smiley: