How can I make a pool with pointers in C? - c

I'm making my library, and just when I thought understanding the pointers syntax, I just get confused, search on the web and get even more confused.
Basically I want to make a pool, here is what I actually want to do:
the following points must be respected :
when I add an object to the pool, the pointers of the current array to the objects are
added to a new array of pointers + 1 (to contain the new object).
the new array is pointed by "objects" of my foo structure.
the old array is free'ing.
when I call the cleanup function, all the object in the pool are
free'd
How should I define my structure ?
typedef struct {
int n;
(???)objects
} foo;
foo *the_pool;
here's the code to manage my pool :
void myc_pool_init ()
{
the_pool = (???)malloc(sizeof(???));
the_pool->n = 0;
the_pool->objects = NULL;
}
void myc_push_in_pool (void* object)
{
if (object != NULL) {
int i;
(???)new_pointers;
the_pool->n++;
new_pointers = (???)malloc(sizeof(???)*the_pool->n);
for (i = 0; i < the_pool->n - 1; ++i) {
new_pointers[i] = (the_pool->objects)[i]; // that doesn't work (as I'm not sure how to handle it)
}
new_array[i] = object;
free(the_pool->objects);
the_pool->objects = new_array; // that must be wrong
}
}
void myc_pool_cleanup ()
{
int i;
for (i = 0; i < the_pool->n; ++i)
free((the_pool->objects)[i]); // as in myc_push_in_pool, it doesn't work
free(the_pool->objects);
free(the_pool);
}
Note: the type of objects added to the pool are not known in advance, so i should handles all pointers as void
any feedback would be very welcomed.

A straight answer to your question would be: use void *. This type is very powerful as it allows you to put any kind of pointer in your pool. However, it's up to you to do the correct casts when retrieving a void * pointer from your pool.
Your struct would look like this
typedef struct {
int n;
(void **)objects
} foo;
foo *the_pool;
As in, an array of pointers.
Your malloc:
new_pointers = (void **)malloc(sizeof(void *)*the_pool->n);
There is an performance issue here. You could simply allocate an array of a fixed size, and only reallocate if the number of elements exceeds a predefined load factor (= number used/ max size)
Also, instead of allocating a new pointer each time you add something to your pool, you could just use realloc (http://www.cplusplus.com/reference/cstdlib/realloc/)
the_pool->objects = (void **)realloc(the_pool->objects, the_pool->n* sizeof(void*));
Realloc tries to increase the current allocated area, without the need to copy everything. Only if the function cannot increase the allocated area contiguously will it allocate a new area and copy everything.

Firstly, you already answered your "What should the type of foo.objects be?" question: void *objects;, malloc already returns void *. Your struct needs to store the size_t item_size;, too. n should probably also be a size_t.
typedef struct {
size_t item_count;
size_t item_size;
void *objects;
} foo;
foo *the_pool;
You could use a home-grown loop, but I'd consider memcpy to be a more convenient way to copy your old items to your new space, and the new item to it's new space.
Dereferencing a void * is a constraint violation, as is pointer arithmetic on a void *, so new_pointers will need to be a different type. You need a type that points to objects of the right size. You could use an array of the right number of unsigned char, like so:
// new_pointers is a pointer to array of the_pool->item_size unsigned chars.
unsigned char (*new_pointers)[the_pool->item_size] = malloc(the_pool->item_count * sizeof *new_pointers);
// copy the old items
memcpy(new_pointers, the_pool->objects, the_pool->item_count * sizeof *new_pointers);
// copy the new items
memcpy(new_pointers + the_pool->item_count, object, sizeof *new_pointers);
Remember, free() is only for pointers returned by malloc(), and there should be a one-to-one correspondence: Each malloc() should be free()d. Look how you malloc: new_pointers = malloc(sizeof(???)*the_pool->n); ... What makes you think you need a loop (in myc_pool_cleanup) to free each item, when you can free them all in one foul swoop?
You could use realloc, but you otherwise seem to be handling malloc/memcpy/free *in myc_push_in_pool* flawlessly. Lots of people tend to mess up when writing realloc code.

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.

What is the correct way to temporarily cast void* for arithmetic?

I am C novice but been a programmer for some years, so I am trying to learn C by following along Stanford's course from 2008 and doing Assignment 3 on Vectors in C.
It's just a generic array basically, so the data is held inside a struct as a void *. The compiler flag -Wpointer-arith is turned on so I can't do arithmetic (and I understand the reasons why).
The struct around the data must not know what type the data is, so that it is generic for the caller.
To simplify things I am trying out the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
void *data;
int aindex;
int elemSize;
} trial;
void init(trial *vector, int elemSize)
{
vector->aindex = 0;
vector->elemSize = elemSize;
vector->data = malloc(10 * elemSize);
}
void add(trial *vector, const void *elemAddr)
{
if (vector->aindex != 0)
vector->data = (char *)vector->data + vector->elemSize;
vector->aindex++;
memcpy(vector->data, elemAddr, sizeof(int));
}
int main()
{
trial vector;
init(&vector, sizeof(int));
for (int i = 0; i < 8; i++)
{add(&vector, &i);}
vector.data = (char *)vector.data - ( 5 * vector.elemSize);
printf("%d\n", *(int *)vector.data);
printf("%s\n", "done..");
free(vector.data);
return 0;
}
However I get an error at free with free(): invalid pointer. So I ran valgrind on it and received the following:
==21006== Address 0x51f0048 is 8 bytes inside a block of size 40 alloc'd
==21006== at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
==21006== by 0x1087AA: init (pointer_arithm.c:13)
==21006== by 0x108826: main (pointer_arithm.c:29)
At this point my guess is I am either not doing the char* correctly, or maybe using memcpy incorrectly
This happens because you add eight elements to the vector, and then "roll back" the pointer by only five steps before attempting a free. You can easily fix that by using vector->aindex to decide by how much the index is to be unrolled.
The root cause of the problem, however, is that you modify vector->data. You should avoid modifying it in the first place, relying on a temporary pointer inside of your add function instead:
void add(trial *vector, const void *elemAddr, size_t sz) {
char *base = vector->data;
memcpy(base + vector->aindex*sz, elemAddr, sz);
vector->aindex++;
}
Note the use of sz, you need to pass sizeof(int) to it.
Another problem in your code is when you print by casting vector.data to int*. This would probably work, but a better approach would be to write a similar read function to extract the data.
If you don't know the array's data type beforehand, you must assume a certain amount of memory when you first initialize it, for example, 32 bytes or 100 bytes. Then if you run out of memory, you can expand using realloc and copying over your previous data to the new slot. The C++ vector IIRC follows either a x2 or x2.2 ratio to reallocate, not sure.
Next up is your free. There's a big thing you must know here. What if the user were to send you a memory allocated object of their own? For example a char* that they allocated previously? If you simply delete the data member of your vector, that won't be enough. You need to ask for a function pointer in case the data type is something that requires special attention as your input to add.
Lastly you are doing a big mistake at this line here:
if (vector->aindex != 0)
vector->data = (char *)vector->data + vector->elemSize;
You are modifiyng your pointer address!!! Your initial address is lost here! You must never do this. Use a temporary char* to hold your initial data address and manipulate it instead.
Your code is somewhat confusing, there's probably a mis-understanding or two hiding in there.
A few observations:
You can't change a pointer returned by malloc() and then pass the new value to free(). Every value passed to free() must be the exact same value returned by one of the allocation functions.
As you've guessed, the copying is best done by memcpy() and you have to cast to char * for the arithmetic.
The function to append a value could be:
void add(trial *vector, const void *element)
{
memcpy((char *) vector->data + vector->aindex * vector->elemSize, element);
++vector->aindex;
}
Of course this doesn't handle overflowing the vector, since the length is not stored (I didn't want to assume it was hard-coded at 10).
Changing the data value in vector for each object is very odd, and makes things more confusing. Just add the required offset when you need to access the element, that's super-cheap and very straight forward.

When should one use dynamic memory allocation function versus direct variable declaration?

