Click here to Skip to main content
15,564,017 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
void listdir(char *path){
    DIR *dir;
    struct dirent *entry;
    char hello[PATH_MAX];
    
    if (!(dir = opendir(path))) {  
        perror ("opendir-path not found");
        return;
    }

    while ((entry = readdir(dir)) != NULL) {  
        char *name = entry->d_name;
        if (entry->d_type == DT_DIR)  
            if (!strcmp(name, ".") || !strcmp(name, ".."))
                continue;
        snprintf (hello, 100, "%s/%s\n", path, name);
        // printf("%s", hello);
        
        // Splitting method 1
        // char *token1 = strtok(hello, "\n");
        // char *token2 = strtok(NULL, "\n");
        // printf("%s\n",token1);

        // Splitting method 2
        char words[100][100];
        size_t indexCtr = 0;
        int wordIndex = 0, totalWords = 0;

        for(indexCtr = 0; indexCtr <= strlen(hello); indexCtr++){
            if(hello[indexCtr] == '\n' || hello[indexCtr] == '\0'){
                words[totalWords][wordIndex] = '\0';
                totalWords++;
                wordIndex = 0;
            }
            else{
                words[totalWords][wordIndex] = hello[indexCtr];
                wordIndex++;
            }
        }
        printf("%s\n", words[0]);
        
        if (entry->d_type == DT_DIR) {
            char *p; 
            strcat (path, "/");
            strcat (path, name);
            listdir(path);
            if ((p = strrchr (path, '/'))) {
                if (p != path)        
                    *p = 0;          
            }
        }
    }
    closedir (dir); 
}


What I have tried:

In this code, I am getting the pathnames successfully and I could print them also using hello variable but I want to split them one by one. I used strtok for this purpose but it was not giving me the required result. I don't know why? Then I wrote more code to tokenize the paths so that I could print them according to my choice that which one to print. But when I print the words[0], it prints all the pathnames. When I print words[1], it shows me nothing.
Posted
Updated 19-Feb-21 6:44am
v4
Comments
Rick York 19-Feb-21 1:47am    
Deja vu, all over again. I see you are still using global variables with your recursive function. Did you not read my previous reply? You need to because it is a major roadblock here.
ibilalkayy 19-Feb-21 2:36am    
I used it but the result was not as I wast expected.
I want it to split the string when there is "\n" but when I print the words[0], it gives me all the pathnames instead of just the first one. And when I print words[1] it shows nothing.

I debugged the code. When I print the words[0] it gives me this result.

$1 = "/home/runner/TestC1/folder1", '\000' <repeats 67="" times="">

And when I print the words[1] it gives the result.

$2 = '\000' <repeats 99="" times="">

When I print the path1 it gives me the result

$3 = '\000' <repeats 4095="" times="">

When I print the path it gives me the result

$4 = "/home/runner/TestC1/folder1", '\000' <repeats 4068="" times="">
Rick York 19-Feb-21 4:09am    
That is not why you got errant results. It will be IMPOSSIBLE to get correct results using the global variables with a recursive function, as you are. It is just not going to happen so start by fixing that. Then you can address your tokenizing issue.

Also, you handled the DT_DIR case OK but the snprintf call looks out of place. You should have gone the strcat route there too. Also, 100 is just too small for a full path name. It's pretty easy to get path names that are longer than that, especially in windows. There, the maximum path name is defined as 260 (MAX_PATH).
ibilalkayy 19-Feb-21 2:38am    
The result this opendir-path not found: No such file or directory after writing the variables locally. I don't know how to solve. Will you please help me?
Rick York 19-Feb-21 4:13am    
Yes, I will try but ONLY after you get rid of the global variables. Do that first. After that, I would set up the code to build the full path name of each file it encounters and prints them - nothing more than that. That will verify that you are walking the directory structure correctly and managing the file names right. After that you can address the tokenizing. I advocate incremental development and testing so you can verify things are working right at every step along the way.

Compiling does not mean your code is right! :laugh:
Think of the development process as writing an email: compiling successfully means that you wrote the email in the right language - English, rather than German for example - not that the email contained the message you wanted to send.

So now you enter the second stage of development (in reality it's the fourth or fifth, but you'll come to the earlier stages later): Testing and Debugging.

Start by looking at what it does do, and how that differs from what you wanted. This is important, because it give you information as to why it's doing it. For example, if a program is intended to let the user enter a number and it doubles it and prints the answer, then if the input / output was like this:
Input   Expected output    Actual output
  1            2                 1
  2            4                 4
  3            6                 9
  4            8                16
Then it's fairly obvious that the problem is with the bit which doubles it - it's not adding itself to itself, or multiplying it by 2, it's multiplying it by itself and returning the square of the input.
So with that, you can look at the code and it's obvious that it's somewhere here:
C#
int Double(int value)
   {
   return value * value;
   }

Once you have an idea what might be going wrong, start using the debugger to find out why. Put a breakpoint on the first line of the method, and run your app. When it reaches the breakpoint, the debugger will stop, and hand control over to you. You can now run your code line-by-line (called "single stepping") and look at (or even change) variable contents as necessary (heck, you can even change the code and try again if you need to).
Think about what each line in the code should do before you execute it, and compare that to what it actually did when you use the "Step over" button to execute each line in turn. Did it do what you expect? If so, move on to the next line.
If not, why not? How does it differ?
Hopefully, that should help you locate which part of that code has a problem, and what the problem is.
This is a skill, and it's one which is well worth developing as it helps you in the real world as well as in development. And like all skills, it only improves by use!
 
