2 votes

C++ : gestion de la mémoire sur la pile (listes chaînées)

Désolé d'afficher ce code spaghetti, mais je ne sais pas d'où vient l'erreur. Cette fonction est censée imiter une version simplifiée de l'aspect inclusion de fichier de c++. Elle copie-colle le contenu de tous les fichiers avec un #include (et récursivement sur le contenu du fichier inclus).

Pour éviter que deux fichiers ne s'incluent mutuellement de manière récursive, j'ai créé une liste liée qui stocke tous les fichiers inclus précédemment. Les fichiers inclus par la suite seront vérifiés par rapport à cette liste liée pour s'assurer qu'un fichier n'inclut pas un fichier précédent. Nous ne sommes pas autorisés à allouer dynamiquement de la mémoire, nous devons donc utiliser la mémoire de la pile pour la liste chaînée. J'ai entendu dire que cela pouvait causer des problèmes de mémoire avec la liste chaînée lorsque les variables sortent du champ d'application.

Le problème est que certaines parties de ma liste chaînée sont écrasées par des éléments aléatoires. Si vous notez les instructions cout, le résultat pourrait ressembler à quelque chose comme ceci

Liste précédente : input.txt

nouveau nœud nom de fichier : file1.txt

nouvelle liste : file1.txt

Flist précédent : WHATEVER DOESNT MATTER (bizarre, il a pris la valeur de la chaîne filename)

nouveau nœud nom de fichier : file2.txt

nouvelle liste : file2.txt

Flist précédent : file2.txt (fonctionne comme prévu)

nouveau nœud nom de fichier : file3.txt

nouvelle liste : file3.txt

Flist précédent : symboles aléatoires (hein ? est-ce que cela provient d'une mémoire aléatoire dans la pile ?)

nouveau nœud nom de fichier : file4.txt

nouvelle liste : file4.txt

Flist précédent : file4.txt (fonctionne comme prévu)

nouveau nœud nom de fichier : file5.txt

nouvelle liste : file5.txt

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>

using namespace std;

struct Node { 
    string fileName;
    Node *link;
};

string extractfilename (string str) 
{
    string filename;

    if ((str.substr(10,1)) == "/" )
    {
        filename = str.substr((str.find_last_of("/"))+1,(str.length()) - (str.find_last_of("/"))-2);
        return filename;            
    } // if     
    else if ( (str.find_last_of("/")) != -1)
    {
        filename = str.substr((str.find_last_of("/")) + 1, (str.length()) - (str.find_last_of("/")) - 2);   
        return filename;
    } // else if 
    else
    {
        filename = str.substr(10,(str.length())-11);
        return filename;
    } // else

    return "ERROR";
}

void check_overlap (string filename, Node *flist)
{  
    while (flist != NULL)
    {
        if (flist->fileName == filename)
        {
            cerr << "Recursive include is being attempted. Terminating program." << endl;
            exit ( -1 );
        }
        flist = flist->link;
    }
}

void processOneFile( istream &in, ostream &out, Node *flist, string prefixDir )
{
    string str;
    getline(in,str);

    while(!(in.fail()))
    {
        string checkinclude = "";
        string checkabsolute = "";
        string prefix = "";
        string filename = "WHATEVER DOESNT MATTER";    
        string relpath = "";

        int checkrelative = 0;    
        int lastof = 0;    
        int length = str.length();

        if ( length > 11)
        {    
            checkinclude = str.substr(0,8);
            checkabsolute = str.substr(10,1);
            checkrelative = str.find_last_of("/");
        }    

        if (checkinclude == "#include")
        {
            ifstream newinput;
            filename = extractfilename(str);

            // PROBLEM WITH THIS ************
            //check_overlap(filename,flist) CAUSES INFINITE LOOP DUE TO DANGLING POINTERS?      
            Node newnode;

            cout << "Previous flist:    "<< flist->fileName << endl;

            newnode.fileName = filename;
            newnode.link = flist;
            Node surrogate_flist = newnode;

            cout << "newnode filename: "<< newnode.fileName << endl;       
            cout << "New flist:         "<< surrogate_flist.fileName << endl;
            cout << endl;
            // PROBLEM WITH THIS **************

            if (checkabsolute == "/" )
            {
                lastof = str.find_last_of("/");
                prefix = str.substr(10,lastof - 9);                    
                newinput.open((prefix + filename).c_str());

                if (!(newinput.is_open()))
                {
                    cout << prefix+filename << " cannot be opened" << endl;
                    exit( -1) ;
                }

                processOneFile(newinput,out,&surrogate_flist,prefix);
                newinput.close();
            } // if        
            else if ( checkrelative != -1)
            {
                relpath = str.substr(10, checkrelative - 9);        
                newinput.open((prefixDir+relpath+filename).c_str());

                if (!(newinput.is_open()))
                {
                    cout << prefixDir + relpath + filename << " cannot be opened" << endl;
                    exit( -1) ;
                }

                processOneFile(newinput,out,&surrogate_flist,(prefixDir+relpath));
                newinput.close();
            } // else if
            else
            {
                newinput.open((prefixDir + filename).c_str());

                if (!(newinput.is_open()))
                {
                    cout << prefixDir +filename << " cannot be opened" << endl;
                    exit( -1) ;
                }

                processOneFile(newinput,out,&surrogate_flist,prefixDir);
                newinput.close();
            } // else
        } // if
        else
        {
            out << str << endl;
        } // else
        getline(in,str);
    } // while
} // processOneFile

Remerciements

EDIT : l'utilisation de la structure des nœuds et des listes liées est obligatoire.

L'allocation dynamique implicite à partir de fonctions de chaînes de caractères est autorisée

ajout du code principal et du code compilable "complet

2voto

Sven Points 10540

Étant donné l'obligation d'utiliser une liste chaînée, vous devez utiliser la récursivité. Cela donnerait quelque chose comme ceci :

struct Node
{
    string value;
    Node *link;
};

void Process(Node *front)
{
    Node newNode;
    newNode.link = front;
    if( /* some condition */ )
        return; // end recursion
    else
        Process(&newNode);
}

La première invocation de Process serait simplement Process(NULL); pour indiquer une liste vide. Ajoutez des paramètres supplémentaires pour inclure le reste de votre état, bien sûr (je ne suis pas là pour faire vos devoirs à votre place). ;) ).

L'important est que vous ne pas modifier front->link car votre nouveau nœud ne sera pas valide au retour de la fonction et ne doit donc pas être visible par l'appelant. Vous devez donc construire cette liste à l'envers (chaque appel récursif ajoute un nœud au début).

Vous faites déjà quelque chose de similaire, votre problème est donc peut-être ailleurs. Sans code complet et compilable, il est toutefois difficile de déterminer où se situe le problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X