简体   繁体   English

使用列表进行壳模拟

[英]Shell simulation using lists

Now i'm learning C and I have a problem with memory alocation, atleast this I understand from my code error.现在我正在学习 C 并且我在内存分配方面遇到了问题,至少我从我的代码错误中了解到这一点。

Code代码

    #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 output: 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)

In touch you missed to set to NULL the fields next and rev联系中,您错过了将nextrev字段设置为 NULL

In mkdir you missed to set to NULL the fields files and dirs , and sometimes nextmkdir 中,您错过了将字段filesdirs设置为 NULL ,有时是next

To simplify your code and makes it robust I encourage you to add for each struct a constructor doing the malloc and initializing all the fields including with NULL when the value is not yet known, and also add a destructor for each to free all allocated element.为了简化您的代码并使其健壮,我鼓励您为每个结构添加一个构造函数,该构造函数执行malloc并在值未知时使用 NULL 初始化所有字段,并为每个结构添加一个析构函数以释放所有分配的元素。 Of course in your case you can also use calloc rather than malloc to put all to 0当然,在您的情况下,您也可以使用calloc而不是malloc将所有内容都设置为 0

deleteroot does not free memory because you set root to NULL before to call free , and because you do not follow the links to free linked resources. deleteroot不会释放内存,因为您在调用free之前将root设置为 NULL ,并且因为您没有按照链接来释放链接的资源。

In rmdir you have the same unexpected assignment to NULL before to call free inside the for .rmdir 中,在for内部调用free之前,您对 NULL 进行了相同的意外分配。 At the end if is useless to check if it is NULL because the continuation test of the for is it != NULL , and the free in the last block is useless最后 if 没有用检查是否为 NULL 因为for的延续测试是it != NULL ,而最后一个块中的free没有用

Out of the memory leaks because you never free the resources you also introduce memory leaks in mkdir doing在内存泄漏之外,因为您从不释放资源,您还在mkdir 中引入了内存泄漏

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

the two first lines must be removed必须删除前两行

In

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

strlen(Directory) is invalid, must be strlen(Directory)无效,必须是

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

In pwd you dopwd你做

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

in that the two first lines are useless因为前两行没用

Furthermore you print nothing in case of root , can be :此外,您在root 的情况下不打印任何内容,可以是:

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

In cd the call to free must be removedcd 中必须删除对free的调用

In case of .. if there is a parent you will always indicate an error because you consider the sub dirs.在 .. 如果有父目录的情况下,您将始终指示错误,因为您考虑了子目录。 Note that at the root level a cd .. does nothing, so replace请注意,在根级别, cd ..什么都不做,因此请替换

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

by经过

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


I encourage you to rename the field newfile to file and newdir to dir because the new has no reason我鼓励您将字段newfile重命名为file并将newdir重命名为dir因为new没有理由


In tree the call to free must be removed树中,必须删除对free的调用


Visibly all is in a header file, I encourage you to put only the struct definitions and function declaration in the header file, and to move the function definitions in a source file, else if you #include several times your header file you will have functions multiply defined显然所有都在头文件中,我鼓励您只将结构定义和函数声明放在头文件中,并将函数定义移动到源文件中,否则如果您多次#include头文件,您将拥有函数多重定义

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM