我试图编写一个小脚本来开始处理指针,以及在 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 *) ¤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;
}
您还可以在此处的 relpit 中找到它 https://replit.com/@EliaRiva/FolderFetcher?v=1
问题是我释放了一个指向空内存地址的指针。我可以发现脚本的问题可能与它从最深目录返回以继续获取有关,并且它正在将字符串与不再指向正确字符串的指针连接起来。
不过,我还是能找到造成这种情况的原因。感谢您的帮助和时间。
尝试运行脚本来注销每个段落;我可能已经发现了问题,但我无法解决它。
根据 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;
}