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.
Related
I have a series of structs that all have some relatively verbose initialization logic and am trying to refactor that out into a helper function so I don't have to keep writing it over and over. Here's a condensed version:
struct base
{
const int *i;
}
struct child1
{
struct base b;
int j;
}
struct child2
{
struct base b;
int k;
}
void *alloc_base_holder(const int *i, size_t size)
{
struct base b = { i };
void *anon = malloc(size);
// error GD320D622: 'memcpy' forming offset [N1, N2] is out of the bounds [0, N3] of object 'b' with type 'struct base'
return memcpy(anon, &b, size);
}
struct child1 *c1_alloc(const int *i)
{
return (struct child1 *)alloc_base_holder(i, sizeof(struct child1));
}
struct child2 *c2_alloc(const int *i)
{
return (struct child2 *)alloc_base_holder(i, sizeof(struct child2));
}
I'm trying to dynamically allocate and initialize the memory given the size of the struct and not the type, but I'm not sure how to do that.
My first thought was to initialize the base part that is common to all of the child types, and then just memcpy that into a void pointer that had been allocated to the correct size, but that's giving the error:
error GD320D622: 'memcpy' forming offset [N1, N2] is out of the bounds [0, N3] of object 'b' with type 'struct base'
I also had the idea to just manually set the memory of the void pointer (anon), but if that's possible, I haven't come up with the right search terms to find it.
Is this possible to do and can somebody point me in the right direction?
Edit:
I'm using gcc with C99 by the way.
Reason of the warning are explained in the other answer.
I suggest always accessing the object via it's final type (struct child1 or struct child2). Otherwise one may easily trigger UB due to strict aliasing rules.
Therefore it's better to have init_base_holder() rather than alloc_base_holder.
void init_base_holder(struct base *b, const int *i)
{
b->i = i;
}
struct child1 *c1_alloc(const int *i)
{
struct child1 *c = malloc(sizeof *c);
init_base_holder(&c->b, i);
return c;
}
struct child2 *c2_alloc(const int *i)
{
struct child2 *c = malloc(sizeof *c);
init_base_holder(&c->b, i);
return c;
}
You get the "error" because you copy size bytes from the base structure b, even if size > sizeof b (which will go out of bounds of the b structure object).
I recommend that you use calloc instead, to let the allocator zero-initialize the allocated memory.
Then copy only the base structure itself, i.e. sizeof b instead:
memcpy(anon, &b, sizeof b);
Of course, you first need to make sure that size >= sizeof b.
You can just allocate size bytes for an instance of base.
struct base *b = malloc(size);
And then initialize the members as usual.
I have the following structs:
typedef struct{
char *name;
int size;
void *data;
} Struct1;
typedef struct st2{
char *name;
struct st2 **Struct2array;
Struct1 **Struct1array;
int Struct1_n;
int Struct2_n;
} Struct2;
where the double pointers in Struct2 are used as dynamic arrays of pointers to other Struct2's or Struct1's. The data in Struct1 is used as a dynamic array to store some data. Struct1_n and Struct2_n represent the number of elements inside of their respective dynamic arrays.
When I make a variable of type Struct1, I fill the data by casting a char * to a void * and using memcpy to copy it into data. If I then cast to data back into a char pointer, I can get back the contents and they are generally the same. However, for some reason the values that data in Struct1 is pointing to change after the following line:
struct2pointer->Struct1array[struct2pointer->Struct1_n - 1] = struct1pointer;
Examples:
printf("%d\n", *(char *)(struct1pointer->data));
gives the value of the 1stbyte of struct1pointer->data as -96 immediately after the problematic line regardless of the value it printed immediately before(which was the same one memcpy-d into data). if I add 1 to the pointer before casting it to a char pointer(2nd byte) it always gives 32, if I add 2 (3rd byte)it always gives 96 and so on.
Why is this happening when the struct1pointer is on the right side of the assignment operator and what can be done to fix this?
EDIT:
Functions where content changes:
void struct2_addstruct1(Struct2 struct2pointer, Struct1 *struct1pointer){
struct2->Struct1_n++;
struct2pointer->Struct1array = realloc(struct2pointer->Struct1array, struct2->Struct1_n * sizeof(Struct1 *)); //edited to remove increment that was added on accident, isn't in the original code
struct2pointer->Struct1array[struct2pointer->Struct1_n - 1] = struct1pointer;
}
The function that creates Struct1:
void struct1_init(Struct1 *s, char *name, void *data, int size){
s->name = malloc(strlen(name) + 1);
strcpy(s->name, name);
s->size = size;
s->data = malloc(size);
memcpy(s->data, data, size);
}
This is how that funcion is called when creating struct1:
Struct1 *s;
struct1_init(s, name, data, size);
name, data and size are provided form the outside but shouldn't have anything to do with the problem.
Look at this code:
Struct1 *s;
struct1_init(s, name, data, size);
Here s is uninitialized.
However in struct1_init function you do assume that the pointer s is already pointing to a Struct1.
Maybe you forgot a malloc - like:
Struct1 *s = malloc(sizeof *s);
struct1_init(s, name, data, size);
Is it possible to find the size of item_t through the pointer?
typedef struct item
{
char x;
char y;
char life;
}item_t;
void main (void)
{
item_t test;
void *ptr = &test;
printf("%d\n",sizeof(ptr));
}
return: 8
Not if ptr is of type void* -- but it probably shouldn't be.
You can't dereference a void* pointer. You can convert it to some other pointer type and dereference the result of the conversion. That can sometimes be useful, but more often you should just define the pointer with the correct type in the first place.
If you want a pointer to an item_t object, use an item_t* pointer:
item_t test;
item_t *ptr = &test;
printf("%zu\n", sizeof(*ptr));
This will give you the size of a single item_t object, because that's the type that ptr points to. If ptr is uninitialized, or is a null pointer, you'll get the same result, because the operand of sizeof is not evaluated (with one exception that doesn't apply here). If ptr was initialized to point to the initial element of an array of item_t objects:
ptr = malloc(42 * sizeof *ptr);
sizeof *ptr will still only give you the size of one of them.
The sizeof operator is (usually) evaluated at compile time. It uses only information that's available to the compiler. No run-time calculation is performed. (The exception is an operand whose type is a variable-length array.)
The correct format for printing a value of type size_t (such as the result of sizeof) is %zu, not %d.
And void main(void) should be int main(void) (unless you have a very good reason to use a non-standard definition -- which you almost certainly don't). If a book told you to define main with a return type of void, get a better book; its author doesn't know C very well.
Short answer: no. Given only ptr, all you have is an address (answer by WhozCraig).
Longer answer: you can implement inheritance by having the first field in all your structs specify its size. For example:
struct something_that_has_size
{
size_t size;
};
struct item
{
size_t size;
char x;
char y;
char life;
};
struct item2
{
size_t size;
char x;
char y;
char z;
char life;
};
// Somewhere in your code
...
struct item *i1 = malloc(sizeof(struct item));
i1->size = sizeof(struct item); // you are telling yourself what the size is
struct item2 *i2 = malloc(sizeof(struct item2));
i2->size = sizeof(struct item2);
// Later in your code
void *ptr = ... // get a pointer somehow
size_t size = ((struct something_that_has_size*)ptr)->size; // here is your size
But instead of size, you should better record the type of your struct - it's more useful than just the size. This technique is called discriminated union.
You can only cast a void pointer to get what is behind in the correct type, you cannot dereference it directly.
#include <stdio.h>
#include <stdlib.h>
typedef struct item {
char x;
char y;
char life;
} item_t;
int main()
{
item_t test;
void *ptr = &test;
printf("%zu %zu\n", sizeof(*(item_t *) ptr), sizeof(item_t));
exit(EXIT_SUCCESS);;
}
But that is of not much use because you need to know the type in the first place and have won nothing.
TL;DR: no, not possible
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.
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.