Симуляция оболочки с использованием списков - PullRequest
0 голосов
/ 29 марта 2020

Теперь я учусь C, и у меня есть проблема с выделением памяти, по крайней мере это я понимаю из ошибки моего кода.

Код

    #ifndef __FILE_H__
#define __FILE_H__

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct Files Files;
typedef struct DirList DirList;
typedef struct NodeFile NodeFile;
typedef struct NodeDir NodeDir;

typedef struct Directory {
    // The name of the directory
    char *name;

    // TODO: The list of files of the current directory
    Files *files;

    // TODO: The list of dirs of the current directory
    DirList *dirs;

    // The parent directory of the current directory (NULL for the root
    // directory)
    struct Directory *parentDir;
} Directory;

// DO NOT MODIFY THIS STRUCTURE
typedef struct File {
    // The name of the file
    char *name;

    // The size of the file
    int size;

    // The content of the file
    char *data;

    // The directory in which the file is located
    Directory *dir;
} File;

typedef struct Files {
    NodeFile *first;
    NodeFile *last;
} Files;

typedef struct DirList {
    NodeDir *first;
    NodeDir *last;
} DirList;

typedef struct NodeFile {
    struct NodeFile *next;
    struct NodeFile *prev;
    File *newfile;
} NodeFile;

typedef struct NodeDir {
    struct NodeDir *next;
    struct NodeDir *prev;
    Directory *newdir;
} NodeDir;

// create root of file system
void makeroot(Directory **root)
{
    *root = (Directory *) malloc(sizeof(Directory));

    (*root)->parentDir = NULL;
    (*root)->name = strdup("/");
    (*root)->files = NULL;
    (*root)->dirs = NULL;
}

// remove root of file system
void deleteroot(Directory *root)
{
    root = NULL;
    free(root);
}

//add new file to current directory
File *touch(Directory *root, char *nume, char *content)
{
    NodeFile *new = (NodeFile *) malloc(sizeof(NodeFile));

    new->newfile = (File *) malloc(sizeof(File));

    new->newfile->name = (char *) malloc(strlen(nume) + 1);
    new->newfile->data = (char *) malloc(strlen(content) + 1);

    strcpy(new->newfile->name, nume);
    strcpy(new->newfile->data, content);

    if (root->files == NULL) {
        root->files = (Files *) malloc(sizeof(Files));
        root->files->first = (NodeFile *) malloc(sizeof(NodeFile));
        root->files->last = (NodeFile *) malloc(sizeof(NodeFile));
        //if no file in folder root has first and last position
        root->files->first = new;
        root->files->last = new;
    } else if (strcmp(root->files->first->newfile->name,
                        new->newfile->name) > 0) {
        new->next = root->files->first;
        root->files->first = new;
    } else if (strcmp(root->files->last->newfile->name,
                        new->newfile->name) < 0) {
        root->files->last->next = new;
        root->files->last = new;
    } else {
        NodeFile *i = root->files->first;

        while (i != root->files->last) {
            if (strcmp(i->next->newfile->name,
                    new->newfile->name) > 0) {
                if (i == root->files->first->next)
                    i = root->files->first;
                i->next->prev = new;
                new->next = i->next;
                new->prev = i;
                i->next = new;
                break;
            }
            i = i->next;
        }
    }
    return new->newfile;
}

