Имитация оболочки с использованием связанных списков - 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;

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

    // 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;


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 = "/";
    (*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(sizeof(char));

    new->newfile->data = (char *) malloc(sizeof(char));

    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)
{
    // la fel ca la touch
    NodeDir *new = (NodeDir *) malloc(sizeof(NodeDir));

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

    new->newdir->name = (char *)malloc(sizeof(char));

    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);
        free(i);
    }

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

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

    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

И это вывод моего выполнения valgrind --tool = memcheck --leak-check = full --show-leak-types = all --track-originins = yes --error-exitcode = 1 ./shell

  touch x
==6012== Invalid write of size 1
==6012==    at 0x4C32E0D: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6012==    by 0x108ACA: touch (file.h:94)
==6012==    by 0x109746: main (main.c:83)
==6012==  Address 0x522d8f1 is 0 bytes after a block of size 1 alloc'd
==6012==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6012==    by 0x108A97: touch (file.h:90)
==6012==    by 0x109746: main (main.c:83)
==6012== 
==6012== Invalid write of size 1
==6012==    at 0x4C32E0D: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6012==    by 0x108AE5: touch (file.h:95)
==6012==    by 0x109746: main (main.c:83)
==6012==  Address 0x522d941 is 0 bytes after a block of size 1 alloc'd
==6012==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6012==    by 0x108AAC: touch (file.h:92)
==6012==    by 0x109746: main (main.c:83)

Заранее спасибо за вашу поддержку.

1 Ответ

2 голосов
/ 29 марта 2020

Вы не выделяете достаточно для своей строки в touch

new->newfile->name = (char *) malloc(sizeof(char));
new->newfile->data = (char *) malloc(sizeof(char));

name и date имеют место только для одного символа, в случае «стандартной» строки это означает, что вы можете обрабатывать только пустые строки (только нулевой символ для их окончания)

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

достаточно число и содержимое иметь 1 символ, а затем завершающий нуль для записи из выделенных строк, valgrind указывает, что это так

У вас та же проблема в mkdir

To можно легко выделить и скопировать, используя strdup , иначе выделите strlen (xx) + 1 для дублирования xx , поэтому замените

new->newfile->name = (char *) malloc(sizeof(char));
new->newfile->data = (char *) malloc(sizeof(char));

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

по

new->newfile->name = strdup(nume);
new->newfile->data = strdup(content);

или

 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);

и сделать то же самое в mkdir


в сделать root вы делаете

(*root)->name = "/";

это опасно, потому что если вы хотите освободить ресурсы, вы должны помнить, чтобы не пытаться освободить (*root) -> имя т o не иметь неопределенного поведения, чтобы не рисковать, я призываю вас также продублировать "/"

(*root)->name = strdup("/");

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

У вас та же проблема в rm .

Каждый раз у вас есть выделение, вам нужно бесплатно


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


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

...