why char buf[] instead of char *buf in redis's sdahdr struct - c

In redis there is a struct called sdahdr:
struct sdahdr
{
int len;
int free;
char buf[];
}
Why not use char *buf instead, and why is sizeof(sdahdr) == 8 instead of 12?

The char buf[] is a placeholder for a string. Since the max length of the string is not known at compiletime, the struct reserves the name for it, so it can be properly adressed.
When memory is allocated at runtime, the allocation must include the length of the string plus the sizeof the struct, and then can pass around the structure with the string, accessible via the array.
char *s = "test";
struct sdahdr *p = malloc(sizeof(struct sdahdr)+strlen(s)+1);
strcpy(p->buf, s);

Related

how to use memcpy to initialize a char pointer in struct

this is how I define struct.
struct urlFormat
{
int port;
char *host;
char *path;
int cat;
char *status;
};
this is how I initialize strcut and allocate the space for the pointer.
struct urlFormat *res;
res = malloc(sizeof(struct urlFormat));
when I used memcpy() function, it reported segmentation fault.
char *ptr1 = (char *)url;
int len = strlen(ptr1);
memcpy(res->host, ptr1, len);
I don't know how to solve it.
res->host is just a pointer (that is not pointing to anything yet).
Until res->host is pointing to some valid memory you can't memcpy to it.
You can either malloc some memory res->host = malloc(len + 1);(+1 for the 0 terminator and sizeof(char) is always 1 so omit it) or in this case just use res->host = strdup(ptr1);

How to initialize struct char array?

I'm having trouble initializing a string of characters belonging to a struct. "Expression must have a modifiable lvalue". Do I need to use strcopy? I am not quite sure how to utilize this. Here is my code:
typedef struct {
char name[50];
int attackDamage;
int magicDamage;
int defense;
int power;
int type;
} ITEM;
int main() {
ITEM item[10];
char itemset[5][5] = { 0 };
char champion1[] = "Gnar";
char champion2[] = "Vi";
char champion3[] = "Fizz";
char champion4[] = "Draven";
char champion5[] = "Braum";
item[0].name = "Brutalizer"; // Having issues here
}
EDIT: I did this and seems there isn't anymore errors. Is this the proper way?
strcpy(item[0].name, "Brutalizer");
item[0].name is an array, you cannot assign a pointer (string literal) to an
array. You need to copy the contents, in this case with strcpy for example:
strcpy(item[0].name, "Brutalizer");
Or if the length of the source is not know beforehand, then you can use
strncpy to avoid buffer overflows:
strncpy(item[0].name, "Brutalizer", sizeof item[0].name);
item[0].name[sizeof(item[0].name) - 1] = '\0'; // make sure that it's \0-terminated
or you can use snprintf
snprintf(item[0].name, sizeof item[0].name, "Brutalizer");

Copy variable length structs to buffer

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

Malloc an array inside a struct

I'm trying to malloc an array inside a struct but I keep getting segmentation errors when I run the program.
The compares function is just something I'm testing so it shouldn't be a part of the problem
typedef struct {
char *string;
} prod_t;
int
main(int agrc, char **argv){
int i = 0;
prod_t *c = NULL;
char str2[100] = "abcd";
c->string = (char *) malloc( 5 * sizeof(char));
strcpy(c->string,str2);
compares(c->stock,str2,i);
return 0;
}
The problem is that you're allocating space for the string, but you're not allocating the struct at all. c remains set to NULL and you're trying to dereference it.
Allocate space for the struct before assigning to its members
prod_t *c = malloc(sizeof(prod_t));
And, as a sidenote for your next-to-fix error: this field doesn't exist
c->stock
You need to allocate space for the struct before you can assign to the string member:
prod_t *c = malloc(sizeof(prod_t));
Also see Do I cast the result of malloc?
First of all, don't cast result of malloc. You only need to do that in C++. In C, it can actually hide potential problems.
Second of all, you need to allocate (or statically declare) your structure.
Third, c->stock doesn't exist. You probably meant c->string.
typedef struct {
char *string;
} prod_t;
int
main(int agrc, char **argv) {
int i = 0;
prod_t *c = malloc( sizeof( prod_t ));
char str2[100] = "abcd";
c->string = malloc( 5 * sizeof(char));
strcpy(c->string,str2);
compares(c->string,str2,i);
return 0;
}

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

Resources