0
votes

Où est cette fuite de mémoire?

J'ai rendu ce dictionnaire "Vérification orthographique" fonctionne pendant un moment et je l'ai enfin fonctionné entièrement, à l'exception d'une petite erreur de ne pas avoir aucune idée de la fuite de cette mémoire. Quand j'exécute Valgrind, cela revient:

```C

//for the universal hash function
#define BASE 256

// Represents a node in a hash table
typedef struct node
{
    char word[LENGTH + 1];
    struct node *next;
}
node;

// Number of buckets in hash table
const unsigned int N = 676;

// Hash table
node *table[N];
int word_count = 0;

// Returns true if word is in dictionary else false
//Require a search funtion
bool check(const char *word)
{
    //change to lower case to compare
    char low[LENGTH + 1];
    
    for (int i = 0, n = strlen(word); i <= (n + 1); i++)
    {
        low[i] = tolower(word[i]);
    }
    
    int hashIndex = hash(low);
    for (node *tmp = table[hashIndex]; tmp != NULL; tmp = tmp->next)
    {
        
        if (strcasecmp(low, tmp->word) == 0)
        {
            return true;
        }
    }
    return false;
}

// Hashes word to a number
// the dividing hash function is one I cited from the yale.edu page http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)HashTables.html having worked with.
unsigned int hash(const char *word)
{
    unsigned long m = 11;
    unsigned long h;
    unsigned const char *us;
    //ensure element value is >= 0 
    us = (unsigned const char *) word;

    h = 0;
    while(*us != '\0') 
    {
        h = (h * BASE + *us) % m;
        us++;
    } 
    return (h % N);
}

// Loads dictionary into memory, returning true if successful else false
//Bring the used sictionary to menu asap
bool load(const char *dictionary)
{
    
    // Open file and check file 
    FILE *file = fopen(dictionary, "r");
    if (!file)
    {
        return false;
    }
    
    
    //array declaration for fscanf to read into
    char word[LENGTH + 1];
    while (fscanf(file, "%s", word) == 1)
    {
        //Create node n = new node
        node *n = malloc(sizeof(node));
        if (n == NULL)
        {
            printf("No memory for node\n");
            fclose(file);
            return false;
            
        }
        strcpy(n->word, word);
        
        //Hash the word
        int hashDigit = hash(word);
        //Insert into the beginning of the list
        if (table[hashDigit] == NULL)
        {
            table[hashDigit] = n;
            n->next = NULL;
        }
        else
        {
            n->next = table[hashDigit];
            table[hashDigit] = n;
        }
        word_count++;
    }
    return true;
}

// Returns number of words in dictionary if loaded else 0 if not yet loaded
//count the amount of words in dictionary
unsigned int size(void)
{
    
    return word_count;
}

// Unloads dictionary from memory, returning true if successful else false
//free the dictionary from memory asap
bool unload(void)
{
    //Loop to run through array
    for (int i = 0; i < N; i++)
    {
        //to target linked list
        while (table[i] != NULL)
        {
            node *tmp = table[i];
            table[i] = table[i]->next;
            free(tmp);
        }
    }
    
    return true;
}


2 commentaires

Lorsque vous collez du texte pré-formaté (y compris le code) dans votre message, vous pouvez facilement conserver ce format en sélectionnant ce texte, puis cliquez sur le bouton {} .


Ce code compile? Je vois une matrice de longueur variable globalement scopée.


4 Réponses :


3
votes

Il fuit fichier * code> obtenu de fopen code>. FCLOSE CODE> est manquant.

Ceci est où Valgrind code> vous indique que: p> xxx pré>

fopen Code> Finalement appelle MALLOC CODE> pour allouer ce fichier code> qui doit être publié avec FCLOSE code> qui appelle éventuellement gratuit code> sur ce fichier * code>. p>


saut conditionnel ou déplacement dépend de la valeur non initialisée code> Avertissement est causée par: P>

for (int i = 0, n = strlen(word); i <= (n + 1); i++)
    low[i] = tolower(word[i]);


7 commentaires

Cela m'est venu que le commentaire final de l'utilisateur est exactement ce que je pourrais retirer sur ma première expérience de Valgrind. Remarquez à quel point les avertissements non initialisés sont-ils éminents que les informations de la mémoire de la mémoire? Je pense que vous devriez mentionner cela dans votre réponse, car si les avertissements de fuite de la mémoire utilisaient dans la sortie avant de résoudre ceux-ci, il peut encore avoir cela "voir texte de la promotion et répondre" habitude.


Je ne sais pas comment interpréter votre réponse principalement car il applique mon point sur la possibilité que l'utilisateur ait pu créer une habitude de réponse à ce qu'il lisait de la manière que vous suggérez. En d'autres termes, s'il veut d'abord se débarrasser de toutes les fuites de mémoire, il devra sauter la partie supérieure que nous voyons tous maintenant ici.


J'ai essayé cette solution, mais il ne semble pas que cela me dise qu'ici:


@Kwsswart a mis à jour la réponse pour vous.


== 707 == Le saut conditionnel ou le déplacement dépend de la valeur non initialisée == 707 == à 0x520A60F: tolower (CTYPE.c: 46) == 707 == par 0x4010E2: chèque (Dictionary.c: 37) == 707 == par 0x400cd9: Main (Spoverer.c: 112) == 707 == Valeur non initialisée a été créée par une allocation de pile == 707 == à 0x4008E4: principale (orthographe.c: 21) == 707 == utilisation de Valeur non initialisée de la taille 8 == 707 == à 0x520A623: tolower (ctype.c: 46) == 707 == par 0x4010e2: chèque (Dictionary.c: 37) == 707 == par 0x400CD9: Main (Speler.C : 112) == 707 == La valeur non initialisée a été créée par une répartition de la pile


@ Maxim Egorushkin merci beaucoup, une fois de plus, j'ai commis l'erreur de courir une boucle une fois de loin


@Kwsswart: Il n'y a vraiment que 2 choses difficiles dans la programmation: nommer des choses, la mise en cache et les erreurs obsolètes.



2
votes
> ==793== 552 bytes in 1 blocks are still reachable in loss record 1 of 1
> ==793==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
> ==793==    by 0x5258E49: __fopen_internal (iofopen.c:65)
> ==793==    by 0x5258E49: fopen@@GLIBC_2.2.5 (iofopen.c:89)
> ==793==    by 0x401211: load (dictionary.c:77)
> ==793==    by 0x4009B4: main (speller.c:40)
The leak is coming from fopen because you aren't calling fclose.

2 commentaires

J'ai essayé cela, mais cela ne semble pas complètement arrêter les lignes ...


== 707 == Le saut conditionnel ou le déplacement dépend de la valeur non initialisée == 707 == à 0x520A60F: tolower (CTYPE.c: 46) == 707 == par 0x4010E2: chèque (Dictionary.c: 37) == 707 == par 0x400CD9: Main (Spoverer.c: 112) == 707 == La valeur non initialisée a été créée par une allocation de pile == 707 == == 707 == Utilisation de la valeur non initialisée de la taille 8 == 707 == à 0x520a623: tolower (ctype.c: 46) == 707 == par 0x4010e2: chèque (Dictionary.c: 37) == 707 == par 0x400CD9: Main (orthographe.c: 112) == 707 == Valeur non initialisée était Créé par une allocation de pile == 707 == à 0x4008E4: Main (Speller.c: 21)



0
votes

Vous faites un grand nombre de pointeurs ici xxx

mais vous ne définissez jamais ce tableau à NULL.

alors vous faites toutes sortes de choses sur ce tableau en supposant que a été initialisé.


6 commentaires

Le vrai problème est qu'il s'agit d'une matrice de longueur variable déclarée à la portée mondiale.


S'il s'agissait d'une matrice de taille statique appropriée à l'aide d'une valeur constante vraie (plutôt que d'un const ), je pense que cela devrait suivre les règles de la durée de stockage statique des objets déclarés, auquel cas les éléments seraient implicitement initialisé à NULL par norme C11 6.7.9 P10


@Christiangibbbons - Je n'étais pas sûr de quelle version il utilisait: haussement d'épaules:


Je ne crois pas que la version devrait importer; Les mêmes règles doivent s'appliquer. La seule différence étant que les VLAS sont facultatives en C11, obligatoire en C99 et inexistantes en C89, mais dans tous les cas, ils ne sont pas autorisés pour des objets de duration statique de stockage.


@Christiangbbbures - En d'autres termes, c'était différent dans chacune de ces versions? :)


VLAS à la durée de stockage statique n'a été inexistante dans chacune de ces versions et pointesR avec une durée de stockage statique sans initialiseur serait initialisée à NULL pour chacune de ces versions. Donc, pour tout ce qui concerne cela spécifiquement, il ne devrait y avoir aucune différence.



0
votes

J'avais le même problème avec le même problème (la semaine 5 du cours CS50 de Harvard), mais les réponses ci-dessus ne me sont pas que la moitié du chemin là-bas.

a finalement résolu en attribuant explicitement l'attribution explicitement le terminateur null '\ 0 'Pour les caractères restants de chaque mot, comme: xxx


0 commentaires