0

I wrote a post earlier about scandir(), but figured I'd make a new post since I believe the requirement is to only have one question per post.

I'm writing a program that uses scandir() and getting a incompatible pointer type warning when I run the program.

According to the man-page for scandir(), the function takes in a "triple pointer" to a dirent struct:

int scandir(const char *dirp, struct dirent ***namelist,
              int (*filter)(const struct dirent *),
              int (*compar)(const struct dirent **, const struct dirent **));

However, the page also provides the example below:

#define _DEFAULT_SOURCE
       #include <dirent.h>
       #include <stdio.h>
       #include <stdlib.h>

       int
       main(void)
       {
           struct dirent **namelist;
           int n;

           n = scandir(".", &namelist, NULL, alphasort);
           if (n == -1) {
               perror("scandir");
               exit(EXIT_FAILURE);
           }

           while (n--) {
               printf("%s\n", namelist[n]->d_name);
               free(namelist[n]);
           }
           free(namelist);

           exit(EXIT_SUCCESS);
       }

In my program, I decided to follow the example and have the code in my program below (distilled to only the statements relevant to scandir()):

int numOfDirectories = 0;
struct dirent **dirEntries;
numOfDirectories = scandir(".", &dirEntries, NULL, alphasort);

When I run the program, I then get the warning below:

Compiler warning

Why would it be giving me this error when I'm essentially following the example it has in the man-page?

Further, according to information received from my other post, passing in &dirEntries when dirEntries is a double-pointer should be a triple-pointer.

I did try changing the program by declaring dirEntries as a triple pointer:

int numOfDirectories = 0;
struct dirent ***dirEntries;
numOfDirectories = scandir(".", dirEntries, NULL, alphasort);

I don't get any compiler errors, but when I run the program I then get a Segmentation fault (core dumped) error.

I did have a filter function as the 3rd parameter, but decided to just set to NULL in-case it was my filter function causes the error. Still get the same segmentation fault error using NULL.

I also tried running the debugger, which it does show this: Debugger View

Then essentially after I declare my dirEntries I have an if-statement that is entered and immediately runs numOfDirectories = scandir(".", &dirEntries, NULL, alphasort);

I'm at a loss of what is going on. Any ideas what it could be? Thank you. Appreciate your help and feedback.

GainzNerd
  • 312
  • 1
  • 10

1 Answers1

1

Why would it be giving me this error when I'm essentially following the example it has in the man-page?

You are not following the example. The example declares a thing with type struct dirent ** and passes its address, using &. You declare a thing with type struct dirent ** and pass it, not its address, not using &.

Change your code to pass &dirEntries, not dirEntries.

I did try changing the program by declaring dirEntries as a triple pointer: … I don't get any compiler errors, but when I run the program I then get a Segmentation fault (core dumped) error.

The thing you pass had the right type, but it did not have a correct value. scandir does not just want you to pass something of type struct dirent **, it wants you to pass the address of a struct dirent ** that you provide. This is because it is going to fill in that struct dirent ** with some value. (That value will be a struct dirent **; it will point to a struct dirent *.)

When you make dirEntries with struct dirent ***dirEntries;, you do not give it any value, so passing it as an argument is wrong. In contrast, struct dirent **dirEntries makes a pointer, and then passing &dirEntries gives the address of that pointer to scandir. It uses that address to put a value in dirEntries.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thanks for the feedback. Regarding your first point, I actually did use the address-of operator to pass the address of `struct dirent **`. On your second point, in a sense I see what you're saying, but having difficulty wrapping my head around it. The documentation says it want's a triple pointer, so I'm passing a triple pointer. – GainzNerd Dec 13 '20 at 01:08
  • One thing I realized is with my "incompatible pointer type" warning, it was due to another statement later on that was just using `dirEntries` and not `&dirEntries`. So I commented that out and now everything compiles and runs correctly. Still not sure about the issue regarding double vs. triple pointer. – GainzNerd Dec 13 '20 at 01:17
  • 1
    Re “The documentation says it want's a triple pointer, so I'm passing a triple pointer”: So? The documentation for `sqrt` says it takes a `double`, but if you do `double x; printf("%g\n", sqrt(x));`, what do you get? `x` was never initialized, so it has no determined value. When you pass `scandir` an uninitialized pointer, it gets a pointer with no determined value. When it tries to use that pointer, something goes wrong. You have to pass a particular value, not just something matching in type. – Eric Postpischil Dec 13 '20 at 01:20