ANSI C - Deallocation of nested BER TLV elements created using dynamic array - c

To build nested TLV elements (e.g., 6F1A840E315041592E5359532E4444463031A5088801025F2D02656E), I'm using the following data structure:
typedef struct Element
{
int16_t nTag; // Tells you if pValue points to a primitive value or constructed one
uint16_t nLength;
void *pValue; // Could be either unsigned char* or TlvElement*
} TlvElement;
How can I implement a function that properly deallocates the memory used by the nested TLV elements?
// Let's build TLV data: 6F04A5020000
TlvElement *pTlvElement = (TlvElement*)malloc(sizeof(TlvElement));
pTlvElement->nTag = 0x6F;
pTlvElement->nLength = 4;
pTlvElement->pValue = malloc(sizeof(TlvElement)); // pValue points to another TLV element
TlvElement *pTlvElementChild = (TlvElement*)pTlvElement->pValue;
pTlvElementChild->nTag = 0xA5;
pTlvElementChild->nLength = 2;
pTlvElementChild->pValue = malloc(2 * sizeof(unsigned char)); // pValue points to a byte array
memset(pTlvElementChild->pValue, 0, 2);
Deallocate(pTlvElement);
//free(pTlvElementChild->pValue);
//free(pTlvElement->pValue);
//free(pTlvElement);

You just deallocate it in the order you gave in the commented lines:
free((TlvElement *)(pTlvElement->pValue)->pValue);
free(pTlvElement->pValue);
free(pTlvElement);
The function free(void *) takes a void *, so the compiler wont complain. The only cast you need is to access the field pValue of the child element.
A word of caution: unless the tag already marks this, you might consider to add keep somewhere that the element does indeed contain a child element.
Assuming the value of ->nTag field can be used for this, you can deallocate the child elements recursively:
void Deallocate(TlvElement *e)
{
if (e->nTag == 0x6f)
Deallocate((TlvElement *)e->pValue);
else
free(e->pValue)
free(e);
}
You might want to take precautions against endless recursion, though.

Related

Is there a way to create a dynamic type assignment in C

