Copy variable length structs to buffer - c

I want to copy variable length structs to a buffer. My struct looks like this:
typedef struct{
int flag;
int size;
unsigned char name[0];
} sp;
I do not know the size of name in advance. After I get size I malloc this struct by:
sp *s = malloc(sizeof(sp)+size)
To copy to a buffer, I do this:
char *buf = calloc(1000, sizeof(*buf));
memcpy(buf, s, sizeof(sp)); //s is of type sp with all memebers initialized
My buffer remains empty. What am I doing wrong?

I don't think you want to declare name as array of pointers, but instead an array of chars.
typedef struct {
int flag;
int size;
char name[];
} sp;
Then you can create an instance like this.
int size = 10;
sp *s = malloc(sizeof(sp)+size);
s->flag = 0;
s->size = size;
strncpy(s->name, "Hello!", size);
s->name[size - 1] = '\0'; // Make sure name is NULL-terminated
You can copy the structure into a buffer as follows.
void *buf = calloc(1000, 1);
memcpy(buf, s, sizeof(s)+ s->size);
Print out the names as follows to check it worked.
printf("Name is %s.\n", s->name);
printf("The buffer's copy of name is %s.\n", ((sp*)buf)->name);

Related

Dynamic Memory Allocation - Keep seg faulting

I have to dynamically allocate memory using these two functions but I keep getting a segfault. The code takes in strings from a file. I need to dynamically allocate memory for a specific number of monsters using structs, pointers and malloc.
typedef struct monster {
char *name;
char *element;
int population;
} monster;
monster* createMonster(char *name, char *element, int population){
//Copying the data into the monster
monster *temp =(monster*) malloc(sizeof(monster));
strcpy(temp->name, name);
strcpy(temp->element, element);
strcpy(temp->population, population);
return temp;
free(temp);
}
monster** readMonsters(FILE* infile, int *monsterCount){
//getting monster count and creating temp pointers
monster **temp = NULL;
char m_word [8];
fscanf(infile, "%d", monsterCount);
fscanf(infile, "%s", m_word); //reading the word monster to skip it
char* temp_name;
char* temp_element;
int temp_pop;
//allocating memory and creating an array of monster pointers * mcount
temp = (monster**)malloc(*monsterCount * sizeof(monster*));
for(int i = 0; i < monsterCount; i++){
fscanf(infile, "%s",temp_name);
fscanf(infile, "%s",temp_element);
fscanf(infile, "%d",temp_pop);
monster *monster_temp = createMonster(temp_name, temp_element, temp_pop);
temp[i]->name = monster_temp->name;
temp[i]->element = monster_temp->element;
temp[i]->population = monster_temp->population;
}
return temp;
}
You haven't posted the definition of struct monster.
If struct monster contains a lot of char* and you are assigning a char* to it, that char* needs to be allocated somewhere. It doesn't look like temp_name and temp_element have been allocated, which would cause a crash on the scanf.
your code segfault because you write at uninitialized and unallocated pointers
you directly write with strcpy name and element field of your struct but these two field point at unknow location
also, you try strcpy an integer, directly assign it : temp->population = population ;
finally you cannot return temp and free temp, if you return it it will be reused, you must not free it, hopefully the free is never reach as you exit the function one line before :)
for storing your strings into the struct, you have some possibilities
declare them as array of char in your structure : char name[64]
use a buffer in your structure and set the name and element field point on part of it
malloc them with strlen of original strings before the copy
directly point name and element vars of your createMonster function to the pointer, it will use original memory, but it's not suitable here as they come from temporary memory
an example of create monster function using a static common buffer for your strings (untested) :
#define MONSTER_MAX_BF 64
typedef struct monster {
char *name;
char *element;
int population;
char bf[MONSTER_MAX_BF];
} monster;
monster* createMonster(char *name, char *element, int population){
monster *temp =(monster*) malloc(sizeof(monster));
char * lastBf = temp->bf + (MONSTER_MAX_BF - 1); // buffer last char
char *bfp = bf, *p ;
// copy name
temp->name = bfp ;
p = name ;
while( *p && *bfp != lastBf ) *bfp++ = *p++ ;
*bfp++ = 0;
// copy element
temp->element = bfp ;
p = element ;
while( *p && *bfp != lastBf ) *bfp++ = *p++ ;
*bfp = 0;
temp->population = population ;
return temp;
}

