简体   繁体   English

程序运行良好,但 valgrind 出现一些错误

[英]Program works fine, but valgrind gives some errors

What am I doing wrong?我究竟做错了什么?

There is no memory leaks, but valgrind stills complain, I didn't figured out what is causing this errors.没有内存泄漏,但 valgrind 仍然抱怨,我没有弄清楚是什么导致了这个错误。

I would be very glad whether someone could just help me figure what am I doing wrong here.如果有人能帮我弄清楚我在这里做错了什么,我会很高兴。

/****************************************************************************
 * dictionary.c
 *
 * Computer Science 50
 * Problem Set 5
 *
 * Implements a dictionary's functionality.
 ***************************************************************************/

#include <stdbool.h>

#include "dictionary.h"

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

struct dict {
         struct dict *next;
         char *word;
};

#define HASHSIZE 26
static struct dict *hashtab[HASHSIZE];

unsigned hash(const char *key)
{
    unsigned index = toupper(key[0]) - 'A';

    return index % HASHSIZE;
}

struct dict *lookup(const char *s)
{
    struct dict *np;

    for (np = hashtab[hash(s)]; np != NULL; np = np->next) {
         if (strcmp(s, np->word) == 0) {
                return np;  /* found */
        }
    }
    return NULL;            /* not found*/
}

/**
 * Returns true if word is in dictionary else false.
 */
bool check(const char* word)
{
    if (lookup(word) != NULL) {
        return true;
    }
    else {
        int i;
        for (i = 0; word[i] != '\0' && !isupper(word[i]); ++i)
            ;
        if (word[i] != '\0') {
            char newword[LENGTH + 1];
            for (i = 0; word[i] != '\0'; ++i) {
                newword[i] = tolower(word[i]);
            }
            newword[i] = '\0';
            if (lookup(newword) != NULL) {
                return true;
            }
        }
    }
    return false;
}

int getword(FILE *fp, char **s)
{
    int c, i;
    char word[LENGTH + 1];

    i = 0;
    while ((c = fgetc(fp)) != '\n' && c != EOF && i < LENGTH + 1) {
        word[i++] = c;
    }
    word[i] = '\0';
    if (c == EOF) {
        return EOF;
    }
    if ((*s = malloc(i)) == NULL) {
        return EOF;
    }
    strncpy(*s, word, i);
    return i;         
}

static unsigned nofwords;

struct dict *install(char *word)
{
    struct dict *np;
    unsigned hashval;

    if ((np = lookup(word)) == NULL) {  /* Not found */
        np = malloc(sizeof(*np));
        if (np == NULL) {
            return NULL;
        }
        struct dict *hpt;
        hashval = hash(word);
        if (hashtab[hashval] != NULL) {
            for (hpt = hashtab[hashval]; hpt->next != NULL; hpt = hpt->next)
                ;
            hpt->next = np;
        }
       else {    
            np->next = hashtab[hashval];
            hashtab[hashval] = np;
       }
       np->word = word;
    }
    else {
        free(word);
    }
    ++nofwords;
    return np;
}

/**
 * Loads dictionary into memory.  Returns true if successful else false.
 */
bool load(const char* dictionary)
{
    FILE *fp;

    if ((fp = fopen(dictionary,"r")) == NULL) {  
        return false;
    }
    char *s = NULL;
    while (getword(fp, &s) != EOF) {
        if (install(s) == NULL) {
            fclose(fp);
            return false;
        }
    }
    fclose(fp);
    return true;
}

/**
 * Returns number of words in dictionary if loaded else 0 if not yet loaded.
 */
unsigned int size(void)
{
    return nofwords;
}

/**
 * Unloads dictionary from memory.  Returns true if successful else false.
 */
bool unload(void)
{
    int i;
    struct dict *np;
    struct dict *tmp;

    for (i = 0; i < HASHSIZE; i++) {
        if (hashtab[i] != NULL) {
            np = hashtab[i];
            while (np != NULL) {
                free(np->word);
                tmp = np;
                np = np->next;
                free(tmp);
            }
        }
    }
    return true;
}

Valgrind output below Valgrind 输出如下

