【问题标题】:CS50 - LOAD - Get random character from no where when trying to execute loadCS50 - 加载 - 尝试执行加载时从任何地方获取随机字符
【发布时间】:2019-04-19 00:47:57
【问题描述】:

我是 C 编程新手。我正在尝试在 CS50 中执行 pset5,同时尝试理解内存、链表和哈希表的概念。我编写了代码并编译了它,但似乎有问题,因为每次我尝试执行代码时它都会返回一些垃圾值。有人可以帮我吗?非常感谢。

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

#include "dictionary.h"

#define DICTIONARY "dictionaries/small"

typedef struct node
{
char WORD[LENGTH + 1];
struct node *next;
}
node;

int hash(char *word);

int main(void)
{
node **HASHTABLE = malloc(sizeof(node) * 26);

//open the dictionary
FILE *dic = fopen(DICTIONARY, "r");
if (dic == NULL)
{
    fprintf(stderr, "Could not open the library\n");
    return 1;
}

int index = 0;
char word[LENGTH + 1];

for (int c = fgetc(dic); c != EOF; c = fgetc(dic))
{
    word[index] = c;
    index++;

    if (c == '\n')
    {
        int table = hash(word);
        printf("%d\n", table);
        //create a newnode
        node *newnode = malloc(sizeof(node));
        strcpy(newnode->WORD, word);
        newnode->next = NULL;

        printf("Node: %s\n", newnode->WORD);
        index = 0;

        //add new node to hash table
        if (HASHTABLE[table] == NULL)
        {
            HASHTABLE[table] = newnode;
        }
        else
        {
            HASHTABLE[table]->next = newnode;
        }
    }
}
for(int i = 0; i < 26; i++)
{
    node *p = HASHTABLE[i];
    while (p != NULL)
    {
        printf("%s", p->WORD);
        p = p->next;
    }
}

//free memory
for(int i = 0; i < 26; i++)
{
    node *p = HASHTABLE[i];
    while (p != NULL)
    {
        node *temp = p->next;
        free(p);
        p = temp;
    }
}
free(HASHTABLE);
}


int hash(char *word)
{
int i = 0;
if (islower(word[0]))
    return i = word[0] - 'a';
if (isupper(word[0]))
    return i = word[0] - 'A';
return 0;
}

【问题讨论】:

  • for (int c = fgetc(dic); c != EOF; c = fgetc(dic)) 通常写成int c; while ((c = fgetc(dic)) != EOF)
  • 顺便说一句,您应该将输出包含为代码块,而不是图像...
  • 另一个问题是尝试添加 3 个具有相同首字母的单词 - 您的哈希表链接不正确。
  • @AnttiHaapala 非常感谢您的 cmets。他们非常有帮助!这是我的第一个问题,所以我很难包含一个代码,也对图像感到抱歉。而且我并没有真正得到您对具有相同首字母的 3 个单词的评论……我只是在尝试使用试用词典。

标签: c memory linked-list hashtable cs50


【解决方案1】:

您的代码存在导致未定义行为的严重问题。

其中两个是这一行的结果:

node **HASHTABLE = malloc(sizeof(node) * 26);

这分配了 26 个node 结构,但HASHTABLE 变量需要指向node * 指针 数组的指针的地址(即@987654325 @ 在node **HASHTABLE 声明中)。

因此,您应该将其替换为:

node **HASHTABLE = malloc( 26 * sizeof( *HASHTABLE ) );

请注意,我使用了分配给 HASHTABLE 的变量的取消引用值。在这种情况下,这意味着 node(比声明中的 * 少一个)。所以如果HASHTABLE的类型发生变化,你不需要对malloc()语句做任何其他的修改。

这个问题虽然在技术上是未定义的行为,但可能不会导致任何问题。

不过还是有问题

node **HASHTABLE = malloc( 26 * sizeof( *HASHTABLE ) );

导致问题 - 并且是严重的问题。

这个由 26 个指针组成的数组没有被初始化 - 你不知道它们里面有什么。他们可以指向任何地方。所以这不会很好,如果有的话:

    if (HASHTABLE[table] == NULL)

意思是指向未知的地方:

    HASHTABLE[table]->next = newnode;

会导致各种问题。

最简单的解决方法?使用 calloc() 而不是 malloc() 将值全部初始化为零:

node **HASHTABLE = calloc( 26, sizeof( *HASHTABLE ) );

在解决这个问题之前,您的整个程序的任何结果都是有问题的,充其量是。

【讨论】:

  • 感谢您的评论。它帮助我更多地了解这些功能!
【解决方案2】:

垃圾的原因是你没有null-terminate字符串:

strcpy(newnode->WORD, word);

strcpy 期望 src 指向一个以 null 结尾的字符串。只需在末尾添加 0 即可。只需用

终止它
word[index] = 0;

strcpy 之前。

除此之外,the ones in Andrew Henle's answer 也应该被解决,但我不会在这里重复它们。


顺便说一句,接下来你会注意到

HASHTABLE[table]->next = newnode;

无法正常工作 - 该代码始终将节点作为第二个插入。但是你想总是无条件地插入新节点作为head,用

newnode->next = HASHTABLE[table];
HASHTABLE[table] = newnode;

first节点插入bucket不需要任何特殊条件。

【讨论】:

    猜你喜欢
    • 2021-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-11
    • 1970-01-01
    • 2018-08-23
    • 1970-01-01
    相关资源
    最近更新 更多