CS50 Speller,通过了测试,但是检查了50个问题,使用了未初始化的值

时间:2019-05-10 06:23:09

标签: c cs50

我刚刚完成了cs50 Speller,并且代码通过了所有其他测试,但是它一直告诉我“您正在尝试使用8字节变量,该变量可能没有值”,拼写检查部分的代码。

我已经看到其他人对此问题的回答,但是我仍然不知道为什么会有这个问题。

Makefile

speller:
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o speller.o speller.c
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -c -o dictionary.o dictionary.c
    clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -o speller speller.o dictionary.o

speller.c

// Implements a spell-checker

#include <ctype.h>
#include <stdio.h>
#include <sys/resource.h>
#include <sys/time.h>

#include "dictionary.h"

// Undefine any definitions
#undef calculate
#undef getrusage

// Default dictionary
#define DICTIONARY "dictionaries/large"

// Prototype
double calculate(const struct rusage *b, const struct rusage *a);

int main(int argc, char *argv[])
{
    // Check for correct number of args
    if (argc != 2 && argc != 3)
    {
        printf("Usage: speller [dictionary] text\n");
        return 1;
    }

    // Structures for timing data
    struct rusage before, after;

    // Benchmarks
    double time_load = 0.0, time_check = 0.0, time_size = 0.0, time_unload = 0.0;

    // Determine dictionary to use
    char *dictionary = (argc == 3) ? argv[1] : DICTIONARY;

    // Load dictionary
    getrusage(RUSAGE_SELF, &before);
    bool loaded = load(dictionary);
    getrusage(RUSAGE_SELF, &after);

    // Exit if dictionary not loaded
    if (!loaded)
    {
        printf("Could not load %s.\n", dictionary);
        return 1;
    }

    // Calculate time to load dictionary
    time_load = calculate(&before, &after);

    // Try to open text
    char *text = (argc == 3) ? argv[2] : argv[1];
    FILE *file = fopen(text, "r");
    if (file == NULL)
    {
        printf("Could not open %s.\n", text);
        unload();
        return 1;
    }

    // Prepare to report misspellings
    printf("\nMISSPELLED WORDS\n\n");

    // Prepare to spell-check
    int index = 0, misspellings = 0, words = 0;
    char word[LENGTH + 1];

    // Spell-check each word in text
    for (int c = fgetc(file); c != EOF; c = fgetc(file))
    {
        // Allow only alphabetical characters and apostrophes
        if (isalpha(c) || (c == '\'' && index > 0))
        {
            // Append character to word
            word[index] = c;
            index++;

            // Ignore alphabetical strings too long to be words
            if (index > LENGTH)
            {
                // Consume remainder of alphabetical string
                while ((c = fgetc(file)) != EOF && isalpha(c));

                // Prepare for new word
                index = 0;
            }
        }

        // Ignore words with numbers (like MS Word can)
        else if (isdigit(c))
        {
            // Consume remainder of alphanumeric string
            while ((c = fgetc(file)) != EOF && isalnum(c));

            // Prepare for new word
            index = 0;
        }

        // We must have found a whole word
        else if (index > 0)
        {
            // Terminate current word
            word[index] = '\0';

            // Update counter
            words++;

            // Check word's spelling
            getrusage(RUSAGE_SELF, &before);
            bool misspelled = !check(word);
            getrusage(RUSAGE_SELF, &after);

            // Update benchmark
            time_check += calculate(&before, &after);

            // Print word if misspelled
            if (misspelled)
            {
                printf("%s\n", word);
                misspellings++;
            }

            // Prepare for next word
            index = 0;
        }
    }

    // Check whether there was an error
    if (ferror(file))
    {
        fclose(file);
        printf("Error reading %s.\n", text);
        unload();
        return 1;
    }

    // Close text
    fclose(file);

    // Determine dictionary's size
    getrusage(RUSAGE_SELF, &before);
    unsigned int n = size();
    getrusage(RUSAGE_SELF, &after);

    // Calculate time to determine dictionary's size
    time_size = calculate(&before, &after);

    // Unload dictionary
    getrusage(RUSAGE_SELF, &before);
    bool unloaded = unload();
    getrusage(RUSAGE_SELF, &after);

    // Abort if dictionary not unloaded
    if (!unloaded)
    {
        printf("Could not unload %s.\n", dictionary);
        return 1;
    }

    // Calculate time to unload dictionary
    time_unload = calculate(&before, &after);

    // Report benchmarks
    printf("\nWORDS MISSPELLED:     %d\n", misspellings);
    printf("WORDS IN DICTIONARY:  %d\n", n);
    printf("WORDS IN TEXT:        %d\n", words);
    printf("TIME IN load:         %.2f\n", time_load);
    printf("TIME IN check:        %.2f\n", time_check);
    printf("TIME IN size:         %.2f\n", time_size);
    printf("TIME IN unload:       %.2f\n", time_unload);
    printf("TIME IN TOTAL:        %.2f\n\n",
           time_load + time_check + time_size + time_unload);

    // Success
    return 0;
}