I am working to create a set of functions in C that will allow a dynamically growing array. In this example I have create a struct with a variable titled len that stores the active length of the array, another variable titled size that stores the total length of the array assigned during initialization, and another variable titled array which is a pointer to the memory containing the array data. In this example the variable array is initialized in the struct as an integer. Within the function titled int_array I initialize the array and and return the struct. Within that function I call the init_int_array function that does the heavy lifting. In addition, I have another function titled append_int_array that checks the memory allocation and assigns another chunk of memory if necessary and then appends the array with a new index/variable. As you can see, this example is hard coded for an integer, and I will need to repeat these lines of code for every other data type if I want an array to contain that type of data. There has got to be a way to instantiate the struct so that the variable array can be a different data type so that I do not have to repeat all lines of code for every data type, but I am not sure what that method is. Any help would be appreciated. The code is shown below. NOTE: I also have a function to free the array memory after use, but I am omitting it since it is not relevant to the question.
array.h
#ifndef ARRAY_H
#define ARRAY_H
#include<stdlib.h>
#include<stdio.h>
typedef struc
{
int *array;
size_t len;
size_t size;
}Array;
void init_int_array(Array, size_t num_indices);
Array int_array(size_t num_indices);
void append_int_array(Array *array, int item);
#endif /* ARRAY_H */
Array.c
void init_int_array(Array *array, size_t num_indices) {
/* This function initializes the array with a guess for
the total array size (i.e. num_indices)
*/
int *int_pointer;
int_pointer = (int *)malloc(num_indices * sizeof(int));
if (int_pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(int_pointer);
exit(0);
}
else {
array->array = int_pointer;
array->len = 0;
array->size = num_indices;
}
}
Array int_array(size_t num_indices) {
/* This function calls init_int_array to initialize
the array and returns a struct containing the array
*/
Array array;
init_int_array(&array, num_indices);
return array;
}
void append_int_array(Array *array, int item) {
/* This function adds a data point/index to the array
and also doubles the memory allocation if necessary
to incorporate the new data point.
*/
array->len++;
if (array->len == array->size){
array->size *= 2;
int *int_pointer;
int_pointer = (int *)realloc(array->array, array->size * sizeof(int));
if (int_pointer == NULL) {
printf("Unable to reallocate memory, exiting.\n");
free(int_pointer);
exit(0);
}
else {
array->array = int_pointer;
array->array[array->len - 1] = item;
}
}
else
array->array[array->len - 1] = item;
}
A simple solution is rewrite your header like this:
typedef struct
{
void *array; // buffer
size_t len; // amount used
size_t elem; // size of element
size_t size; // size of buffer
} Array;
void init_array(Array *, size_t num_indices, size_t elem);
Array array(size_t num_indices, size_t elem);
void append_array(Array *array, void *item);
The changes to your code would be as follows:
Remove references to int in the name.
Make all inputs be to arbitrary type using void *.
Use array.elem instead of sizeof(int).
The biggest change is that elements to append will be passed by pointer, not by value.
Cast the buffer to whatever type you need to access elements.
Cast the buffer to char * internally to do pointer math on it.
Here is a sample calling sequence you could use:
Array buf = array(10, sizeof(int));
for(int i = 0; i < 3; i++) {
append_array(&buf, &i); // Remember that buf knows sizeof(int)
}
printf("Second element (of %d) is %d\n", buf->len, ((int *)buf->array)[1]);
C is a strongly- and statically-typed language without polymorphism, so in fact no, there is no language-supported form of dynamic typing. Every object you declare, every function parameter, every struct and union member, every array element has a specific type declared in your source code.
Some of the things you can do:
use a typedef or a preprocessor macro to provide indirection of the data type in question. That would allow you to have (lexically) one structure type and one set of support functions that provide for your dynamically-adjustable array to have any one element type of the user's choice, per program.
use preprocessor macros to template the structure type and support functions so that users can get separate versions for any and all element types they want. This might be usefully combined with _Generic selection.
define and use a union type for use as the array's element type, allowing use of any of the union's members' types. With a little more work, this can be made a tagged union, so that objects of different types in the same array could be supported. The cost, however, is wasted space and worse memory efficiency when you use members having smaller types.
use void * or maybe uintmax_t or unsigned char[some_largish_number] as the element type, and implement conversions to and from that type. This has some of the disadvantages of the union alternative, plus some complications surrounding the needed conversions. Also, there is no type that can be guaranteed large enough to accommodate all other data types. Nor even all built-in data types, though this is a more realistic goal.
use void as the formal element type (possible only with dynamic allocation and pointers, not with an array-style declaration). Add a separate member that recoirds the actual size of the elements. Implement wrappers / conversions that support use of that underlying structure in conjunction with various complete data types. This is described in more detail in another answer.

How to copy structures that involve pointers in C?

