简体   繁体   中英

Segmentation fault checking strcmp

I am writing a function next_node that finds next file in the directory. node takes a directory and a filename as input.

I want it to return NULL if there is no other file after bname or if it is "." or ".." . It is giving me segmentation fault (core dumped) ONLY when it runs inside the if statement of strcmp .

Can you explain the problem or give a solution please?

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;
}

You have five mistakes.

1:

DIR *dirp = opendir(dname);

You don't check if this opendir succeeds.

2:

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

Here, you call readdir even if the previous loop terminated because readdir returned NULL . You want:

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

3:

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

Converting an integer to a boolean is equivalent to asking if it's not zero. The strcmp function returns zero on a match. So asking if it's not zero is asking if it's not match. But everything is either not a match for "." or not a match for ".."! You want:

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

4:

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

You just returned a pointer into a directory that you closed, rendering the pointer invalid. You need to decide what the lifespan of the returned pointer is supposed to be and perhaps allocate some memory to return.

Maybe:

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

Note that the caller needs to free the returned string when it's done with it.

5:

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

This will fail if the result is NULL . Try:

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

(Posted on behalf of the OP) .

Update: The problem was printing NULL in main. Printing NULL only gives segfault in Linux but not Windows.

strcmp returns 0 If there is no difference between them try the following instead

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

edit: also I'm not sure what you're issue is I'm compiling this using gcc on windows and i'm not having any issues with it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM