【问题标题】:Reading a binary file into a HashTable in C language用C语言将二进制文件读入HashTable
【发布时间】:2018-11-30 06:49:57
【问题描述】:

所以我正在创建一个密码库,并且需要能够将 HashTable 保存到二进制文件中,并在登录时将二进制文件中的相同内容读回程序 HashTable

我一直在玩 fwrite 和 fread 整整 4 个小时,但似乎找不到我哪里出错了。目前我正在segfaulting,我已经尝试GDB来找到它但只是得到消息:

Thread 2 received signal SIGSEGV, Segmentation fault.
0x00007fff9a9a16a0 in ?? ()

我的文件读取代码是:

void readFile(char * fileName, HTable * hashTable){
//Create file pointer and point it at fild to open
FILE * fp;
fp = fopen(fileName, "rb+");

//check if file exists
if(!fp){
    printf("File could not be opened\n");
    return;
}

//Set a temp Node to hold data, read data into the temp Node
//and insert temp into hashtable
Node * temp;    
while(1){
    fread(&temp, sizeof(Node), 1, fp);
    insertData(hashTable, temp->key, temp->data);
    if(feof(fp) != 0)
        break;
    printf("is this working?\n");
}

//Close file pointer
fclose(fp);
}

我写入文件的代码是:

void saveFile(char * fileName, HTable * hashTable){
//Create a FILE pointer and point it to the file to open or create
FILE * fp;
fp = fopen(fileName, "wb+");

//If the file does not exist or cannot be created give error message
if(!fp){
    printf("ERROR: File could not be created\n");
    return;
}


//for each index of the hashTable write its contents to the file
for(int i = 0; i < hashTable->size; i++){
    Node * temp = hashTable->table[i];
    while(temp != NULL){
        fwrite(&temp, sizeof(Node), 1, fp);
        temp = temp->next;
        printf("saved....\n");
    }
    printf("Index %d saved\n", i);
}

//Close file pointer
fclose(fp);

}

我知道段错误不是来自 insertData 函数,因为我已经对其进行了测试并且知道它可以正常工作。对于我做错的事情,我最好的猜测是我的 fwrite 条件不正确,或者当我读取数据时,我在某处错误地管理了内存。

HashTable 结构也是:

typedef struct HTable
{
size_t size; 
Node **table;
void (*destroyData)(void *data);
int (*hashFunction)(size_t tableSize, char * key);
void (*printData)(void *toBePrinted); 
}HTable;

我击中的节点是:

typedef struct Node
{
char * key;
void *data;
struct Node *next;
} Node;

感谢您的任何反馈!

【问题讨论】:

  • 您无法读取/写入键/数据的指针数据。您将需要读/写它们的值。
  • 将原始指针写入磁盘,然后在不同的进程中读取和使用这些指针是导致崩溃和烧毁的秘诀。如果您没有做任何不方便的事情(例如在过渡期间释放内存),则写入磁盘的哈希表中的指针对于同一进程可能是可以的,但不建议这样做。您必须忽略写入磁盘的指针,或者安排不写入磁盘指针(可能是偏移量,可能是其他一些信息)。
  • temp 是一个指针,您永远不会为它分配内存,但是您将数据读入它指向的任何位置。未定义的行为和简单的段错误。请查找有关如何使用调试器的教程,因为它可以帮助您解决遇到的每个问题,并告诉您哪里出了问题。
  • fread(&amp;temp... 不会在任何温度点读取数据。它在 temp 之上读取数据,然后继续粉碎堆栈。

标签: c io binary hashtable read-write


【解决方案1】:

首先,fwrite()/fread()的参数1是void *,不是**void ****。

第二,你不能使用 fwrite()/fread() 来保存/恢复你的数据,因为 Node 的成员 {key, data} 是指示额外的指针内存数据,但是使用 fwrite()/fread() 只是在指针 {char *, void *, Node *} 上操作,而不是额外的数据。

对于key,有一个例子:

Node n;
n.key = malloc(sizeof(char) * DEF_SIZE); // Suppose n.key = 0xb8b270
strcpy(n.key, "Hello world!");
fwrite(&n, sizeof(Node), 1, fp); // Only 0xb8b270 is written.

只有字符串(n.key)的地址,而不是字符串“Hello world”被写入文件。你能明白我说的吗?

简而言之,fwrite()/fread() 只是写入/读取原始数据,当您的结构包含指示额外内存数据的指针时,请小心使用它们。

对于结构

typedef struct Item
{
    char key[128];
    char value[128];
    struct Item *next;
} Item;

这里使用 fwrite()/fread() 可能没问题,因为 {char[], char[], Item *} 会被写/读,只有 {Item *} 是无效数据,{char[], char []} 可以正确保存/恢复。

我想在你的情况下使用 fprintf()/fscanf() 来替换 fwrite()/fread()。

第三,有一个我的hash map实现,可以帮到你: https://github.com/foreverpersist/hashmap

【讨论】:

  • 我会使用 fprintf() 和 fscanf() 但我需要这些信息不是人类可读的。如果没有存储 struct Node * next 也没关系,因为当我使用 insertData() 时,只要我可以将密钥和数据保存在二进制文件中,它就会将信息放在正确的位置。所以我认为你的意思是我需要传递原始数据,也就是密钥和数据的字符串,而不是它们的地址?
  • 是的。对于您关心的成员,应保存其原始数据。对于其他成员,您可以为所欲为。也许你需要像上面的struct Item 那样重建你的结构。
  • 如果您不希望数据可读,请查看encryption 并尝试使用database
【解决方案2】:

这是一些代码。它可以编译,但我还没有测试过。我会完成,但我必须睡觉。

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>
#include <malloc.h>

typedef struct Node
{
    char * key; //assuming this is null terminated
    void *data;
    int datasize; //number of bytes in data
    Node *next; //is this actually necessary?
} Node;

typedef struct HTable
{
    size_t size;
    Node *table;
    void(*destroyData)(void *data);
    int(*hashFunction)(size_t tableSize, char *key);
    char *(*printData)(void *data);
} HTable;


void writenode(FILE* fp, Node *node) {
    fprintf(fp, "%s\n", node->key);
    fprintf(fp, "%d\n", node->datasize);
    fwrite(node->data, sizeof(char), node->datasize, fp);
}

void readnode(FILE* fp, Node *node) {
    char buffer[5001];
    int len;
    //key
    fgets(buffer, 5000, fp);
    len = strlen(buffer) + 1;
    node->key = (char*) malloc(sizeof(char)*len);
    strcpy(node->key, buffer);
    //datasize
    fgets(buffer, 5000, fp);
    fscanf(fp, "%d", &(node->datasize));
    fread(buffer, node->datasize, sizeof(char), fp);
    //data
    node->data = malloc(sizeof(char)*node->datasize);
    memcpy(node->data, buffer, sizeof(char)*node->datasize);
}

【讨论】:

  • 所以我猜我因为建议使用 C 以外的语言而遭到反对,即使我发布了一个不错的解决方案。事实上,SEGFAULT 不会在更现代的语言中发生,所有这些容易出错的内存管理代码都会消失。
猜你喜欢
  • 2021-08-17
  • 2018-04-28
  • 1970-01-01
  • 1970-01-01
  • 2013-06-22
  • 1970-01-01
  • 2012-10-13
  • 2011-05-14
  • 2017-12-01
相关资源
最近更新 更多