I have a vector type defined as follows:
typedef struct vector {
void **items;
unsigned int capacity;
unsigned int size;
} vector_st;
typedef vector_st *vector_t;
And I allocate and free it as follows:
vector_t vector_init(unsigned int capacity)
{
vector_t v = (vector_t)calloc(1, sizeof(vector_st));
v->capacity = capacity;
v->size = 0;
v->items = malloc(sizeof(void *) * v->capacity);
return v;
}
void vector_free(vector_t v)
{
if (v) {
free(v->items);
v->capacity = 0;
v->size = 0;
free(v);
v = NULL;
}
}
Now, the point is that I want to copy one vector to another one, meaning including all its content. So, I tried to define a function like this:
void vector_copy(vector_t to, vector_t from)
{
memcpy(to, from, sizeof(vector_st));
}
But, this does not seem to work quite right, as when I do something like this:
vector_t vec = vector_init(3);
vector_add(vec, 1);
vector_add(vec, 2);
vector_add(vec, 3);
unsigned int i;
for (i = 0; i < vec->size; i++) {
printf("%d\n", (int)vector_get(vec, i));
}
vector_t copied = vector_init(3);
vector_copy(copied, vec);
vector_free(vec);
for (i = 0; i < copied->size; i++) {
printf("%d\n", (int)vector_get(copied, i));
}
For the first vector it correctly prints 1 2 3 but for the second one it prints 0 2 3. So, basically I believe it just copies maybe the memory addresses and not the actual content, as when I free the first vector the first element is set to 0. Any ideas how to copy this structure in my case?
EDIT:
void vector_resize(vector_t v, unsigned int capacity)
{
void **items = realloc(v->items, sizeof(void *) * capacity);
if (items) {
v->items = items;
v->capacity = capacity;
}
}
void vector_add(vector_t v, void *item)
{
if (v->capacity == v->size) {
vector_resize(v, v->capacity * 2);
}
v->items[v->size++] = item;
}
Now, the point is that I want to copy one vector to another one, meaning including all its content.
What you seem to want to perform is called a "deep copy". That means copying not just the data, but any additional pointed-to data, recursively. You have judged correctly that memcpy() of the structure itself does not do this; the vector elements are pointed to by pointers in the structure, but they themselves are elsewhere, and therefore are not copied.
What's worse, you have a fundamental problem here with copying the pointed-to data: your copy function doesn't know how big the pointed-to elements are. Without such knowledge, it is impossible to copy them. Furthermore, if the elements themselves contain pointers, then to perform a true deep copy, you need information about which members those are, and how large are the objects to which they point. Etc.
Basically, then, it is impossible write a generic deep copy (in any language). Performing a deep copy requires information at every level about what you are copying. To give you a bit of a flavor, however, you could copy one level deeper if you could rely on the vector elements being of a consistent size that is known at call time. That might look something like this:
void vector_copy(vector_t to, vector_t from, size_t element_size) {
// NOTE: robust code would check for memory allocation failures. This code does not.
void **temp_items;
to->capacity = from->capacity;
to->size = from->size;
// evaluates to NULL if allocation fails:
temp_items = realloc(to->items, from->capacity * sizeof(*to->items));
to->items = temp_items;
for (int i = 0; i < from->size; i++) {
to->items[i] = malloc(element_size); // evaluates to NULL if allocation fails
memcpy(to->items[i], from->items[i], element_size);
}
}
You could avoid the need to pass the element size by instead making it a member of the vector structure.
Note that this assumes that vector to has been initialized, and that it is not necessary to free the pointers to the individual items, if any, that are currently in it (i.e. the vector does not own these, and is therefore not responsible for managing their memory).
void vector_copy(vector_t to, vector_t from)
{
memcpy(to, from, sizeof(vector_st));
}
This is wrong because the vector owns its items object. So you need to do four things in vector_copy:
1) Free the existing items objects in the destination vector so that it's not leaked.
2) Copy the capacity and size.
3) Allocate a brand new items for the destination vector to own.
4) Copy the source items into the newly-allocated destination items.
If you consider vector_copy to be an initialization function, skip step 1. But in that case, I'd strongly suggest changing the name to vector_init so that it's clear that it creates a new vector.
You're simply trying to access free()d memory. First you're calling free(v->items) in vector_free(), and then you're trying to print its contents as if nothing had happened!
When you copy a vector to another (no matter how) the new vector will hold a reference to old_vector->items, so you cannot just free() it -- C is not a garbage collected language and malloc doesn't reference-count the blocks it's managing.
So, basically I believe it just copies maybe the memory addresses and not the actual content
Yes, because at this line
memcpy(to, from, sizeof(vector_st));
you simply discards whatever memory was allocated for to, so memory held by copied becomes leaked; and after vector_free(vec) copied now holds a dangling reference to an already-freed memory.
To copy vector's contents into another, well, copy it:
memcpy(to->items, from->items, sizeof(void *) * from->size);
(Or less efficient
int i;
for(i = 0; i < from->size; ++i) to->items[i] = from->items[i];
)
Or, better, define a copy-constructor:
vector_t vector_copy(vector_t src);
// this functions allocates a fresh vector on heap;
// set its size and capacity to those of src;
// sets its items to a fresh array on heap of capacity elements;
// copies src's items into that array;
// and returns it

How to append to a pointer array in c

