Frage zu Zeigervektoren

28/04/2008 - 20:46 von Thomas Barth | Report spam
Hallo,
ich möchte Dateinamen aus einem Verzeichnis nach bestimmten Kritieren in
einen Zeigervektor einlesen. Ist es richtig, dass ich hier mit malloc
arbeiten muss und jedesmal, wenn ich Dateien neu in den Zeigervektor
einlese, vorhier free() drüberlaufen lassen muss und natürlich zum
Programmende? Hier nur mal ein Beispiel:

char *sms_visi_queue[MAX_SMSVISIS];

int main(void) {

// es kann sein, dass zur Laufzeit folgende Funktion
// mehrmals aufgerufen
fillSMSVisiQueue(sms_visi_queue, 2);
fillSMSVisiQueue(sms_visi_queue, 3);
fillSMSVisiQueue(sms_visi_queue, 4);

freeSpace();

return EXIT_SUCCESS;
}

void fillSMSVisiQueue(char **sms_visi_queue, int key) {
DIR *dir;
struct dirent *direntry;
struct stat attribut;

char file[STRLEN] = "",
filebasename[STRLEN] = "";

char *newstring;

key = key - 2;

if(0 > key) {
key = 0;
}

int i, filecnt = 0;

//hier bereits free verwenden?

for (i = 0; i < MAX_SMSVISIS; ++i) {
if(NULL != sms_visi_queue[i]) free(sms_visi_queue[i]);
}

if((dir = opendir(SMSVISI_DIR)) != NULL) {
while((direntry = readdir(dir)) != NULL) {
snprintf(filebasename, STRLEN, "%s", (*direntry).d_name);

snprintf(file, STRLEN, "%s/%s", SMSVISI_DIR, filebasename);

if(filecnt < MAX_SMSVISIS) {

stat(file, &attribut);

if(attribut.st_mode & S_IFREG) {

for (i = 0; i < 4; i++) {
if(chargroups[key][i] == tolower(filebasename[0])) {

//hier mit malloc speicher reservieren?
newstring = (char *) malloc(strlen(filebasename) *
sizeof(char) +1);

if(NULL != newstring) {
strcpy(newstring, filebasename);
sms_visi_queue[filecnt] = newstring;

filecnt++;
break;
}
}
}

}
} else {
break;
}
}

closedir(dir);

//der Rest soll mit einem Leerstring initialisiert werden

for (i = filecnt; i < MAX_SMSVISIS; ++i) {
newstring = (char *) malloc(sizeof(char) +1);
strcpy(newstring, "");
sms_visi_queue[i] = newstring;
}

}
}

void freeSpace() {
int i;

for (i = 0; i < MAX_SMSVISIS; ++i) {
if(NULL != sms_visi_queue[i]) free(sms_visi_queue[i]);
}
}


Wàre schön, ob mir jemand sagen könnte, ob man das so machen kann.

Viele Grüße,
Thomas B
 

Lesen sie die antworten

#1 Thomas Richter
28/04/2008 - 21:23 | Warnen spam
Thomas Barth wrote:
Hallo,
ich möchte Dateinamen aus einem Verzeichnis nach bestimmten Kritieren in
einen Zeigervektor einlesen. Ist es richtig, dass ich hier mit malloc
arbeiten muss und jedesmal, wenn ich Dateien neu in den Zeigervektor
einlese, vorhier free() drüberlaufen lassen muss und natürlich zum
Programmende? Hier nur mal ein Beispiel:

char *sms_visi_queue[MAX_SMSVISIS];



Warum kann es eine Maximalzahl von Eintràgen geben? Wàre eine dynamische
Datenstruktur da nicht angebrachter?

int main(void) {

// es kann sein, dass zur Laufzeit folgende Funktion
// mehrmals aufgerufen
fillSMSVisiQueue(sms_visi_queue, 2);
fillSMSVisiQueue(sms_visi_queue, 3);
fillSMSVisiQueue(sms_visi_queue, 4);



Soll das alte Eintràge überschreiben, an die bestehende Liste anhàngen?

freeSpace();

return EXIT_SUCCESS;
}

void fillSMSVisiQueue(char **sms_visi_queue, int key) {
DIR *dir;
struct dirent *direntry;
struct stat attribut;

char file[STRLEN] = "",
filebasename[STRLEN] = "";

char *newstring;

key = key - 2;

if(0 > key) {
key = 0;
}



Ohne weitere Informationen sieht das erstmal seltsam aus. Zumindest
würde ich irgendwo einen Kommentar einfügen, was "key" denn sein soll,
und wie der "magische" Wert von 2 entsteht.


int i, filecnt = 0;



Das geht so nicht in C, sondern nur in C++.


//hier bereits free verwenden?

for (i = 0; i < MAX_SMSVISIS; ++i) {
if(NULL != sms_visi_queue[i]) free(sms_visi_queue[i]);
}



Die Abfrage, ob der Pointer != NULL ist, ist überflüssig. free() auf
einem NULL-Pointer ist ein NOP. Ob Du hier "alte" Daten freigeben
willst, ist Teil der Definition des Interfaces der Funktion und kann so
nicht beantwortet werden. Falls nein, gehört es zum Interface, dass
freeSpace() manuell aufgerufen wird. Zumindest würde ich emfehlen, den
Pointer (sms_visi_queue[i]) auf NULL zu setzen.


if((dir = opendir(SMSVISI_DIR)) != NULL) {
while((direntry = readdir(dir)) != NULL) {



opendir() und readdir() sind nicht Teil von C. Allerdings, sehr viel
portabler geht es nicht.

snprintf(filebasename, STRLEN, "%s", (*direntry).d_name);



Etwas umstàndlich, aber OK. Warum nicht "direntry->d_name"? Warum
überhaupt das herauskopieren? Was passiert, wenn der Dateiname nicht in
den Buffer passt?

snprintf(file, STRLEN, "%s/%s", SMSVISI_DIR, filebasename);



Warum wird das hier nochmal kopiert?

if(filecnt < MAX_SMSVISIS) {

stat(file, &attribut)



Das ist auch nicht C. (-: Fehlerbehandlung fehlt? Insbesondere, wenn
etwa der Name zu lang war für snprintf?


if(attribut.st_mode & S_IFREG) {

for (i = 0; i < 4; i++) {
if(chargroups[key][i] == tolower(filebasename[0])) {



Nur der erste Buchstabe?


//hier mit malloc speicher reservieren?
newstring = (char *) malloc(strlen(filebasename) *
sizeof(char) +1);



sizeof(char) ist *IMMER* 1, insofern ist diese Multiplikation nicht
wirklich nützlich. Ja, Du musst Speicher allozieren. Fehlerabfrage,
falls malloc fehlschlàgt?

if(NULL != newstring) {
strcpy(newstring, filebasename);
sms_visi_queue[filecnt] = newstring;



Hier würde ich zumindest ein "assert" hineincodieren, um zu überprüfen,
ob im besagten Array-Element nicht schon ein Pointer steht. (Siehe auch
oben!)

filecnt++;
break;
}
}
}

}
} else {
break;



Hier wàre ein Kommentar hilfreich, zu welchem "if" dieses "else" gehört,
sonst darf man Klammern verfolgen.

}
}

closedir(dir);

//der Rest soll mit einem Leerstring initialisiert werden

for (i = filecnt; i < MAX_SMSVISIS; ++i) {
newstring = (char *) malloc(sizeof(char) +1);



Siehe oben. Fehlerbehandlung, sizeof(char) == 1 per Definition.

strcpy(newstring, "");
sms_visi_queue[i] = newstring;
}

}
}

void freeSpace() {
int i;

for (i = 0; i < MAX_SMSVISIS; ++i) {
if(NULL != sms_visi_queue[i]) free(sms_visi_queue[i]);




Siehe oben, überprüfung auf NULL ist nicht notwendig, aber den Pointer
würde ich trotzdem auf NULL setzen.

}
}


Wàre schön, ob mir jemand sagen könnte, ob man das so machen kann.



Die Frage ist eigentlich, wie Dein Interface definiert ist. Das kann Dir
niemand beantworten. Von den obigen "Quirks" abgesehen kann man das
schon so machen, wenn es das ist, was Du machen willst - emfehlen würde
ich es nicht, mit den "vordefinierten" Grenzen von einer Dateilànge und
der Anzahl der Files. Wie wàre es mit einer einfach verketteten Liste
von Directory-Eintràgen, von der jedes Listenelement auf einen passenden
Dateinamen zeigt?

Grüße,
Thomas

Ähnliche fragen