// Returns number of seconds between b and a
double calculate(const struct rusage *b, const struct rusage *a)
{
    if (b == NULL || a == NULL)
    {
        return 0.0;
    }
    else
    {
        return ((((a->ru_utime.tv_sec * 1000000 + a->ru_utime.tv_usec) -
                  (b->ru_utime.tv_sec * 1000000 + b->ru_utime.tv_usec)) +
                 ((a->ru_stime.tv_sec * 1000000 + a->ru_stime.tv_usec) -
                  (b->ru_stime.tv_sec * 1000000 + b->ru_stime.tv_usec)))
                / 1000000.0);
    }
}

dictionary.c

// Implements a dictionary's functionality

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

#include "dictionary.h"

// Represents number of buckets in a hash table
#define N 26

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

// Represents a hash table
node *hashtable[N];//pointer 
node *current[N], *previous[N];

// Hashes word to a number between 0 and 25, inclusive, based on its first letter
unsigned int hash(const char *word)
{
    return tolower(word[0]) - 'a';
}

//for hash table
int j;

//for counting 
unsigned int count;

// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
    // Initialize hash table
    for (int i = 0; i < N; i++)
    {
        hashtable[i] = NULL;
    }

    // Open dictionary
    FILE *file = fopen(dictionary, "r");
    if (file == NULL)
    {
        unload();     //?
        return false;
    }

    // Buffer for a word
    char word[LENGTH + 1];

    // Insert words into hash table
    while (fscanf(file, "%s", word) != EOF)       {
        j = tolower(word[0]) - 'a';

        if (hashtable[j] == NULL)
        {
            hashtable[j] = (node*)malloc(sizeof(node));

            if (hashtable[j] == NULL)
            {
                fprintf(stderr, "Error: unable to allocate required memory\n");
                return 1;
            }

            for (int i = 0; i < strlen(word); i++) 
            {
                (*hashtable[j]).word[i] = word[i]; 
            }

            (*hashtable[j]).next = NULL;

            previous[j] = hashtable[j];

            //clear the array "word"
            for (int i = 0; i < (LENGTH + 1); i++)
            {
                word[i] = '0';
            }
        }
        else
        {
            current[j] = (node*)malloc(sizeof(node));

            if (current[j] == NULL)
            {
                fprintf(stderr, "Error: unable to allocate required memory\n");
                return 1;
            }

            (*previous[j]).next = current[j];

            for (int i = 0; i < strlen(word); i++)
            {
                (*current[j]).word[i] = word[i];
            }

            (*current[j]).next = NULL;

            previous[j] = current[j];

            //clear the array "word"
            for (int i = 0; i < (LENGTH + 1); i++)
            {
                word[i] = '0';
            }
        }

        //count the number of words in dictionary
        count++;
    }

    printf("%d", count);

    // Close dictionary
    fclose(file);

    // Indicate success
    return true;
}



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

// Returns true if word is in dictionary else false
bool check(const char *word)
{
    // TODO

    //point current back to the start of linked list
    for (j = 0; j < N; j++)
    {
        current[j] = hashtable[j];
    }

    int i = tolower(word[0]) - 'a';

    while (strcasecmp(word, current[i]->word) != 0)  //the problem occurs here!
    {
        current[i] = (*current[i]).next;

        if(current[i] == NULL)
        {
            return false;
        }
    }

    return true;
}

// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
    // TODO
    for (j = 0; j < N; j++)
    {
        current[j] = hashtable[j];
    }

    for (j = 0; j < N; j++)
    {
        while (current[j] != NULL)
        {
            previous[j] = current[j];
            current[j] = (*current[j]).next;
            free(previous[j]);
        }
    }

    return true;                                
}

如果我通过了check50的其他测试,则意味着我已经成功创建了哈希表,并且检查了正确的拼写,那么为什么我仍然遇到“您要使用8字节的变量,而该变量可能没有价值”问题? while循环中的每个(* current [i])。word都应初始化。希望有人能帮助我,谢谢。

1 个答案:

答案 0 :(得分:0)

strcasecmp采用两个字符串作为参数。记住将字符串变成字符串的事情:终止的空字节。例如,这个循环

for (int i = 0; i < strlen(word); i++) 
            {
                (*hashtable[j]).word[i] = word[i]; 
            }

终止具有空字节的node.word。通过正确终止,确保在“创建” node.word的任何地方将其变成真实的字符串。