在拼写检查中使用大小为8的未初始化值

时间:2017-06-19 12:49:00

标签: c memory-leaks

我写了一个拼写检查器,使用trie存储和检查单词拼写错误。它将文本文件字典加载到内存中,接受单词以检查拼写错误并卸载内存。程序编译成功,但运行时会产生分段错误。基于valgrind,问题似乎是在我的插入函数中使用了未初始化的值。

//If word not present, inserts word into trie
//If the word is a prefix of a node, marks the "leaf node" (end-of-word node)
void insert(struct node *root, const char *word)
{
int length = strlen(word);
int index = 0;

//start from root node
struct node *tempNode = root;

for(int i = 0; i < length; i++)
{
    //if the current letter in word is a letter
    if(word[i] != '\'')

        //convert the alphabet to it's respective index number
        index = CHAR_TO_INDEX(tolower(word[i]));

    else
        //assign index number 27 (for apostrophe)
        index = INPUT_SIZE;

    //create a new node if path doesn't exist (is NULL)
    if(!(tempNode->children[index]))
        tempNode->children[index] = getNode();

        //go to next node  
        tempNode = tempNode->children[index];
        }
    //mark last node as leaf
    tempNode->isWord = true;
}

插入(在trie中放置单词)由load调用(将单词txt文件中的单词移动到内存中):

bool load(const char *dictionary)
{
//initialise variables
char ch;
char word[LENGTH] = "";
int counter = 0;

struct node *root = getNode();

//open file to start inserting words
FILE *file = fopen(dictionary, "r");

//load words in dictionary into memory
while (EOF)
{
    while((ch = fgetc(file)) != '\n')
    {
        word[counter] = ch;
        counter++;
    }
    //whole word found, insert word and reset counter, increment word count
    insert(root, word);
    counter = 0;
    word_Count++;
}

//close all open files if EOF is reached, else loading has failed- return false
if(EOF == true)
    {
    fileLoaded = true;
    fclose(file);
    return true;
    }
else return false;
}

和getNode()创建一个初始化为NULL的新节点:

    //Returns new trie node initialised to NULL
    struct node *getNode(void)
    {
    //initialise new node
    struct node *newNode = NULL;

    newNode = malloc(sizeof(struct node));

    //proceed if enough memory to allocate
    if(newNode) 
    {
    //initialise pointers
    for(int i = 0; i < INPUT_SIZE; i++)
        newNode->children[i] = NULL;

    newNode->isWord = false;
    }
    else return false;

    return newNode;
    }

struct node的定义:

    //Returns new trie node initialised to NULL
struct node *getNode(void)
{
    //initialise new node
    struct node *newNode = NULL;

    newNode = malloc(sizeof(struct node));

    //proceed if enough memory to allocate
    if(newNode) 
    {
        //initialise pointers
        for(int i = 0; i < INPUT_SIZE; i++)
            newNode->children[i] = NULL;

        newNode->isWord = false;
    }
    else return false;

    return newNode;
}

根据valgrind的错误:

    Conditional jump or move depends on uninitialised value(s)
==9334==    at 0x4011DD: insert (dictionary.c:84)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)
==9334==  Uninitialised value was created by a heap allocation
==9334==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9334==    by 0x4010CB: getNode (dictionary.c:40)
==9334==    by 0x4011E7: insert (dictionary.c:85)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)
==9334== 
==9334== Use of uninitialised value of size 8
==9334==    at 0x4011D5: insert (dictionary.c:84)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)
==9334==  Uninitialised value was created by a heap allocation
==9334==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9334==    by 0x4010CB: getNode (dictionary.c:40)
==9334==    by 0x4011E7: insert (dictionary.c:85)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)
==9334== 
==9334== Invalid read of size 8
==9334==    at 0x4011D5: insert (dictionary.c:84)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)
==9334==  Address 0x91 is not stack'd, malloc'd or (recently) free'd
==9334== 
==9334== 
==9334== Process terminating with default action of signal 11 (SIGSEGV)
==9334==  Access not within mapped region at address 0x91
==9334==    at 0x4011D5: insert (dictionary.c:84)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)

valgrind使用--leak-check = full, - leak-check = full和--show-leak-kinds = all运行。我曾尝试引用之前帖子中的类似错误,但上下文中的差异使我难以确定应该做些什么。第84行是读取if(!(tempNode-&gt; children [index]))的行。这似乎(对我来说)是问题的根本原因。

谢谢!

1 个答案:

答案 0 :(得分:0)

SELECT ID_Reference,
       SUBSTRING(Balance,CHARINDEX('-',Balance)+1,Len(Balance))AS Balance 
 FROM SB_RentAccountBalances_V
 WHERE CHARINDEX('-',Balance)>0

这是代码中导致未定义行为的部分。

你的字符串while((ch = fgetc(file)) != '\n') { word[counter] = ch; counter++; } //whole word found, insert word and reset counter, increment word count insert(root, word); 不是空终止,但是word期望它(因为它做的第一件事是调用insert,它需要一个空终止的字符串)。

简单修复就是

strlen

在调用word[counter] = '\0'; 之前,假设一切都在界限内。