【问题标题】:Creating a variable amount of linked lists for hashmap为 hashmap 创建可变数量的链表
【发布时间】:2016-01-25 01:19:15
【问题描述】:

以下是我的代码的重要部分,无用的部分已被注释掉:

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

#include "hmap.h"

struct val_word{
char *final_word;
struct val_word* next;
};


int main (int argc, char **argv){

  //Check if dictionary file is given 

  FILE *fp1;
  char key [125];
  char val [125];
  char temp;
  struct val_word *storage;
  char c;
  int i;
  int j;
  int l;


  HMAP_PTR dictionary = hmap_create(0, 0.75);

  fp1 = fopen(argv[1], "r");

  do{
    c = fscanf(fp1, "%s", key);


    // Convert string to lowercase

    strcpy(val, key);

    //Alphabetically sort string


    struct val_word* word_node = malloc(sizeof(struct val_word));
    word_node->final_word = val;
    word_node->next = NULL;

    storage = hmap_get(dictionary, key);


    if(storage == NULL){
        hmap_set(dictionary, key, word_node);
    }
    else{
        struct val_word *temp2 = storage;

        while(temp2->next != NULL){
            temp2 = temp2->next;
        }

        word_node->final_word = val;
        word_node->next = NULL;

        temp2->next = word_node;

        hmap_set(dictionary, key, storage);

    }


  } while (c != EOF);

  fclose(fp1);

  while(storage->next != NULL){
    printf("The list is %s\n", storage->final_word);
    storage = storage->next;
  }


  return 0;

}

我得到了一个长度未知的字典文件,以及一个我无法触及的哈希表实现文件。哈希表存储单词的混杂版本,键是单词的字母排序版本。例如:

部分词典包含:leloh、hello、elloh、holel

key 将是:ehllo

val 将是一个存储上述 4 个单词的链表。

hmap_get 获取给定键的值,hmap_set 设置给定键的值。

我的代码处理一切正常,直到我尝试打印位于某个键处的列表。 该列表将具有正确的大小,但仅存储它作为输入的 LAST 值。因此,添加到上面的示例中,我的列表将是(按时间顺序):

  1. leloh
  2. 你好->你好
  3. 霍勒 -> 霍勒 -> 霍勒
  4. ehllo -> ehllo -> ehllo -> ehllo

由于某种原因,它还将正确按字母顺序排列的字符串存储为最后一个字符串,我没有提供 hmap_set 函数。对此非常困惑。

但是,这个列表非常有意义。我只有一个节点,它位于 for 循环内。我没有更改变量名,因此指针都指向同一个节点,并且节点通过循环的每次迭代更改它包含的字符串。

所以,我想知道如何解决这个问题。 我不能动态命名变量,我不能只创建一个动态的链表数组,因为我觉得这会破坏拥有哈希表的目的。 我不知道我会使用哪种数据类型来存储它。

感谢您的帮助,谢谢!

【问题讨论】:

  • 使用do … while 这样的循环很糟糕。改用while (fscanf(fp1, "%s", key) == 1) 作为while 循环。您的代码通过循环运行,当您到达 EOF 时,最后一行重复。这不是一个好主意。
  • 问题是,我认为,您不断将新值读入val(从key 复制),但您只有一个变量。您需要先复制字符串,然后再将它们存储在哈希映射中。因此,查找strdup() 函数并使用strdup() 而不是strcpy() 复制key 中的字符串。将从strdup() 返回的值分配给word_node-&gt;final_word。如果不允许使用 strdup,请编写自己的变体:char *dup_str(const char *str) { size_t len = strlen(str) + 1; char *dup = malloc(len); if (dup != 0) memmove(dup, str, len); return dup; }
  • @JonathanLeffler 是的,我希望您将其作为答案提交,以便我可以选择它,但非常感谢!

标签: c loops linked-list hashtable


【解决方案1】:

将 cmets 转换为答案——代码更易于阅读。

我认为,问题在于您不断将新值读入val(从key 复制),但您只有一个变量。

您需要先复制这些字符串,然后再将它们存储在您的哈希映射中。因此,查找strdup() 函数并使用strdup() 而不是strcpy() 复制key 中的字符串。将strdup()返回的值赋值给word_node-&gt;final_word

如果不允许使用strdup(),请编写自己的变体:

char *dup_str(const char *str)
{
    size_t len = strlen(str) + 1;
    char *dup = malloc(len);
    if (dup != 0)
        memmove(dup, str, len);
    return dup;
}

【讨论】:

  • 太棒了。看到副本和副本之间的区别很有趣。我以为我使用 strcpy 是万无一失的!谢谢!
  • 也可以用memcpy()来完成,这里不需要memmove():字符串不能重叠。
  • @joop:我使用memmove(),所以我不必记住何时可以使用memcpy()。你是对的,但在我看来,简单是有益的。
  • 但这对初学者来说很困惑,恕我直言。非初学者应该知道内存对象何时可以/不能重叠。 (还有(愚蠢的)性能论点)
  • 初学者有什么困惑?一个工作有两个功能?是的;这太可笑了。因此,我使用无论如何都可以工作的那个,这样初学者就不会弄错了。虚假的(或大部分虚假的)效率论点不值得使用——它让初学者感到困惑。因此,对于初学者来说,“使用memmove(),因为它总是有效的”比涵盖memcpy() 所需的狡猾措辞更简单。 AFAIAC,memcpy() 不存在,除了作为初学者的陷阱,而不是像 gets()strtok()sprintf() 和......不存在(排序 - gets() 在我的书中算作核心转储) .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多