Alocarea memoriei unei structuri, in interiorul unei functii

Intrebari despre limbajul C++, standardul C++, STL, OOP in C++ sau alte subiecte nelegate de VisualC++
Post Reply
LXS
Junior
Junior
Posts: 2
Joined: 13 Feb 2014, 23:19
Judet: Timiş

Alocarea memoriei unei structuri, in interiorul unei functii

Post by LXS » 13 Feb 2014, 23:51

Salut comunitatea,
Sunt nou pe acest forum codexpert, am cautat un forum national de profil C/C++, dar nu am gasit aceasta alternanta, am gasit doar aceasta comunitate si sper sa ajut sau sa primesc ajutor pe viitor.
Incep prin descrierea unei probleme la care as dori o explicatie sau un posibil fixup.

Ce am incercat sa fac?
O implementare a unei liste liniare simplu inlantuita (LinkedList), desi am gasit cod functionabil pentru ce mi-am propus sa fac nu ma intereseaza, deoarece sunt in stadiul de training, am creat o structura Data in care am definit trei atribute dupa cum urmeaza (int, char* si Data*), unde int reprezinta index-ul, char* valoarea pentru un index iar Data* un pointer catre un element urmator.
O problema apare atunci cand incerc sa aloc memorie in functia appendNode() pentru structura Data, apare un memory leak chiar daca apoi apelez functia de dezalocarea memoriei (free()).
Un fix pentru a scapa de acest memory leak este de a crea pe stack structura (Data d), dar dupa ce functia va returna sau va parasi scop-ul stack-ul va fi elibarat/curatat, in acest caz pierd referinta catre structura creata.
Partea nefunctionabila a codului sursa este comentat.

Cod sursa:

Code: Select all

#include <iostream>
#include <string.h>
#include <malloc.h>

struct Data
{
    int dex;
    char* str;
    struct Data* nxt;
};

typedef struct Data  DATA;
typedef struct Data* PDATA;

int appendNode(PDATA pd, char* str)
{
    int index = 0;
    while(pd != NULL)
    {
        index = pd->dex;
        pd = pd->nxt;
    }
    //PDATA tempNode = (PDATA)memset(sizeof(DATA));
    //free(tempNode);
    //tempNode->dex = index+1;
    //tempNode->str = str;
    //std::cout << tempNode->dex << " " << tempNode->str;
    //free(tempNode);
    //pd->nxt = (PDATA)malloc(sizeof(PDATA));
    return 1;
}

PDATA searchByVal(PDATA pd, const char* str)
{
    while(pd != NULL)
    {
        if(strcmp(pd->str,str)==0)
        {
            return pd;
        }
        pd = pd->nxt;
    }
    return NULL;
}

int main()
{
    PDATA root = (PDATA)malloc(sizeof(PDATA));
    root->dex = 1;
    root->str = "abc";
    root->nxt = NULL;

    appendNode(root, "def");
    //appendNode(root, "ghi");
    //appendNode(root, "jkl");
    //appendNode(root, "mno");

    const char* valName = "jkl";
    root = searchByVal(root, valName);

    if(root != NULL)
    {
        std::cout << "Node with name " << valName << " is found at index " << root->dex << std::endl;
        if(root->nxt != NULL)
            std::cout << "Node is linked with another node. Which have the address " << root->nxt << std::endl;
        else
            std::cout << "Node is not linked with another node. This is the last node in the linked list." << std::endl;
    }
    else
    {
        std::cout << "Node with value " << valName << " is not found in the linked list!" << std::endl;
    }
    return 0;
}
Va multumesc pentru atentia oferita!



User avatar
Marius Bancila
Fondator
Fondator
Posts: 2344
Joined: 11 Jul 2007, 11:45
Judet: Timiş
Location: Timisoara
Contact:

Re: Alocarea memoriei unei structuri, in interiorul unei fun

Post by Marius Bancila » 06 Mar 2014, 18:14

Hai sa le luam problem cu problema.

Code: Select all

struct Data
{
    int dex;
    char* str;
    struct Data* nxt;
};

