Pset5(Speller)奇怪的Valgrind内存错误,无泄漏

时间:2020-06-09 15:57:42

标签: valgrind cs50

我已经阅读了有关pset5 Valgrind内存错误的其他线程,但这对我没有帮助。我收到了0次泄漏,但是相反:

== 1917 ==条件跳转或移动取决于未初始化的值 看起来您正在尝试使用可能没有值的变量?仔细查看dictionary.c的第34行。

错误指向第34行,它是:lower [i] = tolower(word [i]);

为提供上下文,下面的代码尝试检查已上传到哈希表的字典中是否存在某个单词。我正在尝试将所需的单词转换为小写,因为所有的词典单词也都是小写的,因此它们的哈希值是相同的。该程序成功完成了所有任务,但随后偶然发现了这些内存错误。

有人暗示为什么瓦尔格朗德生我的气吗?谢谢!

 // Returns true if word is in dictionary else false
bool check(const char *word)
{
    char lower[LENGTH + 1]; 

   //Converts word to lower so the hashes of the dictionary entry and searched word would match
    for (int i = 0; i < LENGTH + 1; i++)
    {
        lower[i] = tolower(word[i]);
    }

    // Creates node from the given bucket
    node *tmp = table[hash(lower)];

    // Traverses the linked list
    while (tmp != NULL)
    {
        if (strcasecmp(word, tmp->word) == 0)
        {
            return true;
        }

        tmp = tmp->next;
    }

    return false;
}

下面是整个dictionary.c文件:

// Implements a dictionary's functionality
#include <string.h>
#include <strings.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include "dictionary.h"

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

// Number of buckets in hash table 26^3
const unsigned int N = 17576;

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

// Returns true if word is in dictionary else false
bool check(const char *word)
{
    char lower[LENGTH + 1]; 

   //Converts word to lower so the hashes of the dictionary entry and searched word would match
    for (int i = 0; i < LENGTH + 1; i++)
    {
        lower[i] = tolower(word[i]);
    }

    // Creates node from the given bucket
    node *tmp = table[hash(lower)];

    // Traverses the linked list
    while (tmp != NULL)
    {
        if (strcasecmp(word, tmp->word) == 0)
        {
            return true;
        }

        tmp = tmp->next;
    }

    return false;
}

// Hashes word to a number
unsigned int hash(const char *word)
{
    // Modified hash function by Dan Berstein taken from http://www.cse.yorku.ca/~oz/hash.html
    unsigned int hash = 5381;
    int c;

    while ((c = *word++))
    {
        hash = (((hash << 5) + hash) + c) % N; /* hash * 33 + c */
    }

    return hash;
}

// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
    FILE *inptr = fopen(dictionary, "r");

    if (dictionary == NULL)
    {
        printf("Could not load %s\n.", dictionary);
        return false;
    }

    // Create a char array to temporarily hold the new word (r stands for read)
    char r_word[N+1];

    // Until the end of file
    while (fscanf(inptr, "%s", r_word) != EOF)
    {
        // Increments count
        count++;

        // Create a node
        node *new_node = malloc(sizeof(node));

        if (new_node == NULL)
        {
            unload();
            return false;
        }

        strcpy(new_node->word, r_word);

         // Hash the node
        int index = hash(new_node->word);
        // Places the node at the right index
        new_node->next = table[index];
        table[index] = new_node;
    }

    fclose(inptr);

    return true;
}

// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
    if (&load == false)
    {
        return '0';
    }
    else
    {
        return count;
    }

}

// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
    // Interates over the array
    for (int i = 0; i < N; i++)
    {
        node *head = table[i];

        while (head != NULL)
        {
            node *tmp = head;
            head = head->next;
            free(tmp);
        }
    }

    return true;
}

1 个答案:

答案 0 :(得分:1)

此循环迭代word-

最大长度
for (int i = 0; i < LENGTH + 1; i++)
{
    lower[i] = tolower(word[i]);
}

除非您查看如何创建word-

while (fscanf(inptr, "%s", r_word) != EOF)
{
    // Increments count
    count++;
    // Create a node
    node *new_node = malloc(sizeof(node));
    if (new_node == NULL)
    {
        unload();
        return false;
    }
    strcpy(new_node->word, r_word);

注意,变量r_word的长度可能不完全为LENGTH + 1。因此,您在word中真正拥有的字符数为N,其中N不一定是 LENGTH + 1

因此,对于短于0 -> LENGTH + 1的单词,遍历整个LENGTH + 1会成为问题。您正在遍历没有值的数组插槽,它们具有垃圾值。

有什么解决方案?这就是为什么c字符串具有\0-

的原因
for (int i = 0; word[i] != '\0'; i++)
{
    lower[i] = tolower(word[i]);
}

这将在到达NULL字符后立即停止循环,您必须已经学习过NULL字符,它标志着字符串的末尾-aka字符数组。

您的代码中可能仍然存在更多错误。但是对于您的特定问题-超越界限的阅读就是答案。