使用列表进行壳模拟 [英] Shell simulation using lists

查看:59
本文介绍了使用列表进行壳模拟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现在我正在学习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)

解决方案

touch 中,您没有将 next rev

mkdir 中,您错过了将 files dirs 字段(有时是 next )设置为NULL的机会. >

为简化代码并使代码更健壮,我建议您为每个 struct 添加一个构造器,该构造器执行 malloc 并在所有值为NULL的情况下初始化所有包含NULL的字段还不知道,还为每个对象添加了一个析构函数以释放所有分配的元素.当然,根据您的情况,您也可以使用 calloc 而不是 malloc 将所有值都设为0

deleteroot 不会释放内存,因为您在调用 free 之前将 root 设置为NULL,并且因为您未遵循free链接链接的资源.

rmdir 中,您有相同的意外分配给NULL,然后才能在 for 中调用 free .最后,if不能检查 it 是否为NULL,因为 for 的连续测试为 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;

必须删除前两行

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

strlen(目录)无效,必须为

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('/');
}


cd 中,必须删除对 free 的调用

如果是..如果有父母,您总是会指出一个错误,因为您考虑了子目录.请注意,在根级别, 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 ,因为没有理由


tree 中,必须删除对 free 的调用


所有内容都位于头文件中,我建议您仅将 struct 定义和函数声明放在头文件中,并将函数定义移至源文件中,否则,如果 #include 几次您的头文件,您将获得多个定义的函数

Now i'm learning C and I have a problem with memory alocation, atleast this I understand from my code error.

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:

> 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

In mkdir you missed to set to NULL the fields files and dirs, and sometimes 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. Of course in your case you can also use calloc rather than malloc to put all to 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.

In rmdir you have the same unexpected assignment to NULL before to call free inside the for. 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

Out of the memory leaks because you never free the resources you also introduce memory leaks in mkdir doing

    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

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


In pwd you do

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 :

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 removed

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

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


In tree the call to free must be removed


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

这篇关于使用列表进行壳模拟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