I am learning C and have a question about structs.
I have a
struct myStruct {
char member1[16];
char member2[10];
char member3[4];
};
This should take at least 30 bytes of memory to store. Would it be possible to copy all of this data into the variable char foo[30]? What would be the syntax?
You can't just directly copy the whole thing, because the compiler may arbitrarily decide how to pad/pack this structure. You'll need three memcpy calls:
struct myStruct s;
// initialize s
memcpy(foo, s.member1, sizeof s.member1);
memcpy(foo + sizeof s.member1, s.member2, sizeof s.member2);
memcpy(foo + sizeof s.member1 + sizeof s.member2, s.member3, sizeof s.member3);
The size of struct myStruct is sizeof(struct myStruct) and nothing else. It'll be at least 30, but it could be any larger value.
You can do this:
char foo[sizeof(struct myStruct)];
struct myStruct x; /* populate */
memcpy(foo, &x, sizeof x);
According to the C Standard (6.2.6 Representations of types)
4 Values stored in non-bit-field objects of any other object type
consist of n × CHAR_BIT bits, where n is the size of an object of that
type, in bytes. The value may be copied into an object of type
unsigned char [n] (e.g., by memcpy); the resulting set of bytes is
called the object representation of the value.
So you can write simply
unsigned char foo[sizeof( struct myStruct )];
struct myStruct s = { /*...*/ };
memcpy( foo, &s, sizeof( struct myStruct ) );
Take into account that you could copy the data members separatly in one array. For example
unsigned char foo[30];
struct myStruct s = { /*...*/ };
unsigned char *p = foo;
memcpy( p, s.member1, sizeof( s.member1 ) );
memcpy( p += sizeof( s.member1 ), s.member2, sizeof( s.member2 ) );
memcpy( p += sizeof( s.member2 ), s.member3, sizeof( s.member3 ) );
Yes, it is possible.
There are different ways you can go about doing this. Below are the two simplest methods.
struct myStruct myVar;
/* Initialize myVar */
...
memcpy (foo, &myVar, sizeof (myStruct));
Or if you are dealing with a pointer ...
struct myStruct * myVarPtr;
/* Initialize myVarPtr */
...
memcpy (foo, myVarPtr, sizeof (myStruct));
Note that when copying a structure to/from a character array like this, you have to be very careful as structure sizes are not always what you might first think. In your particular case, there might not be any issues; but in general, you should at least be aware of potential padding, alignment and type size issues that may change the size of your structure.
Hope this helps.
you could do the following if you have a myStruct variable named st:
strcpy(foo, st.member1);
strcat(foo, st.member2);
strcat(foo, st.member3);
Pretty simple with memcpy.
char foo[30];
struct myStruct s;
s.member1 = //some data
s.member2 = //some data
s.member3 = //some data
memcpy(foo, &s, 30);
Related
For example I have a struct
struct s{
char c;
int x;
};
And I use calloc() to allocate memory.
s *sp = (s*) calloc(1, sizeof(s));
Now, what will be the values of sp->c and sp->x?
"What will be the values of sp->c and sp->x?"
Since calloc() sets all bits of the allocated memory to 0, c and x will have the value of 0 if the 0 value representation of int and char is of all bits to 0 (which is common).
Note that in the case of pointers, the pointer might not be standard-compliant NULL pointer when just setting all bits to 0 as the C standard does not require the representation of NULL pointers to be all-zero-bits.
Side notes:
1.
struct s{
char c;
int x;
};
s *sp = (s*) calloc(1, sizeof(s));
can´t work as s isn´t a typedefd type; it is a structure tag. Therefore, You need to precede s by the struct keyword:
struct s *sp = (struct s*) calloc(1, sizeof(struct s));
2.
You do not need to cast the returned pointer from calloc() and other memory management functions and rather avoid it since it can add clutter to your code. -> Do I cast the result of malloc
So, just do:
struct s *sp = calloc(1, sizeof(struct s));
I've been trying to implement a generic array searcher and came across this answer, which made me think that my implementation is only valid for dynamically allocated arrays.
The implementation looks like this:
void *array_search( void *arr,
size_t elem_size,
size_t len,
arr_search_checker v,
void *match)
{
char *p = arr;
for(unsigned i = 0; i < len; ++i)
{
if(v((void *) p, match))
return p;
p += elem_size;
}
return NULL;
}
The type arr_search_checker:
typedef bool (*arr_search_checker)(void *, void *);
Having a simple structure:
struct test_struct { int i; char c; };
And a check function:
bool test_checker(void *l, void *r)
{
struct test_struct *ls = l, *rs = r;
return ls->i == rs->i && ls->c == rs->c;
}
And array of length len which is an array of struct test_struct one can invoke the searcher:
struct test_struct match = { .i = 5, .c = 'A' };
struct test_struct *res = array_search(array,
sizeof(struct test_struct), len, test_checker, &match);
Is that true that this implementation of array_search is only valid for dynamically allocated arrays because of incrementation of the char pointer p by size of the single element in the array what can be dangerous for padded arrays? Or is it totally invalid?
Please state your question in the question topic.
The function array_search as valid for any arrays (don't know why dynamically allocated arrays are particular in any way). Char pointer p is incremented by elem_size. elem_size is assigned the value of sizeof(struct test_struct) in your example and that's perfectly ok. Padding has nothing to do with it. Imagine struct test_struct has some padding bytes added to it (anywhere, at the end of the structure or between any of it members). Then sizeof(struct test_struct) will be the size of the test_struct structure including the padding bytes, and p will still be increment correctly.
You may convert any pointer to void* and any pointer to char* without braking the strict aliasing rule. You cannot do arithmetic on void* pointers, that's why it gets converted to char* pointer. elem_size represents the size of a single array element in bytes, char represents one byte in memory, by doing p += elem_size; you add elem_size bytes to p (I like the form p = &p[elem_size];). The smallest addressable size in C is one byte (remember that byte may not be 8 bits) and the size of every structure or type in C must be an integral value (ie. sizeof(struct test_struct) cannot return 1,5).
For more, look at bsearch and qsort functions from standard C library. They have a very similar declaration to array_search and work with any array types, just like array_search here.
I'm currently learning C and I have trouble understanding the following code:
struct dns_header
{
unsigned char ra : 1;
unsigned char z : 1;
unsigned char ad : 1;
unsigned char cd : 1;
unsigned char rcode : 4;
unsigned short q_count : 16;
};
int main(void)
{
struct dns_header *ptr;
unsigned char buffer[256];
ptr = (struct dns_header *) &buffer;
ptr->ra = 0;
ptr->z = 0;
ptr->ad = 0;
ptr->cd = 0;
ptr->rcode = 0;
ptr->q_count = htons(1);
}
The line I don't understand is ptr = (struct dns_header *) &buffer;
Can anyone explain this in detail?
Your buffer is simply a contiguous array of raw bytes. They have no semantic from the buffer point of view: you cannot do something like buffer->ra = 1.
However, from a struct dns_header * point of view those bytes would become meaningful. What you are doing with ptr = (struct dns_header *) &buffer; is mapping your pointer to your data.
ptr will now points on the beginning of your array of data. It means that when you write a value (ptr->ra = 0), you are actually modifying byte 0 from buffer.
You are casting the view of a struct dns_header pointer of your buffer array.
The buffer is just serving as an area of memory -- that it's an array of characters is unimportant to this code; it could be an array of any other type, as long as it were the correct size.
The struct defines how you're using that memory -- as a bitfield, it presents that with extreme specificity.
That said, presumably you're sending this structure out over the network -- the code that does the network IO probably expects to be passed a buffer that's in the form of a character array, because that's intrinsically the sanest option -- network IO being done in terms of sending bytes.
Suppose you want to allocate space for the struct so you could
ptr = malloc(sizeof(struct dns_header));
which will return a pointer to the allocated memory,
ptr = (struct dns_header *) &buffer;
is almost the same, except that in this case it's allocated in the stack, and it's not necessary to take the address of the array, it can be
ptr = (struct dns_header *) &buffer[0];
or just
ptr = (struct dns_header *) buffer;
there is no problem in that though, because the addresses will be the same.
The line I don't understand is ptr = (struct dns_header *) &buffer;
You take the address of the array and pretend like it is a pointer to a dns_header. It is basically raw memory access, which is unsafe, but OK if you know what you are doing. Doing so will grant you access to write a dns_header in the beginning of the array.
Ideally, it should be an array of dns_headers not a byte array. You have to be cautious about the fact that dns_header contains bit fields, the implementation of which is not enforced by the standard, it is entirely up to the compiler vendors. Although bit field implementations are fairly "sane", there is no guarantee, so the size of a byte array might actually be mismatched with your intent.
Adding to the other answers posted:
This code is illegal since ANSI C. ptr->q_count = htons(1); violates the strict aliasing rule.
It is only permitted to use an unsigned short lvalue (i.e. the expression ptr->q_count) to access memory that either has no declared type (e.g. malloc'd space), or has declared type of short or unsigned short or compatible.
To use this code as-is, you should pass -fno-strict-aliasing to gcc or clang. Other compilers may or may not have a similar flag.
An improved version of the same code (which also has some forwards-compatibility to the structure size changing) is:
struct dns_header d = { 0 };
d.q_count = htons(1);
unsigned char *buffer = (unsigned char *)&d;
This is legal because the strict aliasing rule permits unsigned char to alias anything.
Note that buffer is currently unused in this code. If your code is actually a smaller snippet of larger code then buffer may have to be defined differently. In any case, it could be in a union with d.
A struct directly references a contiguous block of memory and each field within a struct is located at a certain fixed offset from the start. Variables can then be accessed via a struct pointer or by the struct declared name which returns the same address.
Here we declare a packed struct which references a contiguous block of memory:
#pragma pack(push, 1)
struct my_struct
{
unsigned char b0;
unsigned char b1;
unsigned char b2;
unsigned char b3;
unsigned char b4;
};
#pragma pack(pop)
Pointers can then be used to refer to the struct by its address. See this example:
int main(void)
{
struct my_struct *ptr;
unsigned char buffer[5];
ptr = (struct my_struct *) buffer;
ptr->b0 = 'h';
ptr->b1 = 'e';
ptr->b2 = 'l';
ptr->b3 = 'l';
ptr->b4 = 'o';
for (int i = 0; i < 5; i++)
{
putchar(buffer[i]); // Print "hello"
}
return 0;
}
Here we explicitly map 1:1 the struct contiguous block of memory to the contiguous block of memory pointed by buffer (using the address to the first element).
An array address and the name of the address are numerically identical but have different types. These two lines are thus equivalent:
ptr = (struct my_struct *) buffer;
ptr = (struct my_struct *) &buffer;
This is usually not a problem if we use the address as is and cast it appropriately. Dereferencing an array address of type pointer to array-of-type yields the same pointer but with a different type array-of-type.
Although it might seem convenient to manipulate memory in this fashion, it is strongly discouraged as the resulting code becomes painfully difficult to understand. If you really have no choice, I suggest using an union to specify that the struct is to be used in a particular manner.
I have the following code:
/* sample.c */
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include"hermes.h"
#include<string.h>
int main (){
struct hermes *h ;
h = ( struct hermes *) malloc ( sizeof ( struct hermes *));
strcpy ( h->api->search_response->result_code , "123" );
printf("VALue : %s\n" , h->api->search_response->result_code );
return 0;
}
/* hermes.h */
struct hermes {
union {
/* search response */
struct {
int error_code;
char *result_code;
char *user_track_id;
struct bus_details bd;
}*search_response;
}*api;
};
I get a segmentation fault when I try to access the elements. Could anyone tell me what is the right way to access these elements?
Your malloc() line isn't correct:
h = ( struct hermes *) malloc ( sizeof ( struct hermes *));
should be:
h = ( struct hermes *) malloc ( sizeof ( struct hermes));
Remove the * in the sizeof(). Otherwise, you're only allocating enough for a pointer rather than the struct itself.
Also, the cast isn't necessary in C.
Use this struct:
#define MAX 512 /* any number you want*/
struct hermes {
union {
/* search response */
struct {
int error_code;
char result_code[MAX];
char user_track_id[MAX];/* can use different sizes too*/
struct bus_details bd;
}search_response[MAX];/* can use different sizes too*/
}*api;
};
Or if you want to use your current struct, malloc the pointer element like:
h->api = malloc((sizeof(int)+sizeof(char)*MAX*2+sizeof(struct bus_details))*MAX)
It's not a problem of accessing the elements. That's about all that you are doing correctly.
Here are some of the things that are wrong. First, you aren't allocating enough space for a hermes struct, just enough for a pointer. Then, even if you malloc( sizeof ( struct hermes ) );, the one element (api) is an uninitialized pointer. You can't just follow uninitialized pointers down deep into the data structure, because they will be pointing to who knows where in memory. You first need to allocate something for h->api to point to. Then you need to allocate space for h->api->search_response. If you correct all that, then you are copying a string to ... who knows where? You should use strdup, not strcpy to create a new string, then you should assign the return value to result_code. Also, your union has only one element, so it's kind of pointless (unless there's more to it that you haven't posted).
EDIT Here's one way of initializing h:
h = malloc( sizeof( struct hermes ) );
h->api = malloc( sizeof( *h->api ) );
h->api->search_response = malloc( sizeof( h->api->search_response ) );
h->api->search_response->result_code = strdup( "123" );
Note that in a well-behaved program that cleans up after itself, each of these allocations will have to be freed individually as well, in reverse order of the calls to malloc. Since you immediately call exit(0), no harm is done in this case if you don't.
For some reason if I try to get the actual size of mystruct I keep getting size 1.
I know that mystruct is holding the data cause I can dump it out and everything is in mystruct.
What could be the reason of getting size 1?
Thanks
// fragments of my code
struct mystruct {
char *raw;
int count;
};
struct counter {
int total; // = 30
}
static struct mystruct **proc()
{
int i = 0;
gchar *key,*val;
struct mystruct **a_struct;
struct counter c;
a_struct = (struct mystruct **)malloc(sizeof(struct mystruct *)*c.total);
while (table (&iter, (gpointer) &key, (gpointer) &val)) {
a_struct[i] = (struct mystruct *)malloc(sizeof(struct mystruct));
a_struct[i]->raw = (char*)key;
a_struct[i++]->count = (int)val;
}
size_t l = sizeof(a_struct) / sizeof(struct mystruct*);
printf("%d",l); // outputs 1
}
You're doing a couple things wrong. First, you're taking sizeof(a_struct) which is going to be the size of a pointer (since that's what a_struct is) and then dividing by the size of another pointer. Guaranteed 1.
Besides that, why are you doing a division at all? What I think you want is:
size_t l = sizeof(struct mystruct);
or
size_t l = sizeof(**a_struct);
Edit:
I think I see the reason for your division now; you're trying to find the size of that array. That's not going to work - sizeof can only work at compile time in C (with some special exceptions in C99 which don't apply to your code), so it can't figure out the size of a dynamic array like that.
you're dividing the size of a pointer by the size of a pointer.
a_struct is a double pointer to struct mystruct.
struct mystruct * is a pointer to struct mystruct.
Both there sizes will be same.
Do this size_t l = sizeof(struct mystruct);
You are taking the size of two pointers and dividing one by the other,
size_t l = sizeof(a_struct) / sizeof(struct mystruct*);
a_struct is declared as struct mystruct **a_struct so this is the same as saying
size_t l = sizeof(struct mystruct **) / sizeof(struct mystruct*);
since all pointers have the same size, ** is the same size as *, so this will always evaluate to 1.
I'm not quite sure what you are trying to print out here, the size of a_struct ? or the total allocation size? The size of a_struct is just c.total, the total allocation is the sum of all of the values that you passed to malloc.