В контексте назначения с использованием C, где мне нужно создать клон li
, я пытаюсь получить доступ ко всем именам дочерних файлов в моем каталоге.
По многочисленным просьбам,вот минимальный код для воспроизведения этой проблемы (пожалуйста, рассмотрите возможность удаления ваших отрицательных голосов ...) (Я не шутил, когда сказал, что это много).
Для начала, создайте где-нибудь эту файловую структуру (. TXT-файлы имеют жонглирование клавиатуры):
var
├── file1.txt
└── var2
├── test -> ../../test
├── var3
│ ├── file2.txt
│ └── file3.txt
└── varfind -> ../
4 directories, 3 files
Код для воспроизведения main.c
#include <stdio.h>
#include <stdlib.h>
#include "helpers.h"
int main(int argc, char **argv) {
char *destination = malloc(sizeof(char[THEORETICAL_MAX_PATH_LENGTH]));
switch (argc) {
case 1: // (== Error case)
fprintf(stderr, "Usage: %s file\n", argv[0]);
exit(EXIT_FAILURE);
break;
case 2: // (== List)
stripSlash(argv[argc - 1], destination);
Object* obj = createNode(destination, NULL);
freeNode(obj);
break;
default:
exit(0);
break;
}
free(destination);
}
helpers.h
#ifndef HEADER_UTILITIES
#define HEADER_UTILITIES
#define THEORETICAL_MAX_PATH_LENGTH 4096
#include <sys/stat.h>
typedef struct {
int numberOfChildren;
char path[2][THEORETICAL_MAX_PATH_LENGTH];
struct stat info;
struct Object **children; // child[0] is parent.
} Object;
void stripSlash(char arg[], char *filename);
void freeNode(Object *node);
Object * createNode(const char *filename, Object *parent);
#endif
helpers.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <dirent.h>
#include "helpers.h"
void stripSlash(char arg[], char *filename) {
strncpy(filename, arg, THEORETICAL_MAX_PATH_LENGTH);
if (filename[strlen(filename) - 1] == '/')
filename[strlen(filename) - 1] = '\0';
}
void getChildren(const char *path, struct stat* statBuffer, char *files[THEORETICAL_MAX_PATH_LENGTH], int *numberOfFiles) {
int count = 0;
struct dirent *currentDir;
if (lstat(path, statBuffer) == 0 && S_ISDIR(statBuffer->st_mode)) {
DIR *folder = opendir(path);
if (access(path, F_OK) != -1) {
if (folder)
while ((currentDir = readdir(folder))) {
if (strcmp(currentDir->d_name, ".") && strcmp(currentDir->d_name, "..")) {
files[count] = (char*) malloc(THEORETICAL_MAX_PATH_LENGTH);
snprintf(files[count], THEORETICAL_MAX_PATH_LENGTH, "%s", currentDir->d_name);
count++;
}
}
free(currentDir);
}
closedir(folder);
} else if (errno < 0)
printf("ERROR %d\n", errno);
*numberOfFiles = count;
}
int rippleCycleCheckUpwards(Object *parent, __ino_t inode) {
if (parent)
if (parent->info.st_ino == inode)
return 1;
else
return rippleCycleCheckUpwards((Object*) parent->children[0], inode);
else
return 0;
}
void freeNode(Object *node) {
node->children[0] = NULL;
for (int i = 1; i < node->numberOfChildren + 1; i++)
freeNode((Object*) node->children[i]);
free(node->children[0]);
free(node->children);
free(node);
node = NULL;
}
Object * createNode(const char *filename, Object *parent) {
Object *node = malloc(sizeof(Object));
char *files[THEORETICAL_MAX_PATH_LENGTH];
char *realDestination = malloc(THEORETICAL_MAX_PATH_LENGTH);
char *res = realpath(filename, realDestination);
strncpy(node->path[0], filename, THEORETICAL_MAX_PATH_LENGTH - 1);
if (res) {
strncpy(node->path[1], realDestination, THEORETICAL_MAX_PATH_LENGTH - 1);
strncat(node->path[1], "\0", 1);
}
free(realDestination);
struct stat *info = malloc(sizeof(struct stat));
lstat(filename, info);
if (S_ISLNK(info->st_mode) == 1) {
getChildren(node->path[1], &node->info, files, &node->numberOfChildren);
} else {
getChildren(node->path[0], &node->info, files, &node->numberOfChildren);
}
free(info);
node->children = malloc((1 + node->numberOfChildren) * sizeof(Object*));
node->children[0] = (struct Object*) parent;
if (rippleCycleCheckUpwards((Object*) parent, node->info.st_ino) == 1) {
node->numberOfChildren = 0;
}
for (int i = 0; i < node->numberOfChildren; i++) {
char nextfile[THEORETICAL_MAX_PATH_LENGTH];
snprintf(nextfile, THEORETICAL_MAX_PATH_LENGTH - 1, "%s/%s", filename, files[i]);
if (S_ISDIR(node->info.st_mode) || S_ISLNK(node->info.st_mode)) {
node->children[i + 1] = (struct Object*) createNode(nextfile, node);
}
free(files[i]);
}
return node;
}
Вы можете создать этот Makefile или gcc:
CC=gcc
CCFLAGS=-Wall -g
LDFLAGS=
SOURCES=$(wildcard *.c)
OBJECTS=$(SOURCES:.c=.o)
TARGET=ultra_cp
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) -o $@ $^ $(LDFLAGS)
%.o: %.c %.h
$(CC) $(CCFLAGS) -c $<
%.o: %.c
$(CC) $(CCFLAGS) -c $<
clean:
rm -f *.o $(TARGET)
Затем протестируйте с make
, затем ./ultra_cp var
для стандартного использования или
valgrind --tool=memcheck --leak-check=yes --track-origins=yes --read-var-info=yes ./ultra_cp var
Моя проблема в том, чтоvalgrind выводит:
HEAP SUMMARY:
==3221== in use at exit: 8,192 bytes in 2 blocks
==3221== total heap usage: 112 allocs, 110 frees, 670,440 bytes allocated
==3221==
==3221== 8,192 bytes in 2 blocks are definitely lost in loss record 1 of 1
==3221== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3221== by 0x108CA1: getChildren (helpers.c:29)
==3221== by 0x108F86: createNode (helpers.c:80)
==3221== by 0x1090F8: createNode (helpers.c:98)
==3221== by 0x1090F8: createNode (helpers.c:98)
==3221== by 0x1091E3: main (main.c:15)
==3221==
==3221== LEAK SUMMARY:
==3221== definitely lost: 8,192 bytes in 2 blocks
==3221== indirectly lost: 0 bytes in 0 blocks
==3221== possibly lost: 0 bytes in 0 blocks
==3221== still reachable: 0 bytes in 0 blocks
==3221== suppressed: 0 bytes in 0 blocks
helpers.c:29
- строка, в которой вызывается files[count] = (char*) malloc(THEORETICAL_MAX_PATH_LENGTH);
, и количество случаев, когда оно не вводится в операторе if.
Это не мешаетфункционирование моего кода, но я бы хотел избежать утечки памяти, если это вообще возможно, и впоследствии поблагодарил бы вас залюбая помощь в этом вопросе.
РЕДАКТИРОВАТЬ
Благодаря пользователю dbush , который предоставил источник проблемы, в том, что в очень конкретном случае, когда rippleCycleCheckUpwards(...)
называетсяЯ не очищаю детей files
.
В helpers.c
можно заменить
if (rippleCycleCheckUpwards((Object*) parent, node->info.st_ino) == 1) {
node->numberOfChildren = 0;
}
на
if (rippleCycleCheckUpwards((Object*) parent, node->info.st_ino) == 1) {
for (int i = 0; i < node->numberOfChildren; i++) {
free(files[i]);
}
node->numberOfChildren = 0;
}