I have an array of pointers to structs and I'm trying to find a way to fill the first NULL pointer in an array with a new pointer to a struct. i.e. I want to add a new element onto the end of an array.
I tried a for loop like this:
struct **structs;
int i;
for(i = 0; i < no_of_pointers; i++) {
if (structs[i] == NULL) {
structs[i] = &struct;
}
}
In theory, this would go through the array and when it finds a null pointer it would initialise it. I realise now that it would initialise all null pointers, not just the first, but when I run it it doesn't even do that. I've tried a while loop with the condition while(structs[i] != NULL) and that just goes on forever, making me think that the issue is with how I'm using NULL.
What is the correct way to add a new element to an array of this kind?
Is there some function like append(structs, struct) that I don't know of?
Thanks!
The length of an array in C is fixed, you cannot change it after you defined an array, which means you cannot add an element to the end of an array. However, unless you defined a constant array, you could assign new values to elements of an array. According to your question description, I believe this is what you want.
Also note that, as other already pointed it out in comments, struct is a keyword of C, therefore
you cannot use it as a type name (as you did in struct **structs)
you also cannot use it as a variable name (as you did in structs[i] = &struct;)
Here is one way to do it:
define an array properly
struct struct_foo **structp;
structp = malloc (no_of_elements * sizeof(*structp));
if (structp == NULL) {
/* error handle */
}
Note, at here the elements of structp is not initialized, you need to initialize them properly. That is what we are going to do in step 2.
do something with structp, maybe initialize all its elements to NULL or some no-NULL value
find the first no-NULL element in structp, and assign it a new value
struct struct_foo foo;
for (i = 0; i < no_of_elements; i++) {
if (structp[i] == NULL) {
structp[i] = &foo;
break;
}
}
Note that this foo also is uninitialized, you may want to initialize it first, or you could initialize it later.
According to man malloc:
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
void *reallocarray(void *ptr, size_t nmemb, size_t size);
...
The reallocarray() function changes the size of the memory block
pointed to by ptr to be large enough for an array of nmemb elements,
each of which is size bytes. It is equivalent to the call
realloc(ptr, nmemb * size);
Try implementing a system like this
struct **structs;
int new_struct() {
static int i = 0; // index of last allocated struct
i++;
struct *structp = malloc(sizeof(struct)); // new structure
// initialize structp here
reallocarray(structs, i, sizeof(struct));
structs[i] = structp;
return i; // use structs[index] to get
}
Then you may invoke new_struct(), which resizes the structs array and appends structp to it. The important part is that
a) create_struct returns the index of the newly created struct, and
b) it stores a static int i, which keeps track of the size of the structs.

A kind of Linked List but Don't understand exactly

I asked this before, but no one answered so revise my questions. I have tried to analyze this codes but it doesn't make sense for me. This time hopefully someone give me an idea or correct my misunderstanding.
char * p pointing to command array is type-casted to CMD_BLOCK * after getting thru a couple of functions.
extern CHGR_CMD command[96]
+---+---+---+---+
(CMD_BLOCK *(char *p)) -> | CHGR_CMD | command[0]
+---+---+---+---+
| CHGR_CMD | command[1]
+---+---+---+---+ ....
| .... | command[95]
+---+---+---+---+
Here is a struct of CMD_BLOCK and union CHGR_CMD
typedef struct cmd_block {
struct cmd_block *next;
short type;
short unused;
CHGR_CMD c; //Union
} CMD_BLOCK;
typedef union chgr_cmd {
NET_HDR n; //struct
CHGR_SC_SETUP su;//struct
CHGR_SC_START st;//struct
CHGR_SC_STOP sp;//struct
....
} CHGR_CMD;
the below variables are used in cmd_init()
#define CMD_OFFSET (sizeof(struct cmd_block *) + 2*sizeof(short))
block_size = sizeOf(CHGR_CMD)
size = 96*sizeOf(CHGR_CMD)
Especially, I don't get the for loop below:
int cmd_init(register char* p, register long size, int block_size)
{
int i;
if((size <= 0) || (block_size <= 0) || (block_size > size))
return(-1);
cmd_out_head = NULL;//extern var
cmd_out_tail = NULL;//extern var
cmd_free_space = NULL;//extern var
block_size += CMD_OFFSET;// turn to be size of CMD_BLOCK
cmd_blocks_free = 0;
cmd_blocks_used = 0;
for(i=0; size >= block_size; size-=block_size, i++, p+=block_size) {
((CMD_BLOCK *)(p))->next = cmd_free_space;
cmd_free_space = (CMD_BLOCK *)(p);
cmd_blocks_free++;
}
cmd_b = NULL;
status_seq_clear();
return(i);
}
for loop iterates until 96 which is size of command array.
p+=block_size keeps adding size of CMD_BLOCK ---> I don't get how this works?. Initially type of array was CHGR_CMD and type-casting to char * then another casting to CMD_BLOCK * then increasing the size of CMD_BLOCKin for-loop??
I am not sure but assumed that type of command array is now turning to be CMD_BLOCK after a couple of type-casting.
Another thing I don't get is this codes:
((CMD_BLOCK *)(p))->next = cmd_free_space;
cmd_free_space = (CMD_BLOCK *)(p);
It doesn't seem like linking together. cmd_free_space seems to point the last element of the array while * p gets increased by the size of CMD_BLOCK.
Regarding the cast from char* to CMD_BLOCK*, It is hard to tell without looking at more code, but most probably the original programmer wanted to give some opacity to the p parameter, that is, maybe he/she didn't want to expose the fact that the function is receiving an array of CMD_BLOCK structs.
This opacity is sometimes exercised on certain APIs to try to minimize the chance that a data structure is directly manipulated by the programmer, bypassing the tested API.
See here for more details on opaque pointers.
In order to remove the opacity, a programmer needs to explicitly cast the opaque pointer to the concrete type that is actually being passed. This is what seems that is being done with the line ((CMD_BLOCK *)(p))->next = cmd_free_space;
As to what the for block is doing, it is actually building a reversed linked list from an array of contiguous CMD_BLOCK structures. The first node's next pointer is initialized to NULL, becoming the tail of the linked list, the second node's next pointer is pointed to the first node and so forth, until the last block becomes the head of the list and seems to be accessible through the cmd_free_space variable as you point out.
** EDIT **
To better illustrate how the list is built, I'll try to step through the first two iterations.
iteration 1
State at the beginning of the iteration:
cmd_free_space is NULL;
p is pointing to the first element of the array.
Execution:
p->next = cmd_free_space; p->next becomes NULL;
cmd_free_space = p; cmd_free_space is pointing to the first element of the array
p += block_size; p is now pointing to the second element of the array
iteration 2
State at the beginning of the iteration:
cmd_free_space is pointing to the first element of the array
p is pointing to the second element of the array.
Execution:
p->next = cmd_free_space; p->next = first element of the array (link is done)
cmd_free_space = p; cmd_free_space is now pointing to the second element of the array
p += block_size; p is now pointing to the third element of the array
and so on...
** END OF EDIT **
I would remove from the for block the i variable, as it is useless (it is neither controlling the number of iterations nor indexing anything).
** EDIT: **
I hadn't noticed that the ´i´ variable is returned from the function, so it most probably has a purpose, outside of the function. The function is actually returning the number of elements that were actually processed in the for loop.
** END OF EDIT **
The fact that blocksize is a variable parameter and not simply sizeof(CMD_BLOCK) may also indicate that the function can initialize a linked list with an array of structs that contain as first member a CMD_BLOCK struct, but that also carry additional data. By adding blocksize to the pointer that is walking the array, the for loop would effectively skip over the extra data.
This initialization of an array into a linked list may seem a strange thing to do, but I would guess that the programmer needed the flexibility of inserting commands in the middle of the list without having to copy/move elements in the original array to make space.

Assigning an address to a struct pointer array member in C