Below is an example of direct variable declaration.
double multiplyByTwo (double input) {
double twice = input * 2.0;
return twice;
}
Below is an example of dynamic memory allocation.
double *multiplyByTwo (double *input) {
double *twice = malloc(sizeof(double));
*twice = *input * 2.0;
return twice;
}
If I had a choice, I will use direct variable declaration all the time because the code looks more readable. When are circumstances when dynamic memory allocation is more suitable?
When are circumstances when dynamic memory allocation is more suitable?
When the allocation size is not known at compile time, we need to use dynamic memory allocation.
Other than the above case, there are some other scenarios, like
If we want to have a data-structure which is re-sizeable at runtime, we need to go for dynamic memory allocation.
The lifetime of dynamically allocated memory remains valid unless it is free()d. At times, it comes handy when returning some address of a variable from a function call, which , otherwise, with an auto variable, would have been out of scope.
Usually the stack size would be moderately limited. If you want to create and use an huge array, it is better to use dynamic memory allocation. This will allocate the memory from heap.
Dynamic memory allocation with malloc places the memory on the heap, so it is not destroyed when leaving the function.
At a later point you would need to manually free the memory.
Direct declaration lands on the stack and is deleted on leaving the function. What happens on the return statement is that a copy of the variable is made before it is destroyed.
Consider this example:
On heap
void createPeople():
struct person *p = makePerson();
addToOffice(p);
addToFamily(p);
Vs. on stack
void createPeople():
struct person p = makePerson();
addToOffice(p);
addToFamily(p);
In the first case only one person is created and added to office and family. Now if the person is deleted, it is invalidated in both office and family and moreover, if his data is changed, it is changed in both, too.
In the second case a copy of the person is created for the office and family. Now it can happen that you change data of the copy in office and the copy in family remains the same.
So basically if you want to give several parties access to the same object, it should be on the stack.
"If I had a choice, I will use direct variable declaration all the time"
As well you should. You don't use heap memory unless you need to. Which obviously begs the question: When do I need dynamic memory?
The stack space is limited, if you need more space, you'll have to allocate it yourself (think big arrays, like struct huge_struct array[10000]). To get an idea of how big the stack is see this page. Note that the actual stack size may differ.
C passes arguments, and returns values by value. If you want to return an array, which decays into a pointer, you'll end up returning a pointer to an array that is out of scope (invalid), resulting in UB. Functions like these should allocate memory and return a pointer to it.
When you need to change the size of something (realloc), or you don't know how much memory you'll need to store something. An array that you've declared on the stack is fixed in size, a pointer to a block of memory can be re-allocated (malloc new block >= current block size + memcpy + free original pointer is basically what realloc does)
When a certain piece of memory needs to remain valid over various function calls. In certain cases globals won't do (think threading). Besides: globals are in almost all cases regarded as bad practice.
Shared libs generally use heap memory. This is because their authors can't assume that their code will have tons of stack space readily available. If you want to write a shared library, you'll probably find yourself writing a lot of memory management code
So, some examples to clarify:
//perfectly fine
double sum(double a, double b)
{
return a + b;
}
//call:
double result = sum(double_a, double_b);
//or to reassign:
double_a = (double_a, double_b);
//valid, but silly
double *sum_into(double *target, double b)
{
if (target == NULL)
target = calloc(1, sizeof *target);
*target = b;
return target;
}
//call
sum_into(&double_a, double_b);//pass pointer to stack var
//or allocate new pointer, set to value double_b
double *double_a = sum_into(NULL, double_b);
//or pass double pointer (heap)
sum_into(ptr_a, double_b);
Returning "arrays"
//Illegal
double[] get_double_values(double *vals, double factor, size_t count)
{
double return_val[count];//VLA if C99
for (int i=0;i<count;++i)
return_val[i] = vals[i] * factor;
return return_val;
}
//valid
double *get_double_values(const double *vals, double factor, size_t count)
{
double *return_val = malloc(count * sizeof *return_val);
if (return_val == NULL)
exit( EXIT_FAILURE );
for (int i=0;i<count;++i)
return_val[i] = vals[i] * factor;
return return_val;
}
Having to resize the object:
double * double_vals = get_double_values(
my_array,
2,
sizeof my_array/ sizeof *my_array
);
//store the current size of double_vals here
size_t current_size = sizeof my_array/ sizeof *my_array;
//some code here
//then:
double_vals = realloc(
double_vals,
current_size + 1
);
if (double_vals == NULL)
exit( EXIT_FAILURE );
double_vals[current_size] = 0.0;
++current_size;
Variables that need to stay in scope for longer:
struct callback_params * some_func( void )
{
struct callback_params *foo = malloc(sizeof *foo);//allocate memory
foo->lib_sum = 0;
call_some_lib_func(foo, callback_func);
}
void callback_func(int lib_param, void *opaque)
{
struct callback_params * foo = (struct callback_params *) opaque;
foo->lib_sum += lib_param;
}
In this scenario, our code is calling some library function that processes something asynchronously. We can pass a callback function that handles the results of the library-stuff. The lib also provides us with a means of passing some data to that callback through a void *opaque.
call_some_lib_func will have a signature along the lines of:
void call_some_lib_func(void *, void (*)(int, void *))
Or in a more readable format:
void call_some_lib_func(void *opaque, void (*callback)(int, void *))
So it's a function, called call_some_lib_func, that takes 2 arguments: a void * called opaque, and a function pointer to a function that returns void, and takes an int and a void * as arguments.
All we need to do is cast the void * to the correct type, and we can manipulate it. Also note that the some_func returns a pointer to the opaque pointer, so we can use it wherever we need to:
int main ( void )
{
struct callback_params *params = some_func();
while (params->lib_sum < 100)
printf("Waiting for something: %d%%\r", params->lib_sum);
puts("Done!");
free(params);//free the memory, we're done with it
//do other stuff
return 0;
}
Dynamic memory allocation is needed when you intend to transport data out of a local scope (for example of a function).
Also, when you can not know in advance how much memory you need (for example user input).
And finally, when you do know the amount of memory needed but it overflows the stack.
Otherwise, you should not use dynamic memory allocation because of readability, runtime overhead and safety.

