I understand more about pointers and stuff but I have no idea what I am doing wrong here.
if i Have
char *(*data)[]
That would just be interpreted as "a pointer to an array of char pointers", right?
Then I have a struct like this, typedef'd to be myStruct, redundant as it may be, but that's aside the point:
typedef struct myStruct myStruct;
struct myStruct{
int size;
char *name;
myStruct *(*array)[];
}
Having looked around the site for similar posts, I got something like this:
//let's say allocating 5 spaces for this case
myStruct *a = malloc(sizeof(myStruct)+ sizeof(struct myStruct *)*5);
I am sure that the number I allocated the struct with is the size of the array.
I can't quite get my head wrapped around this, how does it work if it's a struct?
The plan here is to have this struct, and it contains an array of 5 myStruct's. Do I have to allocate them separately as well? like this?
a->array[0] = malloc( .... )
I tried and it keeps giving me an error saying Invalid use of array with unspecified bounds.
What am I doing wrong or how Can i fix this?
Thank you
From your comment, it sounds like you want a pointer to an array of pointers to structures, rather than a pointer to an array of structures, since "pointer to an array of char *" also has two levels of indirection.
Here's the difference:
A pointer to a structure:
A pointer to an array of structures:
A pointer to an array of pointers to structures:
Assuming you want #3, you can do it like so (in "traditional" C):
typedef struct myStruct myStruct;
struct myStruct
{
int size;
char *name;
myStruct **array;
};
myStruct *allocate_node(char *name, int size)
{
myStruct *p_node;
if (size < 0)
size = 0;
p_node = calloc(1, sizeof(myStruct));
p_node->name = name;
p_node->size = size;
p_node->array = calloc(1, size * sizeof(myStruct *));
return p_node;
}
void expand_node_child_array(myStruct *p_node, int size_to_add)
{
if (size_to_add < 1 || p_node == NULL)
return;
if (p_node->array == NULL)
{
p_node->size = size_to_add;
p_node->array = calloc(1, size_to_add * sizeof(myStruct *));
}
else
{
p_node->array = realloc(p_node->array, (p_node->size + size_to_add) * sizeof(myStruct *));
memset(p_node->array + p_node->size * sizeof(myStruct *), 0, size_to_add * sizeof(myStruct *));
p_node->size += size_to_add;
}
}
myStruct *get_child_node(myStruct *p_node, int index)
{
if (index < 0 || index >= p_node->size)
return 0;
return p_node->array[index];
}
int set_child_node(myStruct *p_node, int index, myStruct *p_child)
{
if (index < 0 || index >= p_node->size)
return FALSE;
p_node->array[index] = p_child;
return TRUE;
}
void free_node(myStruct **pp_node)
{
// Free p_node and the array but DO NOT free the children
if (pp_node == NULL || *pp_node == NULL)
return;
if ((*pp_node)->array != NULL)
free((*pp_node)->array);
free((*pp_node));
*pp_node = NULL;
}
void free_node_and_children(myStruct **pp_node)
{
int iChild;
if (pp_node == NULL || *pp_node == NULL)
return;
for (iChild = 0; iChild < (*pp_node)->size; iChild++)
{
myStruct *p_child = get_child_node((*pp_node), iChild);
if (p_child != NULL)
free_node_and_children(&p_child);
set_child_node((*pp_node), iChild, NULL);
}
free_node(pp_node);
}
Update
A flexible array, under the C99 standard syntax, is a variable-length array that appears at the tail of a structure and whose actual length is set at run time. It looks like this in memory:
Assuming your compiler supports this syntax (not all do), you declare it like this:
struct myStruct
{
Type array_of_type[]; /* AT THE END OF THE STRUCT ONLY */
};
And the code for "myStruct" becomes:
typedef struct myStruct myStruct;
struct myStruct
{
int size;
char *name;
myStruct *array[];
};
myStruct *allocate_node(char *name, int size)
{
myStruct *p_node;
if (size < 0)
size = 0;
p_node = calloc(1, sizeof(myStruct) + size * sizeof(myStruct *));
p_node->name = name;
p_node->size = size;
return p_node;
}
myStruct *get_child_node(myStruct *p_node, int index)
{
if (index < 0 || index >= p_node->size)
return NULL;
return p_node->array[index];
}
int set_child_node(myStruct *p_node, int index, myStruct *p_child)
{
if (index < 0 || index >= p_node->size)
return FALSE;
p_node->array[index] = p_child;
return TRUE;
}
void free_node(myStruct **pp_node)
{
if (pp_node == NULL || *pp_node == NULL)
return;
free((*pp_node));
*pp_node = NULL;
}
void free_node_and_children(myStruct **pp_node)
{
int iChild;
if (pp_node == NULL || *pp_node == NULL)
return;
for (iChild = 0; iChild < (*pp_node)->size; iChild++)
{
myStruct *p_child = get_child_node((*pp_node), iChild);
if (p_child != NULL)
free_node_and_children(&p_child);
set_child_node((*pp_node), iChild, NULL);
}
free_node(pp_node);
}
If you compiler does not, see here for some workarounds.
With flexible arrays, expanding the array would require re-allocating the node itself and fixing all references to it, something not required in the "pointer to array of pointers" design.
The syntax you are using:
myStruct *(*array)[];
should be read as "a pointer to array(s) of unknown size of pointers to structures", rather than
myStruct **array;
which is "a pointer to pointer(s) to structures", or (e.g.):
myStruct *(*array)[4];
which is "a pointer to array(s) of length 4 of pointers.
Your syntax actually produces memory map #3, however accessing the individual elements is a bit more awkward because you have to explicitly get a pointer to the zeroth element of the "array of unknown size", which is (*p_node->array). Thus the functions from #3 are modified as follows:
void expand_node_child_array(myStruct *p_node, int size_to_add)
{
if (size_to_add < 1 || p_node == NULL)
return;
if (p_node->array == NULL)
{
p_node->size = size_to_add;
p_node->array = calloc(1, size_to_add * sizeof(myStruct *));
}
else
{
p_node->array = realloc(p_node->array, (p_node->size + size_to_add) * sizeof(myStruct *));
memset((*p_node->array) + p_node->size * sizeof(myStruct *), 0, size_to_add * sizeof(myStruct *));
p_node->size += size_to_add;
}
}
myStruct *get_child_node(myStruct *p_node, int index)
{
if (index < 0 || index >= p_node->size)
return NULL;
return (*p_node->array)[index];
}
int set_child_node(myStruct *p_node, int index, myStruct *p_child)
{
if (index < 0 || index >= p_node->size)
return FALSE;
(*p_node->array)[index] = p_child;
return TRUE;
}
And finally, the test code for either architecture:
void dump_nodes_recursive(myStruct *p_node, int level)
{
if (p_node == NULL)
{
printf("%*s", 4*level, " ");
printf("NULL\n");
}
else
{
int iChild;
printf("%*s", 4*level, " ");
printf("Node: Name=\"%s\", array size=%d\n", p_node->name, p_node->size);
for (iChild = 0; iChild < p_node->size; iChild++)
{
myStruct *p_child = get_child_node(p_node, iChild);
printf("%*s", 4*level, " ");
printf("Child [%d]:\n", iChild);
dump_nodes_recursive(p_child, level+1);
}
}
}
void dump_nodes(myStruct *p_node)
{
dump_nodes_recursive(p_node, 0);
}
void test_my_struct()
{
myStruct *p_top = allocate_node("top", 4);
myStruct *p_child0 = allocate_node("child0", 1);
myStruct *p_child1 = allocate_node("child1", 5);
myStruct *p_child2 = allocate_node("child2", 0);
myStruct *p_child3 = allocate_node("child3", 0);
myStruct *p_child00 = allocate_node("child00", 0);
set_child_node(p_top, 0, p_child0);
set_child_node(p_top, 1, p_child1);
set_child_node(p_top, 2, p_child2);
set_child_node(p_top, 3, p_child3);
set_child_node(p_child0, 0, p_child00);
dump_nodes(p_top);
free_node_and_children(&p_top);
}
myStruct *(*array)[]; is not a flexible array member, since it's not an array type. It is a pointer which happens to be pointing to an incomplete array type.
The general pattern for flexible array member is:
struct myStruct {
int size;
char *name;
Type array[];
};
where in your case, Type would be defined by typedef MyStruct * Type;. I'm assuming you want an array which will contain 5 pointers. (This is the same effect as having myStruct *array[]; in the struct, of course).
(If you do actually want your struct to contain a single pointer, which points to an array of 5 elements; then flexible array member is not the right technique to use).
Your malloc is correct for this definition I have just given. It allocates a contiguous bloc of memory and you can use array as if it were actually an array of 5 objects, except you can't do sizeof on it to find the size.
Related
How can I free memory allocated in this struct
struct image_t {
char type[3];
int **ptr;
int width;
int height;
};
In the first function I made these allocations:
struct image_t *struktura = (struct image_t *)malloc(sizeof(struct image_t));
int **ptr = (int**)malloc(struktura->height * sizeof(int*));
for (i = 0; i < struktura->height; i++) {
*(ptr + i) = (int *)malloc(struktura->width * sizeof(int));
if (*(ptr + i) == NULL) {
break;
}
}
In the second function I must free allocated memory so I tried to free memory something like this but it does not work
void destroy_image(struct image_t **m) {
if (m != NULL) {
if (*m != NULL) {
if ((*m)->ptr != NULL) {
for (int i = 0; i < (*m)->height; i++) {
free(*((*m)->ptr + i));
}
free((*m)->ptr);
free(*m);
}
}
}
}
I can't change declaration of the destroy function so there must be double pointer on struct.
In order for your destroy function to work properly, all pointers in the pointer array must be either valid or null. Memory returned by malloc() is uninitialized so breaking out of the loop in the allocation function leaves the rest of the pointer array uninitialized, hence should not be passed to free().
Also note the you should test for allocation failure of the structure pointer and the pointer array. Furthermore the width and height members of the newly allocated structure are unintialized: you should use function arguments to initialize them.
The destroy_image function should probably set *m to NULL after deallocation and must free(*m); even if (*m)->ptr is a null pointer.
Here are solutions for this issue:
allocate the array with calloc() (a good idea in all cases) or
set height to the number of successfully allocated pointers.
explicitly set the remaining pointers in the array to NULL
free the allocated block upon allocation failure and return NULL.
Here is a modified version:
#include <stdlib.h>
struct image_t {
char type[3];
int **ptr;
int width;
int height;
};
struct image_t *allocate_image(int width, int height) {
struct image_t *struktura = calloc(1, sizeof(*struktura));
if (struktura == NULL)
return NULL;
// should initialize struktura->type too
struktura->width = width;
struktura->height = height
struktura->ptr = calloc(height, sizeof(*struktura->ptr));
if (struktura->ptr == NULL) {
free(struktura);
return NULL;
}
for (int i = 0; i < height; i++) {
struktura->ptr[i] = calloc(sizeof(*struktura->ptr[i]), width);
if (struktura->ptr[i] == NULL) {
// Iterate downwards on index values of allocated rows
// (i --> 0) is parsed as (i-- > 0)
// this test works on signed and unsigned index types, unlike (--i >= 0)
while (i --> 0) {
free(struktura->ptr[i]);
}
free(struktura->ptr);
free(struktura);
return NULL;
}
}
return struktura;
}
void destroy_image(struct image_t **m) {
if (m != NULL) {
struct image_t *p = *m;
if (p != NULL) {
if (p->ptr != NULL) {
for (int i = 0; i < p->height; i++) {
free(p->ptr[i]);
}
free(p->ptr);
}
free(p);
*m = NULL;
}
}
}
To start with...
Don't cast the value returned by malloc
Don't use *(ptr + i) Use the equivalent but much more readable version, i.e. ptr[i]
Doing that changes your allocation to:
struct image_t *struktura = malloc(sizeof(struct image_t));
int **ptr = malloc(struktura->height * sizeof(int*));
for (i = 0; i < struktura->height; i++) {
ptr[i] = malloc(struktura->width * sizeof(int));
if (ptr[i] == NULL) {
break;
}
}
Here is the first problem... you never assign ptr to anything. In the end of the code block you need to add:
struktura->ptr = ptr;
Another problem is that both struktura->height and struktura->width are uninitialized when used. They must be assigned a value before use.
For freeing the allocated memory: Your current code is too complex. A statement like free(*((*m)->ptr + i)); contains 3 pointer dereferences!!. That's hard to read. I'll recommend that you use a few local variables to simplify the code.
void destroy_image(struct image_t **m) {
if (m == NULL) return;
if (*m == NULL) return;
struct image_t *t = *m;
int **ptr = t->ptr;
if (ptr != NULL)
{
for (int i = 0; i < t->height; i++)
{
free(ptr[i]);
}
free(ptr);
}
free(t);
*m = NULL; // The only reason to pass a double pointer to this
// function is to be able to change *m. I guess
// the prototype authoe wants the function to set
// *m to NULL
}
By using these local variables the code is much easier to read than stuff like free(*((*m)->ptr + i));
And for the break in the allocation code...
It's kind of strange (a bug?) that you you don't check for NULL after the first two malloc and then do it inside the loop. Further it's kind of strange to use break as it will leave the rest of the pointers uninitialized.
Anyway - If you really want that break in the allocation code, you also need to take that into account when freeing memory. Something like:
void destroy_image(struct image_t **m) {
if (m == NULL) return;
if (*m == NULL) return;
struct image_t *t = *m;
int **ptr = t->ptr;
if (ptr != NULL)
{
for (int i = 0; i < t->height && ptr[i] != NULL; i++)
{
free(ptr[i]);
}
free(ptr);
}
free(t);
*m = NULL;
}
This is needlessly complicated and inefficient. Have a look at Correctly allocating multi-dimensional arrays.
You can change the struct like this:
struct image_t {
char type[3];
int* ptr; // placeholder pointer
int width;
int height;
};
Then malloc like this:
struct image_t* s = malloc(sizeof *s);
s->width = width;
s->height = height;
s->ptr = malloc( sizeof(int[width][height]) );
(Remember to check the result of each malloc and stop the program if it returns NULL.)
Then use it like this:
int (*arr)[s->height] = (void*) s->ptr; // convert to a temporary 2D array pointer
...
arr[i][j] = whatever; // this enables 2D array access syntax
And free it like this:
free(s->ptr);
free(s);
In this thread I was suggested to use max_align_t in order to get an address properly aligned for any type, I end up creating this implementation of a dynamic array:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
struct vector {
size_t capacity;
size_t typesize;
size_t size;
max_align_t data[];
};
#define VECTOR(v) ((struct vector *)((unsigned char *)v - offsetof(struct vector, data)))
static void *valloc(size_t typesize, size_t size)
{
struct vector *vector;
vector = calloc(1, sizeof(*vector) + typesize * size);
if (vector == NULL) {
return NULL;
}
vector->typesize = typesize;
vector->capacity = size;
vector->size = 0;
return vector->data;
}
static void vfree(void *data, void (*func)(void *))
{
struct vector *vector = VECTOR(data);
if (func != NULL) {
for (size_t iter = 0; iter < vector->size; iter++) {
func((unsigned char *)vector->data + vector->typesize * iter);
}
}
free(vector);
}
static void *vadd(void *data)
{
struct vector *vector = VECTOR(data);
struct vector *new;
size_t capacity;
if (vector->size >= vector->capacity) {
capacity = vector->capacity * 2;
new = realloc(vector, sizeof(*vector) + vector->typesize * capacity);
if (new == NULL) {
return NULL;
}
new->capacity = capacity;
new->size++;
return new->data;
}
vector->size++;
return vector->data;
}
static size_t vsize(void *data)
{
return VECTOR(data)->size;
}
static void vsort(void *data, int (*comp)(const void *, const void *))
{
struct vector *vector = VECTOR(data);
if (vector->size > 1) {
qsort(vector->data, vector->size, vector->typesize, comp);
}
}
static char *vgetline(FILE *file)
{
char *data = valloc(sizeof(char), 32);
size_t i = 0;
int c;
while (((c = fgetc(file)) != '\n') && (c != EOF)) {
data = vadd(data);
data[i++] = (char)c;
}
data = vadd(data);
data[i] = '\0';
return data;
}
struct data {
int key;
char *value;
};
static int comp_data(const void *pa, const void *pb)
{
const struct data *a = pa;
const struct data *b = pb;
return strcmp(a->value, b->value);
}
static void free_data(void *ptr)
{
struct data *data = ptr;
vfree(data->value, NULL);
}
int main(void)
{
struct data *data;
data = valloc(sizeof(struct data), 1);
if (data == NULL) {
perror("valloc");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < 5; i++) {
data = vadd(data);
if (data == NULL) {
perror("vadd");
exit(EXIT_FAILURE);
}
data[i].value = vgetline(stdin);
data[i].key = (int)vsize(data[i].value);
}
vsort(data, comp_data);
for (size_t i = 0; i < vsize(data); i++) {
printf("%d %s\n", data[i].key, data[i].value);
}
vfree(data, free_data);
return 0;
}
But I'm not sure if I can use max_align_t to store a chunk of bytes:
struct vector {
size_t capacity;
size_t typesize;
size_t size;
max_align_t data[]; // Used to store any array,
// for example an array of 127 chars
};
Does it break the one past the last element of an array rule?
Does it break the one past the last element of an array rule?
No.
Using max_align_t to store a chunk of bytes
OP's issue is not special because it uses a flexible array member.
As a special case, the last element of a structure ... have an incomplete array type; this is called a flexible array member. ... However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) ...
It is the same issue as accessing any allocated memory or array of one type as if it was another type.
The conversion from max_align_t * to char * to void * is well defined when alignment is done right.
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C11dr §6.3.2.3 7
All reviewed accessing in code do not attempt to access outside the "as if" array.
I am trying to find the size of the struct array that I am using to do a sort on it. Not sure how to implement it with the sizeof() function that is normally used in nonstruct arrays.
I am also trying to figure what I am doing wrong when initializing the vehicle struct in the arguments vs the temp struct variable.
error: incompatible types when initializing type ‘struct data *’ using type ‘struct data’
struct data *temp = vehicles[j];
This is the data struct that I am using
struct data{
char *model;
float engineSize;
int cost;
char *color;
};
This is the code that I am currently running for the sort that I am using
void bubbleSortFloats(struct data vehicles[], int check)
{
int i, j, n;
n = sizeof(vehicles)/sizeof(vehicles[0]);
// If check == 1 then ascending sort
if(check == 1){
for (i = 0; i < n-1; i++){
// Last i elements are already in place
for (j = 0; j < n-i-1; j++){
if (vehicles[j].engineSize > vehicles[j+1].engineSize){
struct data temp = vehicles[j];
vehicles[j] = vehicles[j+1];
vehicles[j+1] = temp;
}
}
}
}
// If check == 0 then decending sort
if(check == 0){
for (i = 0; i < n-1; i++){
// Last i elements are already in place
for (j = 0; j < n-i-1; j++){
if (vehicles[j].engineSize < vehicles[j+1].engineSize){
struct data temp = vehicles[j+1];
vehicles[j+1] = vehicles[j];
vehicles[j] = temp;
}
}
}
}
}
This is the update with the readfile function that I am using
struct values * readFile(){
FILE *fp;
int c;
int count = 0;
char *line = NULL;
size_t len = 0;
fp = fopen("hw3.data", "r");
while ((c = fgetc(fp)) != EOF){
if(c == '\n'){
count++;
}
}
if (feof(fp)){
rewind(fp);
struct data *vehicles = malloc((sizeof(struct data))* count);
count = 0;
char *token = NULL;
while (getline(&line, &len, fp)!= -1){
printf("%s", line);
token = strtok(line, " ");
vehicles[count].model = malloc(strlen(token) + 1);
strcpy(vehicles[count].model, token);
token = strtok(NULL, " ");
vehicles[count].engineSize = atof(token);
token = strtok(NULL, " ");
vehicles[count].cost = atoi(token);
token = strtok(NULL, " ");
vehicles[count].color = malloc(strlen(token) + 1);
strcpy(vehicles[count].color, token);
free(line);
line = NULL;
len = 0;
}
struct values *value = malloc(sizeof(struct values));
value.vehicles = vehicles;
value.count = count;
return value;
}
This code
sizeof(vehicles)/sizeof(vehicles[0]);
will only work with true arrays.
In
void bubbleSortFloats(struct data vehicles[], int check);
vehicles look like an array but in fact it is a pointer, this function
definition is the same as
void bubbleSortFloats(struct data *vehicles, int check);
In C you cannot pass true arrays to the functions, they always are passed as
pointers. Even with code like this:
void foo(int arr[10])
{
printf("%lu\n", sizeof arr / sizeof *arr);
}
int main()
{
int arr[10] = { 0 };
foo(arr);
}
I get a warning of my compiler:
a.c: In function ‘foo’:
a.c:6:25: warning: ‘sizeof’ on array function parameter ‘arr’ will return size of ‘int *’ [-Wsizeof-array-argument]
printf("%lu\n", sizeof arr);
^~~
a.c:4:14: note: declared here
void foo(int arr[10])
^~~
and if I execute it, I get 2, because on my system the size of a pointer is 8
and the size of an int is 2. That's why the sizeof arr / sizeof *arr doesn't
work in a function that gets an array passed.
You have to calculate the length of the array before you call
bubbleSortFloats and pass that length to the function. The correct function
would be:
void bubbleSortFloats(struct data *vehicles, size_t len, int check)
{
...
}
We don't see how you created the array, but the function that creates it will
know the size:
void foo(void)
{
struct data vehicles[SOME_LEN];
...
bubbleSortFloats(vehicles, sizeof vehicles / sizeof *vehicles, check);
}
or if you did it with malloc
void foo(void)
{
size_t len = ...;
struct data *vehicles = malloc(len * sizeof *vehicles);
if(vehicles == NULL)
return;
...
bubbleSortFloats(vehicles, len, check);
}
edit
Jeffrey Hennen asked in the comment section:
I made it clear. I am going to want to return a structure and an int count for the size of the array of structures
Like I said in the comments, if you want to return more than one value, you have
essentially two options:
Declare a struct that encapsulates all the returning values and return it
Or pass pointers to the function and let the function update the values
provided by the pointers.
You've chosen way 1, so I guess you have this struct:
struct values {
struct data *vehicles;
size_t count;
};
Then the way you are returning it, is OK. Of course you should check that the
last malloc did not return NULL (you are ignoring that throughout the whole
function, though).
The second option would be:
The easiest way would be:
struct data *readFile(size_t *length) {
if(length == NULL)
return NULL;
...
while (getline(&line, &len, fp)!= -1){
...
};
// NOT NEEDED ANYMORE
//struct values *value = malloc(sizeof(struct values));
//value.vehicles = vehicles;
//value.count = count;
*length = count; // UPDATE the length through the pointer
return vehicles; // return the array
}
and the calling function would do:
void foo(void)
{
size_t count;
struct data *vehicles = readFile(&count);
if(vehicles == NULL)
{
// error
return;
}
do_something_with_the_vehicles(vehicles, count);
free_the_vehicles(vehicles, count);
}
Of course you would have to write a function free_the_vehicles (you can of
course choose another name) that frees all the memory allocated.
struct data *temp = &vehicles[j];
Otherwise it is incompatible as you try to assign the pointer with the structure. You need to assign the address of the structure
When copying a struct, a direct assignment does not work.
Suggest using the function: memcpy().
memcpy( temp, &vehicles[j], sizeof( struct data );
similar considerations exist for all the statements that are trying to copy the 'struct data' instances
I'm having trouble retrieving values from my GArray.
GArray * get_leakddata(struct memory* mem) {
struct leak_data {
char *file;
int line;
char *pointer;
size_t sz;
};
.....
GArray * get_leakddata(struct memory* mem) {
GArray *leak_array = g_array_new(false, false,sizeof(struct leak_data));
g_hash_table_foreach(mem->metadata_hashtable,(GHFunc)get_leakdata_from_metadata, leak_array);
,struct leak_data *,3)->sz);
return leak_array;
}
void get_leakdata_from_metadata(char *key_address, struct metadata_record *metarec, GArray *leak_array) {
if(!get_isallocated(metarec))
return;
static int i=0;
struct leak_data * ld = (struct leak_data *) malloc(sizeof(struct leak_data));
ld->file = get_prev_file(metarec);
ld->line = get_prev_line(metarec);
ld->pointer = key_address;
ld->sz = get_metadata_recordsize(metarec);
printf("get_leakdata_from_metadata sz: %d\n",ld->sz);
g_array_append_val(leak_array,ld);
i++;
printf("get_leakdata_from_metadata 2: %d\n",g_array_index(leak_array,struct leak_data*,i)->sz);
}
prints out:
get_leakdata_from_metadata sz: 12
get_leakdata_from_metadata 2: 1
Eventually I get a seg fault
The array is of struct leak_datas, not pointers to them. So your indexing code:
g_array_index(leak_array,struct leak_data*, i)->sz
is wrong. This is a bit surprising, but GArray really models an array, not a pointer array. There's GPtrArray for that. :) So, the above should be
g_array_index(leak_array, struct leak_data, i).sz
plain C have nice feature - void type pointers, which can be used as pointer to any data type.
But, assume I have following struct:
struct token {
int type;
void *value;
};
where value field may point to char array, or to int, or something else.
So when allocating new instance of this struct, I need:
1) allocate memory for this struct;
2) allocate memory for value and assign it to value field.
My question is - is there ways to declare "array of type void", which can be casted to any another type like void pointer?
All I want is to use "flexible member array" (described in 6.7.2.1 of C99 standard) with ability to casting to any type.
Something like this:
struct token {
int type;
void value[];
};
struct token *p = malloc(sizeof(struct token) + value_size);
memcpy(p->value, val, value_size);
...
char *ptr = token->value;
I suppose declaring token->value as char or int array and casting to needed type later will do this work, but can be very confusing for someone who will read this code later.
Well, sort of, but it's probably not something you want:
struct token {
// your fields
size_t item_size;
size_t length
};
struct token *make_token(/* your arguments */, size_t item_size, size_t length)
{
struct token *t = malloc(sizeof *t + item_size * length);
if(t == NULL) return NULL;
t->item_size = item_size;
t->length = length;
// rest of initialization
}
The following macro can be used to index your data (assuming x is a struct token *):
#define idx(x, i, t) *(t *)(i < x->length ? sizeof(t) == x->item_size ?
(void *)(((char *)x[1]) + x->item_size * i)
: NULL : NULL)
And, if you like, the following macro can wrap your make_token function to make it a little more intuitive (or more hackish, if you think about it that way):
#define make_token(/* args */, t, l) (make_token)(/* args */, sizeof(t), l)
Usage:
struct token *p = make_token(/* args */, int, 5); // allocates space for 5 ints
...
idx(p, 2, int) = 10;
Expanding on AShelly's answer you can do this;
/** A buffer structure containing count entries of the given size. */
typedef struct {
size_t size;
int count;
void *buf;
} buffer_t;
/** Allocate a new buffer_t with "count" entries of "size" size. */
buffer_t *buffer_new(size_t size, int count)
{
buffer_t *p = malloc(offsetof(buffer_t, buf) + count*size);
if (p) {
p->size = size;
p->count = count;
}
return p;
}
Note the use of "offsetof()" instead of "sizeof()" when allocating the memory to avoid wasting the "void *buf;" field size. The type of "buf" doesn't matter much, but using "void *" means it will align the "buf" field in the struct optimally for a pointer, adding padding before it if required. This usually gives better memory alignment for the entries, particularly if they are at least as big as a pointer.
Accessing the entries in the buffer looks like this;
/** Get a pointer to the i'th entry. */
void *buffer_get(buffer_t *t, int i)
{
return &t->buf + i * t->size;
}
Note the extra address-of operator to get the address of the "buf" field as the starting point for the allocated entry memory.
I would probably do this:
struct token {
int type;
void *value;
};
struct token p;
p.value = malloc(value_size);
p.value[0] = something;
p.value[1] = something;
...
edit, actually you have to typecast those p.value[index] = somethings. And/or use a union to not have to typecast.
You can't have an array of 'void' items, but you should be able to do something like what you want, as long as you know value_size when you do the malloc. But it won't be pretty.
struct token {
int type;
void *value;
};
value_size = sizeof(type)*item_count;
struct token *p = malloc(sizeof(struct token) + value_size);
//can't do memcpy: memcpy(p->value, val, value_size);
//do this instead
type* p = (type*)&(p->value);
type* end = p+item_count;
while (p<end) { *p++ = someItem; }
Note that you need an extra address-of operator when you want to get the extra storage.
type *ptr = (type*)&(token->value);
This will 'waste' sizeof(void*) bytes, and the original type of value doesn't really matter, so you may as well use a smaller item. I'd probably typedef char placeholder; and make value that type.
following structure can help you.
struct clib_object_t {
void* raw_data;
size_t size;
};
struct clib_object_t*
new_clib_object(void *inObject, size_t obj_size) {
struct clib_object_t* tmp = (struct clib_object_t*)malloc(sizeof(struct clib_object_t));
if ( ! tmp )
return (struct clib_object_t*)0;
tmp->size = obj_size;
tmp->raw_data = (void*)malloc(obj_size);
if ( !tmp->raw_data ) {
free ( tmp );
return (struct clib_object_t*)0;
}
memcpy ( tmp->raw_data, inObject, obj_size);
return tmp;
}
clib_error
get_raw_clib_object ( struct clib_object_t *inObject, void**elem) {
*elem = (void*)malloc(inObject->size);
if ( ! *elem )
return CLIB_ELEMENT_RETURN_ERROR;
memcpy ( *elem, inObject->raw_data, inObject->size );
return CLIB_ERROR_SUCCESS;
}
More Details : clibutils
Array of type void is not supporting in c/c++.
Example like:
int main() {
void alexa[]; // error: declaration of ‘alexa’ as array of void
return 0;
}
Array of void pointer is supported in c/c++.
Example below:
int main(int argc, char argv*[])
{
void *alexa[100]; // Compiled successfully
return 0;
}