Having considerable trouble with some pointer arithmatic. I think I get the concepts (pointer variables point to a memory address, normal variables point to data) but I believe my problem is with the syntax (*, &, (*), *(), etc.)
What I want to do is build dynamic arrays of a custom struct (i.e. arrays of pointers to heap structs), and my interface provides two methods, "ad_to_obj_array" (which takes the object to add and the array which can be null for empty) and "obj_array_dustbin" (which just takes the array to dispose, also disposing of the contents, the heap objs). The former is rendered below.
The details of the objects are not important (and the struct has been renamed anyway) but my solution to the general problem is below, and I'd be grateful if you can spot the error. The compiler is complaining about an invalid lvalue, where I try and assign the address in the pointer on the RHS to the pointer value in an array of pointers to heap structs:
#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))
obj* add_to_obj_array(obj* new_obj, obj* array)
{
int number_of_elements = 0;
if (array != NULL)
{
number_of_elements = NUM_ELEM(array);
}
obj* new_array = NULL;
/* note: I am expecting sizeof(new_obj) to return the size of an obj*
to go into the array of pointers. */
if ( NULL ==
(new_array = (obj*)malloc((number_of_elements + 1)* sizeof(new_obj))) )
{
/* memory request refused :( */
return NULL;
}
/* copy the old array pointers into the new array's pointer slots: */
int i;
for (i = 0; i < number_of_elements; i++)
{
&(new_array[i]) = &(array[i]);
}
/* add the new item to the end (assign pointer value directly): */
new_array[number_of_elements] = new_obj;
if (number_of_elements > 0)
{
free(&array);
}
return new_array;
}
Now, I have tried the following permutations of the offending line:
&(new_array[i]) = &(array[i]);
*(new_array[i]) = &(array[i]);
new_array[i] = &(array[i]);
and all give a compiler error of one sort or another. I am fairly sure that the right hand side is the address of the ith element of the old array, but how to I assign to the ith element of the new, when the elements of the array are pointers to structs?
EDIT - please note, the macro NUM_ELEM above DOES NOT WORK; it will always return 1. See #Merlyn Morgan-Graham's answer below for why.
Based on your description, you're starting off wrong, so by the time you get to copying things, nothing you can do is likely to work.
Right now, you've defined new_array (and, presumably, array) as a pointer to obj. The result looks like this:
In this case, you have a pointer to a dynamically allocated array of objects. When/if you expand the allocation, you'll need to copy all the objects themselves.
According to your description: "(i.e. arrays of pointers to heap structs)", what you want is an array of pointers. If you want to allocate that array of pointers automatically, your definition would look like:
obj *array[NUMBER];
My guess is that's not what you want though. Presumably, you want to allocate that array dynamically as well. That would look like this:
In this case, new_array and array will each need to be defined as a pointer to pointer to obj. You'd then allocate an array of pointers (i.e., pointers to as many objs as you want) and have each point point at an obj:
obj **new_array;
// allocate an array of pointers with space to point at more items:
new_array = malloc(sizeof(obj *) * new_elements);
// copy the pointers to the current items to the new array:
for (i=0; i<current_elements; i++)
new_array[i] = array[i];
The advantage of this is that when you do the copying, you only copy pointers, not the objects themselves. Especially with large objects, this can save a substantial amount of effort. The tradeoff is that using an element goes through two levels of indirection intead of one, so the reference may be slower (though rarely much slower, especially on a relatively high-performance processor).
As #rerun already pointed out, in either case you probably want to use realloc. In particular, this might be able to expand an allocation "in place", and avoid copying data as often. Of course, that's not guaranteed, but at least you're giving it a chance; if you malloc and copy every time, you eliminate even the possibility of that optimization.
You have two arrays doesn't new_array[i] = array[i] do what you need.
Have you looked at realloc as a possible solution.
Just assign the values across. new_array[i] = array[i].
The problem you may be running into is that, for obj* to actually be an array of pointers, obj must itself be a pointer type:
typedef struct
{
int value1;
} obj_pool;
typedef obj_pool* obj;
int main(int argc, char* argv[])
{
obj_pool pool1;
pool1.value1 = 5;
obj array[] = { &pool1 };
array[0]->value1 = 16;
return 0;
}
Another problem you'll run into once you get this compiling is that sizeof(array) == sizeof(obj*). NUM_ELEM(array) will always return the same value. This means you'll have to pass a size_t array_size parameter to your function.
in your code elements of the array are not pointers on the structure, they are structure objects. elements of the this array obj** array are pointers on the structure obj.
#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))
void add_to_obj_array(obj* new_obj, obj** array)
{
int number_of_elements = 0;
if (array != NULL)
{
number_of_elements = NUM_ELEM(array);
}
// expand array with one more item
array = (obj**)realloc(array, (number_of_elements + 1) * sizeof(new_obj));
if (array == NULL )
{
/* memory request refused :( */
return;
}
// Put new item at the last place on the array
array[number_of_elements] = new_obj;
}
So here we used matrix (pointer on pointers of the obj structure). When we add new element we simply expand existing array for one place and on that place we put new structure object. There is no need to return value because we operate on the pointers of the objects, and all change is done on actual objects, not on their copies.

Resources