【问题标题】:Convert struct in byte array and store in db. Read db and get byte array to recreate the struct in C将 struct 转换为字节数组并存储在 db 中。读取 db 并获取字节数组以在 C 中重新创建结构
【发布时间】:2016-12-15 14:20:48
【问题描述】:

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

结构 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并存储它。

我真的很努力解决这个问题。提前谢谢你。

【问题讨论】:

  • 您不能将指针值写入文件并期望它工作。
  • 我写的原始数据是怎么回事。
  • 这很重要。在您的示例中,dead 实际上并不包含字符串"John""Doe",而仅包含指向这些字符串的指针。所以如果你写dead的原始数据,你只写指针的值而不是字符串本身。
  • 指针不是数组!
  • 那么预分配内存可以解决这个问题吗?

标签: c arrays struct filesystems gdbm


【解决方案1】:

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

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

mystruct s;
s.name = "Salam";

这将为字符串“Salam”保留一个内存空间,将字符串Salam放入并返回指向s.name的指针。

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

如果你想这样做,你必须为 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);

【讨论】:

  • 罗杰。我对 C 和指针不太熟悉。我还试图在这个结构中添加一个字符串数组(char [])。那具体案例呢?
  • 您有两种选择,一种是使用高效的指针,另一种是使用效率不高但更简单的二维字符数组
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

    问题在于 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);
    

    诚然,这段代码很难维护。

    【讨论】:

    • 这也是一个很好的解决方案。我认为这样做你可以设法拥有一个在我的情况下更好的动态结构。
    猜你喜欢
    • 1970-01-01
    • 2020-07-29
    • 2018-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-08
    • 1970-01-01
    相关资源
    最近更新 更多