I was trying to make a little script to get me started on handling pointers, and allocating and deallocating memory in C.
In this script I'm trying to recursively fetch folders and files using the package dirent.h
.
This is the script:
// Packages
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
// Constants
#define root "/"
#define currentDir "."
#define prevDir ".."
#define binDir "bin"
#define gitDir ".git"
// Structs
struct filesArray {
int currentArrayDirectoryElements;
int currentArrayFileElements;
const char** arrayDirectoriesPtr;
const char** arrayFilesPtr;
};
/*
concat concatenates two referenced strings,
returns concatenated string or exit
*/
char* concat(const char* s1, const char* s2)
{
char* result = malloc(strlen(s1) + strlen(s2) + 1); // null term
if (result == NULL) {
fprintf(
stderr,
"Fatal: failed to concatenate strings: %s and %s",
s1, s2
);
exit(0);
}
strcpy(result, s1);
strcat(result, s2);
return result;
}
/*
readDirAddFile recursively reads the passed in directory and adds each file to
the filesArray struct passed as a reference.
*/
void readDirAddFile(const char* dirPath, struct filesArray* filesArray)
{
printf("************ Getting out ************\n");
printf("Current path passed in: %s\n", dirPath);
printf("Current path pointer passed in: %p\n", dirPath);
printf("*************************************\n");
// Fetch files and add their local dir path to array
DIR* dir = opendir(dirPath);
if (dir == NULL) {
return;
}
// Read current directory
struct dirent* entity = readdir(dir);
// Create and allocate a string path to the current dir
const char* pathToDir = concat(dirPath, (const char *) &root);
printf("************ Starting looping ************\n");
printf("Current directory: %s\n", pathToDir);
printf("Current directory pointer: %p\n", pathToDir);
printf("*************************************\n");
// Iterate through all directory elements
while (entity != NULL) {
printf("\nType: %hhd, Name: %s\n", entity->d_type, entity->d_name);
// File
printf("File: %d\n", entity->d_type == DT_REG);
if (entity->d_type == DT_REG) {
// Add file path to array
const char* filePath = concat(pathToDir, (const char *) &entity->d_name);
// Alloctae Element
printf("Filepath String: %s\n", filePath);
printf("Array files ptr: %p, %d\n", filesArray->arrayFilesPtr, filesArray->currentArrayFileElements);
printf("Element ptr: %p\n", filePath);
filesArray->arrayFilesPtr[filesArray->currentArrayFileElements] = filePath;
printf("Element allocated: %s\n", filesArray->arrayFilesPtr[filesArray->currentArrayFileElements]);
// Bk
filesArray->currentArrayFileElements += 1;
}
// Directory
printf("Directory: %d, current dir: %d, prev dir: %d, Bin dir: %d\n", entity->d_type == DT_DIR, strcmp(entity->d_name, currentDir) != 0, strcmp(entity->d_name, prevDir) != 0, strcmp(entity->d_name, binDir) != 0);
if (
entity->d_type == DT_DIR
&& strcmp(entity->d_name, currentDir) != 0
&& strcmp(entity->d_name, prevDir) != 0
&& strcmp(entity->d_name, binDir) != 0
&& strcmp(entity->d_name, gitDir) != 0
) {
// Generate path
const char* newDir = concat(pathToDir, (const char *) &entity->d_name);
printf("************ Passing in ************\n");
printf("Recursing directory Path: %s\n", newDir);
printf("Recursing directory Pointer: %p\n", newDir);
printf("*************************************\n");
readDirAddFile(newDir, filesArray);
// Recurse fetch
filesArray->arrayDirectoriesPtr[filesArray->currentArrayDirectoryElements] = newDir;
// Bk
filesArray->currentArrayDirectoryElements += 1;
}
entity = readdir(dir);
};
// Close read and path to dir
printf("\nClosing directory at path: %s\n\n", pathToDir);
closedir(dir);
free((void *) pathToDir);
return;
}
/*
fetchFiles runs through the whole directory and stores all files' path
into an array of strings pointers.
returns a pointer to the array, its max elements and current present elements,
namely a filesArray.
*/
void fetchFiles(struct filesArray* filesArray)
{
// Recursively read from dir root
readDirAddFile((const char *) ¤tDir, filesArray);
// Return the filesArray struct
return;
}
/*
main execution
*/
int main()
{
// Track execution
clock_t begin = clock();
// printf() displays the string inside quotation
printf("Scanning for invalid URLs and Local Paths\n\n");
// Init filesStuct
struct filesArray filesArray = {
.currentArrayDirectoryElements = 0,
.currentArrayFileElements = 0,
.arrayFilesPtr = malloc(sizeof(char*)),
.arrayDirectoriesPtr = malloc(sizeof(char*)),
};
printf("Current directory: before fetchfiles\n\n");
fetchFiles(&filesArray);
printf("\nArray Pointer: %p \nCurrent Elements: %d \n",
filesArray.arrayFilesPtr,
filesArray.currentArrayFileElements
);
// Bk
// Files
for (int i = 0; i < filesArray.currentArrayFileElements; ++i) {
printf("\n\n");
printf("\nFreeing File Element: %s, At pointer: %p\n", filesArray.arrayFilesPtr[i], filesArray.arrayFilesPtr[i]);
free((void *) filesArray.arrayFilesPtr[i]);
};
free((void *) filesArray.arrayFilesPtr);
// Paths
for (int i = 0; i < filesArray.currentArrayDirectoryElements; ++i) {
printf("\n\n");
printf("\nFreeing File Element: %s, At pointer: %p\n", filesArray.arrayDirectoriesPtr[i], filesArray.arrayDirectoriesPtr[i]);
free((void *) filesArray.arrayDirectoriesPtr[i]);
};
free((void *) filesArray.arrayDirectoriesPtr);
// Calculate execution Time
clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("\n\nScript took: %fs\n", time_spent);
// End
return 0;
}
You can also find it in a relpit here https://replit.com/@EliaRiva/FolderFetcher?v=1
The problem is that I deallocate a pointer that is pointing to an empty memory address. I can spot that the problem of the script is probably related to when it goes back from the deepest directory to continue the fetch, and it is concatenating a string with a pointer that is not pointing to the correct string anymore.
Still, I can find what is causing this. Thank you for your help and time.
Tried running the script logging out each passage; I may have found the problem but I can't resolve it.
As suggested from Jonathan Leffler, I'm posting a self-response for people looking for an implemented solution.
The error occurs because the pointer pointing to an array of char pointers (char** PointingToAnArrayOfCharPointers) had an allocation of memory of just one pointer element, thus having undefined behaviour for any exceeding element. Note that the error wasn't happening shortly after allocating an extra element but after a few.
The solution is simple, check wether you have enough allocated space for elements and if not, increase the space size by allocating new memory for the array and coping over old values. Don't forget to deallocate the old array (free) and update the new pointer.
Implementation: