2

Hello everyone sorry for asking but I could find any appropriate solution. I am working on a file system where I save each file node as key-value pair in a GDBM database. I have a struct which has some attributes and I convert this to a byte array

struct mystruct:

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

I convert it as following to a byte array

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

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

to store in a database we use a datum structure which is as following:

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

I fill the datum structure as following:

//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);

Now I store in GDBM as key-value pair

Then in another file I read the data I store and try to recast it back to a struct

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);

It prints the following:

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

It manages to bring back the struct but data of char* is lost. Only the integer data is covered. Any idea why that happening? How to solve it? It it cant be solved by storing a byte array what about converting the byte array to hex or base64 and store it as such.

I really am struggling with this one.Thank you in advance.

Arnold Asllani
  • 155
  • 1
  • 12

3 Answers3

2

A pointer inside struct is just a pointer to character array not the character array itself:

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

mystruct s;
s.name = "Salam";

This will reserver a memory space for string "Salam", put string Salam into and return back the pointer to s.name.

now you're copying entire struct into something other, youre copying from struct address with sizeof(mystruct) which isn't hold string "Salam" actually, it just holds a pointer to "Salam".

If you want to do this way, you have to preallocate some space for 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");

now memcpy will work

mystruct d;
memcpy(&d, &s, sizeof(mystruct);
e.jahandar
  • 1,715
  • 12
  • 30
  • Roger that. Im not very familiar with C and mostly pointers. I am trying to also add an array of strings (char[]) inside this struct. What about that specific case? – Arnold Asllani Dec 15 '16 at 14:41
  • You have two choices, one is using pointers which is efficient, another one is using 2D character arrays which isn't very efficient but simpler – e.jahandar Dec 15 '16 at 14:45
2

Pointer values are meaningful only in the context of a specific run of a specific program. It is possible to write them and read them back, but it is essential to remember that a pointer designates an address, not (directly) the data residing at that address, if indeed the address is valid at all for the program accessing it. You do not convey the pointed-to data between processes by conveying the pointer.

You could perhaps solve the problem by putting the data you want to convey directly into the struct:

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

The drawback of this approach is that you have to put a fixed upper bound on the size of the data, but in many cases that's not a problem. If you need unbounded data, then you need an altogether different approach.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

The problem is that name and surname are pointers to string literals. So your struct does not contain the string itself but rather pointers to the data section where the literals reside. As soon as you copy that to your buffer, you are in fact simply copying the pointer values. Upon reconstruction, those pointer values would now point to some arbitrary area that don't contain your strings.

EDIT: Here's a function that transfers the data to a buffer:

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;
}

And how you can use it:

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);

Admittedly though, this code is difficult to maintain.

Leon Carlo Valencia
  • 7,979
  • 1
  • 11
  • 12
  • This is a good solution too. I think doing this way your can manage to have a dynamic struct which is way better in my case. – Arnold Asllani Dec 16 '16 at 10:25