// Create directory
Directory *mkdir(Directory *parent, char *name)
{
    NodeDir *new = (NodeDir *) malloc(sizeof(NodeDir));

    //new->newdir = (Directory *) malloc(sizeof(Directory));
    new->newdir = (Directory *) malloc(strlen(Directory) + 1);

    new->newdir->name = (char *) malloc(strlen(name) + 1);

    strcpy(new->newdir->name, name);
    new->newdir->parentDir = parent;

    if (parent->dirs == NULL) {
        parent->dirs = (DirList *)malloc(sizeof(DirList));
        parent->dirs->first = (NodeDir *) malloc(sizeof(NodeDir));
        parent->dirs->last = (NodeDir *) malloc(sizeof(NodeDir));
        parent->dirs->first = new;
        parent->dirs->last = new;
    } else if (strcmp(parent->dirs->first->newdir->name,
                        new->newdir->name) > 0) {
        new->next = parent->dirs->first;
        parent->dirs->first = new;
    } else if (strcmp(parent->dirs->last->newdir->name,
                        new->newdir->name) < 0) {
        parent->dirs->last->next = new;
        parent->dirs->last = new;
    } else {
        NodeDir *i = parent->dirs->first->next;

        while (i != NULL) {
            if (strcmp(i->newdir->name, new->newdir->name) > 0) {
                if (i == parent->dirs->first->next)
                    i = parent->dirs->first;
                i->next->prev = new;
                new->next = i->next;
                new->prev = i;
                i->next = new;
                break;
            }
            i = i->next;
        }
    }
    return new->newdir;
}

// traverse list and print files and folders names
void ls(Directory *parent)
{
    if (parent->files != NULL) {
        NodeFile *i;

        for (i = parent->files->first; i != NULL; i = i->next)
            printf("%s ", i->newfile->name);
    }

    if (parent->dirs != NULL) {
        NodeDir *j;

        for (j = parent->dirs->first; j != NULL; j = j->next)
            printf("%s ", j->newdir->name);
    }

    printf("\n");
}

// working directory
void pwd(Directory *dir)
{
    if (dir->parentDir == NULL)
        return;
    if (dir->parentDir != NULL) {
        pwd(dir->parentDir);
        printf("/%s", dir->name);
    }
}


Directory *cd(Directory *dir, char *where)
{
    if (strcmp(where, "..") == 0 && dir->parentDir != NULL) {
        return dir->parentDir;
    } else if (dir->dirs == NULL)
        printf("Cannot move to ‘%s’: No such directory!\n", where);
    else {
        NodeDir *it = dir->dirs->first;

        while (it != NULL) {
            if (strcmp(it->newdir->name, where) == 0) {
                dir = it->newdir;
                break;
            }
            it = it->next;
        }
        if (it == NULL)
            printf("Cannot move to ‘%s’: No such directory!\n",
                    where);
        free(it);
    }
    return dir;
}

void tree(Directory *parent, int i)
{

    if (i == 1)
        printf("\n%s\n", parent->name);
    if (parent->files != NULL) {
        NodeFile *it;

        for (it = parent->files->first; it != NULL; it = it->next) {
            if (i != 1) {
                int j;

                for (j = 0; j < i; j++)
                    printf("   ");
            }
            printf("   %s\n", it->newfile->name);
        }
        free(it);
    }
    if (parent->dirs != NULL) {
        NodeDir *it = parent->dirs->first;

        while (it != NULL) {

            int j;

            for (j = 0; j < i; j++)
                printf("   ");
            printf("%s\n", it->newdir->name);
            i = i + 1;
            tree(it->newdir, i);
            it = it->next;
            i = i - 1;
        }
        free(it);
    }
}


void rm(Directory *parent, char *dirname)
{ //it -- item
    NodeFile *it;

    for (it = parent->files->first; it != NULL; it = it->next) {
        if (strcmp(it->newfile->name, dirname) == 0) {
            if (it == parent->files->first) {
                parent->files->first =
                parent->files->first->next;
            } else if (it == parent->files->last) {
                parent->files->last = it->prev;
            } else {
                it->prev->next = it->next;
                it->next->prev = it->prev;
            }
            it = NULL;
            free(it);
            return;
        }
    }
    if (it == NULL) {
        printf("Cannot remove ‘%s’: No such file!\n", dirname);
        free(it);
    }
}