Share this answer
 
Comments
ibilalkayy 19-Feb-21 2:36am    
I want it to split the string when there is "\n" but when I print the words[0], it gives me all the pathnames instead of just the first one. And when I print words[1] it shows nothing.

I debugged the code. When I print the words[0] it gives me this result.

$1 = "/home/runner/TestC1/folder1", '\000' <repeats 67="" times="">

And when I print the words[1] it gives the result.

$2 = '\000' <repeats 99="" times="">

When I print the path1 it gives me the result

$3 = '\000' <repeats 4095="" times="">

When I print the path it gives me the result

$4 = "/home/runner/TestC1/folder1", '\000' <repeats 4068="" times="">
OriginalGriff 19-Feb-21 2:42am    
So how - exactly - did you debug the code?

What did you do with the debugger?
what did it show you was happening while your code was running?
ibilalkayy 19-Feb-21 2:44am    
It just print those messages that I showed you.
OriginalGriff 19-Feb-21 3:24am    
So ... when you said "I debugged the code" what you meant is "I got it to compile and ran it".

Debugging is not "running the code" it's a process which means looking at what your code is doing, and how that differs from what you expected it to do, and using that to find out why, and how you alter your code to make sure it doesn't.

"Running the code" is called "very basic testing".

Now, break out whatever debugger comes with your IDE / compiler - Google will help you there - and start looking at what your code it doing while it runs.
ibilalkayy 19-Feb-21 3:29am    
By debugging I mean debugging. I am not an idiot. The result I showed you.
The strtok function works fine, I have been using it for years. The problem was that your code was incorrect. Did you read the documentation properly? And you could get rid of your globals by using proper parameters in your functions. So you could have something like:
C++
void listdir(char* pszPath){
    if (!(dir = opendir(pszPath))) {  
        perror ("opendir-path not found");
        return;
    }
// rest of code here
}

int main (int argc, char **argv) { 
    char* dirPath; // use a pointer rather than copying text everywhere.
    if (argc > 1)
        dirPath = argv[1];
    else
        dirPath = "/home/runner/TestC1";
    listdir(dirPath);

    return 0;
}
 
Share this answer
 
Comments
ibilalkayy 19-Feb-21 5:34am    
I updated the code also. You can see it but it is still not working. Thanks!
Richard MacCutchan 19-Feb-21 7:05am    
What does "it is still not working." mean? Please, when you have a problem, you need to explain it in full detail. We cannot guess what you are seeing.
ibilalkayy 19-Feb-21 8:45am    
I wrote the description in which I wrote that which thing is not working.
Richard MacCutchan 19-Feb-21 9:00am    
It is still not clear what you are trying to do in your code. Why are you using the newline character ("\n") as the separator in your split code? Directory paths use the forward slash ("/") or backward slash ("\\") characters. So, once again, please explain in full and clear detail what is the problem.
Here is a function I have used a LOT for parsing tokens. It does destructive parsing (because of strtok) so the delimiters are nulled. This means you should make a copy of the original string if you need to retain it. Here's the code :
C++
// parse a string into tokens
typedef char *      PTSTR;
typedef const PTSTR PCTSTR;

int ParseItems( PTSTR buffer, PCTSTR delims, PTSTR tokens[], int maxTokens )
{
    PTSTR pbuffer = buffer;
    int tokenCount = 0;
    for( int x = 0; x < maxTokens; x += 1 )
    {
        PTSTR cptr = strtok( pbuffer, delims );
        if( ! cptr )
            break;

        tokens[ tokenCount ] = cptr;
        ++tokenCount;
        pbuffer = nullptr;
    }
    return tokenCount;
}
You can see from the typedefs that it is used primarily in windows code and it is unicode-capable - change strtok to _tcstok for the TCHAR-version. Normally it's a bad idea to use a fixed-sized array of tokens like that but in C there are few alternatives. I have a C++ version that builds a vector of tokens. Anyway, the key to using strtok is to pass it your string the first time and then null thereafter which tells it to use the last string it was passed. Here's a sample of using it, assuming you have a text string in buffer.
C++
#define MAX_TOKENS 64
PTSTR tokens[ MAX_TOKENS ];
PCTSTR delimiters = "/\r\n";
int tokenCount;
tokenCount = ParseTokens( buffer, delimiters, tokens, MAX_TOKENS );
That will give you an array of pointers to tokens found in buffer. The pointers are pointing into buffer and each delimiter has been nulled. Here's a way you can print them :
C++
int n;
for( n = 0; n < tokenCount; ++n )
     printf( "token %d is '%s'\n", n + 1, tokens[ n ] );
 
Share this answer
 
Comments
Rick York 19-Feb-21 12:53pm    
I would add - if you wanted to be truly dynamic, and could afford the performance cost, you could adapt that function to build a linked list of the token pointers OR it actually make copies of the strings. Both are possible.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900