Dynamically allocate array of file pointers

is it possible to 'dynamically' allocate file pointers in C?
What I mean is this :
FILE **fptr;
fptr = (FILE **)calloc(n, sizeof(FILE*));
where n is an integer value.
I need an array of pointer values, but I don't know how many before I get a user-input, so I can't hard-code it in.
Any help would be wonderful!
You're trying to implement what's sometimes called a flexible array (or flex array), that is, an array that changes size dynamically over the life of the program.) Such an entity doesn't exist among in C's native type system, so you have to implement it yourself. In the following, I'll assume that T is the type of element in the array, since the idea doesn't have anything to do with any specific type of content. (In your case, T is FILE *.)
More or less, you want a struct that looks like this:
struct flexarray {
T *array;
int size;
}
and a family of functions to initialize and manipulate this structure. First, let's look at the basic accessors:
T fa_get(struct flexarray *fa, int i) { return fa->array[i]; }
void fa_set(struct flexarray *fa, int i, T p) { fa->array[i] = p; }
int fa_size(struct flexarray *fa) { return fa->size; }
Note that in the interests of brevity these functions don't do any error checking. In real life, you should add bounds-checking to fa_get and fa_set. These functions assume that the flexarray is already initialized, but don't show how to do that:
void fa_init(struct flexarray *fa) {
fa->array = NULL;
fa->size = 0;
}
Note that this starts out the flexarray as empty. It's common to make such an initializer create an array of a fixed minimum size, but starting at size zero makes sure you exercise your array growth code (shown below) and costs almost nothing in most practical circumstances.
And finally, how do you make a flexarray bigger? It's actually very simple:
void fa_grow(struct flexarray *fa) {
int newsize = (fa->size + 1) * 2;
T *newarray = malloc(newsize * sizeof(T));
if (!newarray) {
// handle error
return;
}
memcpy(newaray, fa->array, fa->size * sizeof(T));
free(fa->array);
fa->array = newarray;
fa->size = newsize;
}
Note that the new elements in the flexarray are uninitialized, so you should arrange to store something to each new index i before fetching from it.
Growing flexarrays by some constant multiplier each time is generally speaking a good idea. If instead you increase it's size by a constant increment, you spend quadratic time copying elements of the array around.
I haven't showed the code to shrink an array, but it's very similar to the growth code,
Any way it's just pointers so you can allocate memory for them
but don't forget to fclose() each file pointer and then free() the memory

Passing a dynamic array in to functions in C