typedef struct Data  DATA;
typedef struct Data* PDATA;
In C++ nu e necesar sa pui acel struct in fata lui Data. Asta e suficient:

Code: Select all

struct Data
{
    int dex;
    char* str;
    Data* nxt;
};

typedef Data  DATA;
typedef Data* PDATA;
Practic, primul typedef e degeaba.

Aici ai alocat memorie pentru un nod, dar nodul tau contine un pointer la char si unul catre alt nod.

Code: Select all

   PDATA root = (PDATA)malloc(sizeof(PDATA));
   root->dex = 1;
   root->str = "abc";
   root->nxt = NULL;
Chiar daca poti sa zici str = "abc", nu e corect pentru ca in general ce atribui acolo nu e probabil un string literal. Ce trebuie sa faci e sa aloci memorie si la timpul potrivit sa o stergi.

In alta ordine de idei, daca scri in C++ macar foloseste new/delete in loc de malloc/free.

Code: Select all

   Data* root = new Data;
   root->dex = 1;
   root->str = new char[4] {0};
   strcpy(root->str, "str");
   root->nxt = NULL;
Functia de adaugat ar trebui sa arate cam asa:

Code: Select all

int appendNode(PDATA pd, char* str)
{
   while(pd != NULL && pd->nxt != NULL)
      pd = pd->nxt;

   Data* tempNode = new Data;
   tempNode->dex = pd->dex + 1;
   tempNode->str = new char[strlen(str) + 1] {0};
   tempNode->nxt = NULL;
   strcpy(tempNode->str, str);
   pd->nxt = tempNode;

   return 1;
}
In codul tau ai acest loop:

Code: Select all

    while(pd != NULL)
    {
        index = pd->dex;
        pd = pd->nxt;
    }
Ce se intampla e ca intotdeauna ajungi pana la ultimul element is apoi setezi pd pe pointerul catre urmatorul lor nod, adica NULL. De acum, in momentul cand incerci sa accesezi pd o sa ai parte de o exceptie care iti crapa programul.

Eu as face cateva modificari la codul tau si as folosi std::string in loc de char*.

Code: Select all

struct Data
{
   int dex;
   string str;
   Data* nxt;
};

Data* appendNode(Data* pd, string const & str)
{
   while(pd != NULL && pd->nxt != NULL)
      pd = pd->nxt;

   Data* tempNode = new Data;
   tempNode->dex = pd != NULL ? pd->dex + 1 : 1;
   tempNode->str = str;
   tempNode->nxt = NULL;

   if(pd != NULL)
      pd->nxt = tempNode;

   return tempNode;
}

Data* searchByVal(Data* pd, string const & str)
{
   while(pd != NULL)
   {
      if(pd->str == str)
      {
         return pd;
      }
      pd = pd->nxt;
   }
   return NULL;
}

void freeList(Data* pd)
{
   while(pd != NULL)
   {
      Data* next = pd->nxt;

      delete pd;

      pd = next;
   }
}

int main()
{
   Data* root = appendNode(NULL, "abc");

   appendNode(root, "def");
   appendNode(root, "ghi");
   appendNode(root, "jkl");
   appendNode(root, "mno");

   const char* valName = "jkl";
   Data* node = searchByVal(root, valName);

   if(node != NULL)
   {
      std::cout << "Node with name " << valName << " is found at index " << node->dex << std::endl;
      if(root->nxt != NULL)
         std::cout << "Node is linked with another node. Which have the address " << node->nxt << std::endl;
      else
         std::cout << "Node is not linked with another node. This is the last node in the linked list." << std::endl;
   }
   else
   {
      std::cout << "Node with value " << valName << " is not found in the linked list!" << std::endl;
   }

   freeList(root);

   return 0;
}
Pasul urmator e sa pui functiile astea intr-o clasa in care sa ascuzi detaliile de implementare (pointerul la primul si eventual ultimul nod din lista) si sa oferi functii publice prin care sa modifici lista.
Marius Bancila
Fondator Codexpert, Microsoft MVP VC++
Site personal | Blog

Post Reply