void rmdir(Directory *parent, char *dirname)
{

    NodeDir *it;

    for (it = parent->dirs->first; it != NULL; it = it->next) {
        if (strcmp(it->newdir->name, dirname) == 0) {
            if (it == parent->dirs->first) {
                parent->dirs->first =
                parent->dirs->first->next;
            } else if (it == parent->dirs->last) {
                parent->dirs->last =
                parent->dirs->last->prev;
            } else {
                it->prev->next = it->next;
                it->next->prev = it->prev;
            }
            it = NULL;
            free(it);
            return;
        }
    }
    if (it == NULL) {
        printf("Cannot remove ‘%s’: No such directory!\n", dirname);
        free(it);
    }
}

#endif
/* __FILE_H__ */

Вывод Valgrind:

> create fs ls
> 
> ls
> 
> mkdir test ls
> ==11466== Conditional jump or move depends on uninitialised value(s)
> ==11466==    at 0x109025: ls (file.h:189)
> ==11466==    by 0x1097D4: main (main.c:86)
> ==11466==  Uninitialised value was created by a heap allocation
> ==11466==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
> ==11466==    by 0x108D44: mkdir (file.h:134)
> ==11466==    by 0x109766: main (main.c:81)

1 Ответ

1 голос
/ 29 марта 2020

В коснитесь , которое вы пропустили, чтобы установить в NULL поля далее и rev

В MKDIR , которые вы пропустили чтобы установить в NULL поля файлы и dirs , а иногда next

Чтобы упростить ваш код и сделать его надежным, я призываю вас добавить для каждого struct конструктор выполняет mallo c и инициализирует все поля, включая NULL, когда значение еще не известно, а также добавляет деструктор для каждого, чтобы освободить все выделенные элемент. Конечно, в вашем случае вы также можете использовать callo c вместо mallo c, чтобы установить все в 0

delete root не освобождает память, потому что вы установили root в NULL, прежде чем вызывать free , и потому что вы не переходите по ссылкам на бесплатные связанные ресурсы.

В rmdir у вас есть такое же неожиданное назначение NULL, прежде чем вызвать free внутри для . В конце, если бесполезно проверять, является ли это НЕДЕЙСТВИТЕЛЬНЫМ, потому что тест продолжения для равен it! = NULL и free в последнем блоке бесполезно

Из-за утечек памяти, поскольку вы никогда не освобождаете ресурсы, вы также вносите утечки памяти в mkdir , делая

    parent->dirs->first = (NodeDir *) malloc(sizeof(NodeDir));
    parent->dirs->last = (NodeDir *) malloc(sizeof(NodeDir));
    parent->dirs->first = new;
    parent->dirs->last = new;

две первые строки должны быть удалены

In

new->newdir = (Directory *) malloc(strlen(Directory) + 1);

strlen (Directory) недействительно, должно быть

new->newdir = (Directory *) malloc(sizeof(Directory));

В pwd вы делаете

if (dir->parentDir == NULL)
    return;
if (dir->parentDir != NULL) {

, поскольку две первые строки бесполезны

Более того вы ничего не печатаете в случае root, может быть:

void pwd(Directory *dir)
{
  if (dir->parentDir != NULL) {
    pwd(dir->parentDir);
    printf("%s/", dir->name);
  }
  else
    putchar('/');
}

In cd вызов free must быть удаленным

В случае ... если есть родитель, вы всегда будете указывать ошибку, потому что вы рассматриваете вложенные каталоги. Обратите внимание, что на уровне root cd .. ничего не делает, поэтому замените

if (strcmp(where, "..") == 0 && dir->parentDir != NULL) {
    return dir->parentDir;
} else if (dir->dirs == NULL)

на

if (strcmp(where, "..") == 0) {
    return (dir->parentDir != NULL) ? dir->parentDir : dir;
} else if (dir->dirs == NULL)


Я рекомендую переименовать поле newfile в file и newdir в dir , поскольку new без причины


В дереве должен быть удален вызов free


Видимо все находится в заголовочном файле Я рекомендую вам помещать только определения struct и объявления функций в файл заголовка и перемещать определения функций в исходный файл, иначе, если вы # включите несколько раз в свой заголовок файл, который вы будете иметь функции, кратно определенные

...