I'm trying to create a function which takes an array as an argument, adds values to it (increasing its size if necessary) and returns the count of items.
So far I have:
int main(int argc, char** argv) {
int mSize = 10;
ent a[mSize];
int n;
n = addValues(a,mSize);
for(i=0;i<n;i++) {
//Print values from a
}
}
int addValues(ent *a, int mSize) {
int size = mSize;
i = 0;
while(....) { //Loop to add items to array
if(i>=size-1) {
size = size*2;
a = realloc(a, (size)*sizeof(ent));
}
//Add to array
i++;
}
return i;
}
This works if mSize is large enough to hold all the potential elements of the array, but if it needs resizing, I get a Segmentation Fault.
I have also tried:
int main(int argc, char** argv) {
...
ent *a;
...
}
int addValues(ent *a, int mSize) {
...
a = calloc(1, sizeof(ent);
//usual loop
...
}
To no avail.
I assume this is because when I call realloc, the copy of 'a' is pointed elsewhere - how is it possible to modify this so that 'a' always points to the same location?
Am I going about this correctly? Are there better ways to deal with dynamic structures in C? Should I be implementing a linked list to deal with these?
The main problem here is that you're trying to use realloc with a stack-allocated array. You have:
ent a[mSize];
That's automatic allocation on the stack. If you wanted to use realloc() on this later, you would create the array on the heap using malloc(), like this:
ent *a = (ent*)malloc(mSize * sizeof(ent));
So that the malloc library (and thus realloc(), etc.) knows about your array. From the looks of this, you may be confusing C99 variable-length arrays with true dynamic arrays, so be sure you understand the difference there before trying to fix this.
Really, though, if you are writing dynamic arrays in C, you should try to use OOP-ish design to encapsulate information about your arrays and hide it from the user. You want to consolidate information (e.g. pointer and size) about your array into a struct and operations (e.g. allocation, adding elements, removing elements, freeing, etc.) into special functions that work with your struct. So you might have:
typedef struct dynarray {
elt *data;
int size;
} dynarray;
And you might define some functions to work with dynarrays:
// malloc a dynarray and its data and returns a pointer to the dynarray
dynarray *dynarray_create();
// add an element to dynarray and adjust its size if necessary
void dynarray_add_elt(dynarray *arr, elt value);
// return a particular element in the dynarray
elt dynarray_get_elt(dynarray *arr, int index);
// free the dynarray and its data.
void dynarray_free(dynarray *arr);
This way the user doesn't have to remember exactly how to allocate things or what size the array is currently. Hope that gets you started.
Try reworking it so a pointer to a pointer to the array is passed in, i.e. ent **a. Then you will be able to update the caller on the new location of the array.
this is a nice reason to use OOP. yes, you can do OOP on C, and it even looks nice if done correctly.
in this simple case you don't need inheritance nor polymorphism, just the encapsulation and methods concepts:
define a structure with a length and a data pointer. maybe an element size.
write getter/setter functions that operate on pointers to that struct.
the 'grow' function modifies the data pointer within the struct, but any struct pointer stays valid.
If you changed the variable declaration in main to be
ent *a = NULL;
the code would work more like you envisioned by not freeing a stack-allocated array. Setting a to NULL works because realloc treats this as if the user called malloc(size). Keep in mind that with this change, the prototype to addValue needs to change to
int addValues(ent **a, int mSize)
and that the code needs to handle the case of realloc failing. For example
while(....) { //Loop to add items to array
tmp = realloc(*a, size*sizeof(ent));
if (tmp) {
*a = tmp;
} else {
// allocation failed. either free *a or keep *a and
// return an error
}
//Add to array
i++;
}
I would expect that most implementations of realloc will internally allocate twice as much memory if the current buffer needs resizing making the original code's
size = size * 2;
unnecessary.
You are passing the array pointer by value. What this means is:
int main(int argc, char** argv) {
...
ent *a; // This...
...
}
int addValues(ent *a, int mSize) {
...
a = calloc(1, sizeof(ent); // ...is not the same as this
//usual loop
...
}
so changing the value of a in the addValues function does not change the value of a in main. To change the value of a in main you need to pass a reference to it to addValues. At the moment, the value of a is being copied and passed to addValues. To pass a reference to a use:
int addValues (int **a, int mSize)
and call it like:
int main(int argc, char** argv) {
...
ent *a; // This...
...
addValues (&a, mSize);
}
In the addValues, access the elements of a like this:
(*a)[element]
and reallocate the array like this:
(*a) = calloc (...);
Xahtep explains how your caller can deal with the fact that realloc() might move the array to a new location. As long as you do this, you should be fine.
realloc() might get expensive if you start working with large arrays. That's when it's time to start thinking of using other data structures -- a linked list, a binary tree, etc.
As stated you should pass pointer to pointer to update the pointer value.
But I would suggest redesign and avoid this technique, in most cases it can and should be avoided. Without knowing what exactly you trying to achieve it's hard to suggest alternative design, but I'm 99% sure that it's doable other way. And as Javier sad - think object oriented and you will always get better code.
Are you really required to use C? This would be a great application of C++'s "std::vector", which is precisely a dynamically-sized array (easily resizeble with a single call you don't have to write and debug yourself).

Resources