Do I need to copy dynamic memory in my structs when resizing a dynamic array of structs?

I have a dynamic array, where each element is a struct that contains a dynamically allocated character array among other things.
When I resize the array, I create a new array that's about 50% bigger than the old array, copy the data from the old array into the new one, and delete the old one.
Here's the code:
typedef struct Thing
{
char* str; /* dynamic memory */
int num;
int other_data;
} thing;
typedef struct ThingStream
{
thing* things; /* dynamic memory */
int capacity;
int size;
} thing_stream;
void resize_thing_stream(thing_stream* ts)
{
int new_capacity;
thing* new_things;
int i;
new_capacity = ts->capacity + ts->capacity / 2;
new_things = malloc(new_capacity * sizeof(thing));
for(i = 0; i < ts->size; i++)
{
new_things[i] = ts->things[i];
/* here is where I would copy the str data */
}
free(ts->things);
ts->things = new_things;
ts->capacity = new_capacity;
}
Can I just expect the str to be in the new array, or do I need to copy the str data into the new array?
You can start by something simpler. Lets say you write text to a buffer, then you want to increase buf size and add more characters to it. The easiest way is to use realloc:
int main()
{
char *buf;
buf = malloc(4);
strcpy(buf, "123");
buf = realloc(buf, 7);
strcat(buf, "456"); //buf still contains 123
puts(buf);//output: 123456
free(buf);
}
You can achieve the same thing with malloc. But to use malloc a second time, you have to save the old string in to a different string, free the old allocation, allocate a larger buffer, and copy the old string. Example:
char *buf;
buf = malloc(4);
strcpy(buf, "123");
char *temp = strdup(buf); //save the old string
free(buf); //free the old string
buf = malloc(7); //allocate new size
strcpy(buf, temp); //copy the old string
strcat(buf, "456"); //finally the string is ready
free(temp); //cleanup temp variable
puts(buf);
free(buf);
To put this in some structure:
typedef struct string_t
{
char* data;
int capacity;
} string;
void string_reserve(string *str, int capacity)
{
str->data = realloc(str->data, capacity);//str->data was initialized to zero
str->capacity = capacity;
}
int main()
{
string str;
//initialize str:
str.data = 0;
str.capacity = 0;
string_reserve(&str, 4);
strcpy(str.data, "123");
string_reserve(&str, 7);
strcat(str.data, "456");
puts(str.data);
//free memory
free(str.data);
return 0;
}
Again you can achieve the same thing with malloc, but you have to be more careful.

Issue with assignment from incompatible pointer type

Hey so im trying to attempt to read in a file, store it in a hash and then copy it. However i get the incompatible pointer type
struct hash_struct {
int id;
char name[BUFFER_SIZE]; /* key (string WITHIN the structure */
UT_hash_handle hh; /* makes this structure hashable */
};
int main(int argc, char *argv[] )
{
char *lines[80];
FILE* fp = fopen("file.txt","r");
if(fgets(*lines, BUFFER_SIZE, fp) != NULL)
{
puts(*lines);
// do something
}
fclose(fp);
const char **n;
char *names[1024];
strcpy(*names, *lines);
struct hash_struct *s, *tmp, *users = NULL;
int i=0;
for (n = names; *n != NULL; n++)
{
s = (struct hash_struct*)malloc(sizeof(struct hash_struct));
strncpy(s->name, *n,10);
s->id = i++;
HASH_ADD_STR( users, name, s );
}
HASH_FIND_STR( users, "joe", s);
if (s) printf("joe's id is %d\n", s->id);
printf("Hash has %d entries\n",HASH_COUNT(users));
/* free the hash table contents */
HASH_ITER(hh, users, s, tmp) {
HASH_DEL(users, s);
free(s);
}
return 0;
}
The code works when i initialize const char **n, *names = {array elements here};
But it doesnt work with the code i have. Please help.
lines is declared to be an array of char pointers, but doesn't allocate any space for the strings they point to. In your working version, the compiler took care of allocating space for each string.
Plus, you can't use strcpy to copy an array of 80 pointers to an array of 1024 pointers.
Instead, each line you read in needs space to be allocated for it to be read into; then the addresses of each of those can be assigned to an element of names. In fact, as #BLUEPIXY suggests, line should be an array of 80 chars, not an array of 80 pointers-to-chars. Or you could just malloc the space for each new line, and put the address of that line into names.

