Shell simulation using lists

十年热恋 提交于 2020-04-18 05:43:13

问题


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)

回答1:


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



来源:https://stackoverflow.com/questions/60913495/shell-simulation-using-lists

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!