【问题标题】:Shell simulation using lists使用列表进行 Shell 模拟
【发布时间】:2020-07-09 19:33:52
【问题描述】:

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

【问题讨论】:

  • #ifndef __FILE_H__?以双下划线开头的标识符,以及以单下划线和大写字母开头的标识符是保留的,不应使用。 7.1.3 Reserved identifiers: "所有以下划线和大写字母或另一个下划线开头的标识符始终保留供任何使用。"

标签: c memory heap-memory


【解决方案1】:

touch 中,您错过了将字段 nextrev

设置为 NULL

mkdir 中,您错过了将字段 filesdirs 设置为 NULL,有时还有 next

为了简化您的代码并使其健壮,我鼓励您为每个 struct 添加一个构造函数,该构造函数执行 malloc 并在值为 NULL 时初始化所有字段,包括 NULL还不知道,并且还为每个添加一个析构函数以释放所有分配的元素。当然,在您的情况下,您也可以使用 calloc 而不是 malloc 将所有内容置于 0

deleteroot 不会释放内存,因为您在调用 free 之前将 root 设置为 NULL,并且因为您没有按照链接进行释放链接资源。

rmdir 中,在 for 中调用 free 之前,您有相同的意外分配给 NULL。最后 if 没用检查 it 是否为 NULL,因为 for 的延续测试是 it != NULL,而 free最后一个block没用了

由于您从不释放资源而导致内存泄漏,您还会在 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(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('/');
}

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 几次你的头文件,你将拥有多重定义的函数

【讨论】:

  • 我正在使用您提供的指导。希望得到更多的工作。我会很快在这里更新代码。感谢您的支持。
猜你喜欢
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 2011-11-08
  • 2011-03-18
  • 2020-08-20
  • 2017-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多