转换字节数组中的结构并存储在数据库中。读取 db 并获取字节数组以在 C 中重新创建结构

Convert struct in byte array and store in db. Read db and get byte array to recreate the struct in C

大家好,很抱歉提问,但我可以找到任何合适的解决方案。 我在一个文件系统上工作,我将每个文件节点作为键值对保存在 GDBM 数据库中。 我有一个具有一些属性的结构,我将其转换为字节数组

struct mystruct:

typedef struct nold{
char* name;
char* surname;
 int age;
}mystruct;

我把它转换成字节数组

dead.name="john";
dead.surname="doe";
dead.age=22;

//copy bytes of the our struct 
char buffer[sizeof(dead)]; 
memcpy(buffer, &dead, sizeof(dead));

为了存储在数据库中,我们使用如下数据结构:

 typedef struct {
         char *dptr;
         int  dsize;
      } datum

我填写的数据结构如下:

//create a key datum
char* k="file.txt";
key.dptr=k;
key.dsize=strlen(k)+1;



//create a value datum  here I assign bytes
value.dptr=buffer;
value.dsize = sizeof(dead);

现在我在 GDBM 中存储为键值对

然后在另一个文件中我读取了我存储的数据并尝试将其重新转换为结构

datum result;

//read
result=gdbm_fetch(file,key);

char* bytes=result.dptr;

mystruct* reborn;

reborn=(mystruct*)bytes;


//print from our new struct
printf("%s\n",reborn->name);
printf("%s\n",reborn->surname);
printf("%d\n",reborn->age);

它打印以下内容:

E���D$�$ˈ�k����E��
$�$ˈ�k����E��
22

它设法恢复了结构,但 char* 的数据丢失了。仅涵盖整数数据。知道为什么会这样吗?如何解决?它不能通过存储字节数组来解决如何将字节数组转换为十六进制或 base64 并按原样存储。

我真的很纠结这个one.Thank你提前

结构内部的指针只是指向字符数组的指针,而不是字符数组本身:

typedef struct nold{
   char* name;
   char* surname;
   int age;
}mystruct;

mystruct s;
s.name = "Salam";

这将为字符串 "Salam" 保留内存 space,将字符串 Salam 放入并 return 返回指向 s.name 的指针。

现在您正在将整个结构复制到其他内容中,您正在使用 sizeof(mystruct) 从结构地址复制,实际上它不包含字符串 "Salam",它只是包含指向 "Salam" 的指针.

如果你想这样做,你必须预先分配一些 space 给 name :

#define MAX_NAME_LEN    50
typedef struct nold{
   char name[MAX_NAME_LEN];
   char surname[MAX_NAME_LEN];
   int age;
}mystruct;

mystruct s;
strcpy(s.name, "Salam");

现在 memcpy 可以工作了

mystruct d;
memcpy(&d, &s, sizeof(mystruct);

问题是 name 和 surname 是指向字符串文字的指针。因此,您的结构不包含字符串本身,而是指向文字所在的数据部分的指针。一旦将其复制到缓冲区,实际上只是在复制指针值。重建后,这些指针值现在将指向某个不包含您的字符串的任意区域。

编辑:这是一个将数据传输到缓冲区的函数:

size_t copyMyStructToBuffer(mystruct *aPerson, char **buffer) {
    size_t nameLen = strlen(aPerson->name);
    size_t surnameLen = strlen(aPerson->surname);
    size_t structLen = nameLen + 1 + surnameLen + 1 + sizeof(int);
    *buffer = malloc(structLen);

    memcpy(*buffer, aPerson->name, nameLen + 1); // w/ terminator
    memcpy((*buffer)[nameLen+1], aPerson->surname, surnameLen + 1); // w/ terminator
    memcpy((*buffer)[nameLen+1+surnameLen+1], &aPerson->age, sizeof(int));

    return structLen;
}

以及如何使用它:

mystruct dead;
dead.name = "John";
dead.surname = "Doe";
dead.age = 22;
char *buff;
size_t buffLen;
buffLen = copyMyStructToBuffer(&dead, &buff);
// use buff here
free(buff);

不可否认,这段代码很难维护。

指针值仅在特定程序的特定 运行 上下文中才有意义。可以将它们写入并读回,但必须记住指针指定地址,而不是(直接)驻留在该地址 at 的数据,如果地址确实是对于访问它的程序完全有效。您不通过传递指针来传递进程之间指向的数据。

你或许可以通过将你想要传送的数据直接放入结构中来解决问题:

typedef struct {
     char data[MAX_DATA_SIZE];
     int  dsize;
} datum;

这种方法的缺点是您必须对数据大小设置一个固定的上限,但在许多情况下这不是问题。如果您需要无限数据,那么您需要一种完全不同的方法。