how to malloc for this structure

typedef struct testMsg_ {
unsigned char opCode;
unsigned int Count;
char *macsStrList[MAC_ADDR_STR_LEN];
} testMsg_t;
Number of elements in macsStrList is m_Count.
I know following is not correct:
testMsg_t *pInput = (testMsg_t *) malloc(sizeof(testMsg_t) );
This is correct, given the structure you have done
testMsg_t *pInput = (testMsg_t *) malloc(sizeof(testMsg_t) );
However you are probably confused to the meaning of *arr[dimension] -- which is an array length dimension of pointers to chars -- reading between the lines,
MAC_ADDR_STR_LEN
Is probably ment to the legth of the string representation of a mac address (say <20 bytes?)
However your struct gives you 20 char pointers, and the character pointers still have to be initializaed to point to valid memory.
testMsg_t *pInput = (testMsg_t *) malloc(sizeof(testMsg_t) );
pInput->macsStrList[0] = (char *) malloc( MAC_ADDR_STR_LEN+1 );
pInput->macsStrList[1] = (char *) malloc( MAC_ADDR_STR_LEN+1 );
pInput->macsStrList[2] = (char *) malloc( MAC_ADDR_STR_LEN+1 );
...
or redefine your struct to
typedef struct testMsg_ {
unsigned char opCode;
unsigned int Count;
char macsStrList[NUMBER_OF_MAC_ADDRESSES][MAC_ADDR_STR_LEN];
} testMsg_t;
To avoid having to deal with multiple number of allocations.
ADDITION;
As per comments, given that the number of mac addresses are dynamically determined, you could also define the struct as;
typedef struct testMsg_ {
unsigned char opCode;
unsigned int Count;
char macsStrList[1][MAC_ADDR_STR_LEN];
} testMsg_t;
and then allocate it using
testMsg_t *pInput = (testMsg_t *) malloc(sizeof(testMsg_t) + (countOfMacsAddresses * MAC_ADDR_STR_LEN) );
That would have the added over a solution with pointers of that you could use realloc to resize the array dynamically if you needed to do that as well.....
I think what you're looking for is maybe (ok, Soren got in first, but I'll show a way to allocate a single contiguous chunk):
/* assuming we only need macStrList[0] ... [Count-1] */
struct testMsg
{
unsigned char opCode;
unsigned int Count;
char *macsStrList[];
};
struct testMsg *allocate_testMsg(int count)
{
char *string_storage;
struct testMsg *msg;
size_t size = sizeof(struct testMsg) /* base object */
+ (count * sizeof(char *)) /* char* array */
+ (count * (MAC_ADDR_STR_LEN+1)) /* char storage */
;
msg = malloc(size);
msg->Count = count;
string_storage = (char *)&(msg->macStrList[count]);
/* note msg->macStrList points to UNINITIALIZED but allocated storage.
it might be sensible to zero-fill string_storage, depending on how you'll
initialize it
*/
for (count=0; count < msg->Count;
++count, string_storage += (MAC_ADDR_STR_LEN+1))
{
msg->macStrList[count] = string_storage;
}
return msg;
}
Of course it is. You allocate a pointer to a testMsg_t which is an alias for struct testMsg_. However you need to initialize this object yourself.
(And you don't need to cast the allocated pointer in C).

Copy structure member to an array

struct {
char a[10];
char b[5];
char c[10];
} info;
How can I concatenate all the struct data members into one single array?
With memcpy():
// Assign a buffer big enough to hold everything
char *buf = malloc(sizeof(info.a) + sizeof(info.b) + sizeof(info.c));
// Get a pointer to the beginning of the buffer
char *p = buf;
// Copy sizeof(info.a) bytes of stuff from info.a to p
memcpy(p, info.a, sizeof(info.a));
// Advance p to point immediately after the copy of info.a
p += sizeof(info.a);
// And so on...
memcpy(p, info.b, sizeof(info.b));
p += sizeof(info.b);
memcpy(p, info.c, sizeof(info.c));
You could use sprintf. This funcions 'prints' a string into anoter:
int struct_size = sizeof(info);
char *result = (char*)malloc(sizeof(char)*struct_size);
sprintf(result, "%s%s%s", info.a, info.b, info.c);

Resources