jharvard@appliance (~/Dropbox/pset5): valgrind ./speller ~cs50/pset5/dictionaries/small text
==18743== Memcheck, a memory error detector
==18743== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==18743== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==18743== Command: ./speller /home/cs50/pset5/dictionaries/small text
==18743== 
==18743== Invalid read of size 1
==18743==    at 0x402E5CA: strcmp (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==18743==    by 0x8049012: lookup (dictionary.c:39)
==18743==    by 0x8049296: install (dictionary.c:102)
==18743==    by 0x80493F6: load (dictionary.c:139)
==18743==    by 0x8048785: main (speller.c:45)
==18743==  Address 0x41f51bb is 0 bytes after a block of size 3 alloc'd
==18743==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==18743==    by 0x804922D: getword (dictionary.c:85)
==18743==    by 0x80493E0: load (dictionary.c:138)
==18743==    by 0x8048785: main (speller.c:45)
==18743== 

MISSPELLED WORDS

==18743== Conditional jump or move depends on uninitialised value(s)
==18743==    at 0x8048FF8: lookup (dictionary.c:38)
==18743==    by 0x8049066: check (dictionary.c:51)
==18743==    by 0x8048B1D: main (speller.c:117)
==18743== 
==18743== Invalid read of size 1
==18743==    at 0x402E5CA: strcmp (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==18743==    by 0x8049012: lookup (dictionary.c:39)
==18743==    by 0x8049145: check (dictionary.c:64)
==18743==    by 0x8048B1D: main (speller.c:117)
==18743==  Address 0x41f51bb is 0 bytes after a block of size 3 alloc'd
==18743==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==18743==    by 0x804922D: getword (dictionary.c:85)
==18743==    by 0x80493E0: load (dictionary.c:138)
==18743==    by 0x8048785: main (speller.c:45)
==18743== 
==18743== Conditional jump or move depends on uninitialised value(s)
==18743==    at 0x8049492: unload (dictionary.c:168)
==18743==    by 0x8048D14: main (speller.c:157)
==18743== 

WORDS MISSPELLED:     0
WORDS IN DICTIONARY:  2
WORDS IN TEXT:        1
TIME IN load:         0.07
TIME IN check:        0.01
TIME IN size:         0.00
TIME IN unload:       0.01
TIME IN TOTAL:        0.08

==18743== 
==18743== HEAP SUMMARY:
==18743==     in use at exit: 0 bytes in 0 blocks
==18743==   total heap usage: 6 allocs, 6 frees, 734 bytes allocated
==18743== 
==18743== All heap blocks were freed -- no leaks are possible
==18743== 
==18743== For counts of detected and suppressed errors, rerun with: -v
==18743== Use --track-origins=yes to see where uninitialised values come from
==18743== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)

Conditional jump or move depends on uninitialised value(s)条件跳转或移动取决于未初始化的值

static struct dict *hashtab[HASHSIZE] = {0};

0 bytes after a block of size 3 alloc'd分配大小为 3 的块后的 0 个字节

getword() -> *s = malloc(i);

-->> here i may be zero, hence, malloc of 0 size (consider the case when file has empty line instead of valid word) -->> 这里 i 可能为零,因此,malloc 为 0 大小(考虑文件有空行而不是有效字的情况)

Invalid read of size 1 (strcmp)大小 1 的无效读取 (strcmp)

lookup() -> if (strcmp(s, np->word) == 0)

Here, s may be empty string, so adding empty string handling (not to call strcmp() for empty string, returning error) will help.在这里, s 可能是空字符串,因此添加空字符串处理(不要为空字符串调用 strcmp(),返回错误)会有所帮助。

Further, your getword() function need following modifications:此外,您的 getword() 函数需要进行以下修改:

while ((c = fgetc(fp)) != '\n' && c != EOF && i < LENGTH + 1)

---> change is i < LENGTH instead of i < LENGTH + 1 (i is starting from 0, so it can go till LENGTH-1 to allow accommodate '\\0' at end at index LENGTH). ---> 变化是 i < LENGTH 而不是 i < LENGTH + 1(i 从 0 开始,所以它可以一直到 LENGTH-1 以允许在索引 LENGTH 的末尾容纳 '\\0')。

if ((*s = malloc(i)) == NULL)

---> malloc should be for i+1 length to accommodate '\\0'. ---> malloc 应该是 i+1 长度以容纳 '\\0'。

strncpy(*s, word, i);

---> Add code to put '\\0' at end in s ie (*s)[i] = '\\0'; ---> 添加代码以将 '\\0' 放在 s 的末尾,即 (*s)[i] = '\\0'; after strncpy() call.在 strncpy() 调用之后。

Invalid read of size 1

Valgrind tells you that you try to read 1 byte (in strcmp) you are not allowed to read. Valgrind 告诉您,您尝试读取 1 个不允许读取的字节(在 strcmp 中)。

It is probably because no function define your string s that you try to compare with np->word (line 39).可能是因为没有函数定义您尝试与np->word (第 39 行)进行比较的 string s

Conditional jump or move depends on uninitialised value(s)

That means you are trying to use an unitialized variable in a condition.这意味着您正在尝试在条件中使用未初始化的变量。

Try to run your code in a debugger and follow the values of your strings to see if they point to something when you give them as arguments to functions.尝试在调试器中运行您的代码并跟踪您的字符串的值,看看当您将它们作为函数的参数时,它们是否指向某些东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM