C 递归目录获取器

问题描述 投票:0回答:1

我试图编写一个小脚本来开始处理指针,以及在 C 中分配和释放内存。

在此脚本中,我尝试使用包

dirent.h
递归地获取文件夹和文件。

这是脚本:

// 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 *) &currentDir, 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;
}

您还可以在此处的 relpit 中找到它 https://replit.com/@EliaRiva/FolderFetcher?v=1

问题是我释放了一个指向空内存地址的指针。我可以发现脚本的问题可能与它从最深目录返回以继续获取有关,并且它正在将字符串与不再指向正确字符串的指针连接起来。

不过,我还是能找到造成这种情况的原因。感谢您的帮助和时间。

尝试运行脚本来注销每个段落;我可能已经发现了问题,但我无法解决它。

c pointers recursion dirent.h
1个回答
0
投票

根据 Jonathan Leffler 的建议,我正在为寻求实施解决方案的人们发布自我回复。

发生该错误的原因是,指向 char 指针数组的指针 (char** PointingToAnArrayOfCharPointers) 只分配了一个指针元素的内存,因此对于任何超出的元素都具有未定义的行为。请注意,错误不是在分配额外元素后不久发生的,而是在分配了几个元素之后发生的。

解决方案很简单,检查是否有足够的分配空间用于元素,如果没有,则通过为数组分配新内存并覆盖旧值来增加空间大小。不要忘记释放旧数组(免费)并更新新指针。

实施:

/*
  increaseArraySize increases the size of a dynamic char pointer to pointers array
*/
void increaseArraySize(
  const char** arrayPtr,
  int* currentMaxElementsPtr,
  int newMaxElements
)
{
  // Store
  int totalNewMaxElements = *currentMaxElementsPtr + newMaxElements;

  // Allocate space for enough elements
  const char** newSizeArray = malloc(*currentMaxElementsPtr * sizeof(char*));

  if (newSizeArray == NULL) {
    fprintf(
      stderr,
      "Fatal: failed to allocate new array space"
    );

    exit(0);
  }

  // Copy old array values into new array
  memcpy(newSizeArray, arrayPtr, (totalNewMaxElements - newMaxElements) * sizeof(char*));

  // Update struct array pointer, max elements and free old array
  *currentMaxElementsPtr = totalNewMaxElements;
  free(arrayPtr);
  arrayPtr = newSizeArray;
}
© www.soinside.com 2019 - 2024. All rights reserved.