2017-02-17 2 views
0

Ich schreibe eine Funktion next_node, die nächste Datei im Verzeichnis findet. Knoten nimmt ein Verzeichnis und einen Dateinamen als Eingabe.Segmentierung Fehlerprüfung strcmp

Ich will es NULL zurück, wenn es keine andere Datei nach bname oder wenn es ist "." oder "..". Es gibt mir segmentation fault (core dumped) NUR wenn es innerhalb der if Anweisung von strcmp läuft.

Können Sie das Problem erklären oder bitte eine Lösung geben?

Code:

#include <stdio.h> 
#include <dirent.h> // DIR opendir() closedir() struct dirent readdir() 
#include <string.h> // strcmp() 

char *next_node(char *dname, char *bname) { 
    if (!strcmp(dname, bname)) { 
     // dname same as bname 
     return NULL; 
    } 
    DIR *dirp = opendir(dname); 
    struct dirent *direntp; 
    while (((direntp = readdir(dirp)) != NULL) && (strcmp(direntp->d_name, bname))) { 
    } 
    if ((direntp = readdir(dirp)) != NULL) { 
     // if d_name is "." or ".." return NULL 
     if ((strcmp(direntp->d_name, ".")) || (strcmp(direntp->d_name, ".."))) { 
      return NULL; 
     } 
     // it can reach here with no problem 
     closedir(dirp); 
     return direntp->d_name; 
    } else { 
     closedir(dirp); 
     return NULL; 
    } 
} 

int main() { 
    char *dname = "."; 
    char *bname = "test.c"; 
    char *result = next_node(dname, bname); 
    printf("%s\n", result); 
    return 0; 
} 
+0

Beginnen Sie mit einigen Fehlerprüfung ... speziell auf "opendir" –

+0

Dieser Code macht keinen Sinn. Ihr Schleifenkörper ist leer. –

+0

Die while-Schleife funktioniert, wenn die 'bname' und' dname' existieren. Ich habe 'bname' und' dname' überprüft, bevor ich die Funktion in einem anderen Teil meines Programms verwende. –

Antwort

3

Sie haben fünf Fehler.

1:

DIR *dirp = opendir(dname); 

Sie überprüfen nicht, ob dies opendir gelingt.

2:

struct dirent *direntp; 
while (((direntp = readdir(dirp)) != NULL) && (strcmp(direntp->d_name, bname))) { 
} 
if ((direntp = readdir(dirp)) != NULL) { 

Hier rufen Sie readdir auch wenn die vorherige Schleife beendet, weil readdirNULL zurückgegeben. Sie wollen:

if ((direntp != NULL) && ((direntp = readdir(dirp)) != NULL)) { 

3:

if ((strcmp(direntp->d_name, ".")) || (strcmp(direntp->d_name, ".."))){ 

Konvertieren eine ganze Zahl mit einem boolean zu fragen entspricht, wenn es nicht Null ist. Die Funktion strcmp gibt bei einer Übereinstimmung null zurück. Wenn Sie also fragen, ob es nicht Null ist, fragen Sie, ob es nicht ist. Aber alles passt entweder nicht zu "." oder kein Match für ".."! Sie wollen:

if ((!strcmp(direntp->d_name, ".")) || (!strcmp(direntp->d_name, ".."))){ 

4:

// it can reach here with no problem 
    closedir(dirp); 
    return direntp->d_name; 

Sie gerade einen Zeiger in einem Verzeichnis, das Sie geschlossen, wodurch der Zeiger ungültig. Sie müssen entscheiden, wie die Lebensdauer des zurückgegebenen Zeigers sein soll, und vielleicht etwas zurückgeben.

Vielleicht:

char *ret = strdup (dirent->d_name); 
    closedir(dirp); 
    return ret; 

Beachten Sie, dass der Anrufer die zurückgegebene Zeichenfolge free muss, wenn es mit ihm fertig ist.

5:

char *result = next_node(dname, bname); 
printf("%s\n", result); 

Dies wird fehlschlagen, wenn die resultNULL ist. Versuchen:

char *result = next_node(dname, bname); 
printf("%s\n", (result == NULL) ? "NULL" : result); 
+0

Habe ich die Chance verloren, 'ret' freizugeben, wenn die Funktion 'NULL' zurückgibt? –

+0

@katharineKim Mit meiner vorgeschlagenen Änderung wird 'strdup' nur aufgerufen, wenn wir etwas anderes als' NULL' zurückgeben. –

+0

Danke für die Erklärung meiner Fehler. Ich habe Ihren Ansatz genommen, aber es gibt immer noch Segmentfehler, wenn es innerhalb von 'if (strcmp) {}' läuft. –

-1

strcmp liefert 0, wenn es keinen Unterschied zwischen ihnen versuchen, ist die folgende Stelle

if (strcmp(dname, bname)) { 
    return NULL; 
} 

edit: auch ich bin nicht sicher, was Sie Ausgabe, die ich‘ m das kompilieren mit gcc auf Windows und ich habe keine Probleme damit.

+0

Es wäre kein Problem auf Windows, weil 'readdir' hat eine andere Reihenfolge zu Linux. Im Falle von Windows wird der Code nie einen Fall erreichen, der 'direntp-> d_name' ist' "." 'Oder' ".." ' –

+0

@katharineKim guter Punkt, auch ein TIL. kompiliert es auf Linux und bekam den Segmentierungsfehler. Wie auch immer, ich glaube, Ihr Problem ist nicht die if-Anweisung, sondern der 'return NULL;' -Teil. Sie müssen ein 'char *' zurückgeben. Ich habe versucht, "Return" \ 0 ";" und es funktioniert auf dem Linux-Rechner, also vielleicht versuchen Sie das? Sie erhalten immer noch einen Segmentierungsfehler mit dem Rest des Codes, aber David scheint das für Sie geantwortet zu haben – zee

+0

Interessant gefunden @zee. Da 'char *' ein Zeiger ist und 'NULL' auch ein Zeiger ist, sollte es gut sein,' NULL' zurückzugeben. Ich frage mich, warum es funktioniert hat, NULL irgendwo anders im Code zurückzugeben, aber nicht in dem, wenn ich 'strcmp' verwende. –

0

(Geschrieben im Auftrag des OP).

Update: Das Problem war NULL in Haupt drucken. Drucken von NULL gibt nur segfault in Linux, aber nicht in Windows.