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
Related
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.
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.
If I create a struct in C and want to add them to an array that is not set to a fixed size, how is the array created?
Can one create a tempStruct which is used on every iteration while getting user input and store this in an array, always using the same tempStruct struct in the loop?
How is an array created if the size is unknown as it depends on user input, and how are structs added to this array?
When the size is unknown at compile time, you'll need to allocate the memory on the heap, rather than in the data segment (where global variables are stored) or on the stack (where function parameters and local variables are stored). In C, you can do this by calling functions like malloc.
MyStructType *myArray = (MyStructType *)malloc(numElements * sizeof(MyStructType)
... do something ...
free(myArray)
If you're actully using C++, it's generally better to use new[] and delete[], e.g.
MyStructType *myArray = new MyStructType[numElements]
... do something ...
delete [] myArray
Note that new[] must be paired with delete[]. If you're allocating a single instance, use new and delete (without "[]"). delete[] and delete are not equivalent.
Also, if you're using C++, it's generally easier and safer to use an STL vector.
the C array must be with fixed size this is what we have learned years ago
but memory allocation functions may help you to find a solution
in c++ you can use the operator new
int num=0;
cout<<"please enter the number"<<endl;
cin>>num;
int *x=new int[num];
for(int i=0;i<num;i++)
{
cout<<"enter element "<<(i+1)<<endl;
cin>>x[i];
}
//do your work
and as
Mr Fooz
mentioned delete[] is used to free the memory allocated by new[]
and this is a general example
If you are using the older C89 standard compiler, you cannot use variable length arrays. If you use C99 then you can create variable length array. For clarification: variable-lenght doesnt mean that the array lenght can change during execution. It just means that you can set it during execution instead of fixing a value during compile time.
For eg:
CreateArray(const int numberOfElements)
{
struct MyStruct arrayOfStructs[numberOfElements];
}
This is valid in C99 but not in C89. Check your compiler documentaion.
Yes, you can use a tempStruct during input which you add later to the array.
If the size of the array is unknown, then you are in trouble. You must keep track of the array's size somewhere. Just have an integer variable that you change every time you change your array to keep track of your array's size.
If the size of the struct is not known at compile time it is even more complicated. You either just store Pointers in the array which point to your actual struct elements in memory, or you have to keep track of the sizes of every struct in the array. In the later case you would have to do addressing in the array completely manually calculating a lot. While this is very memory efficient, it is also error prone and extremely hard to debug.
OK. sample to create an array that hold your struct using pointers:
struct MyStruct
{
/* code */
}
main()
{
counter = 0;
struct MyStruct** array = malloc(counter);
// Create new Element
struct MyStruct myElement;
myElement.someData = someValue;
// Add element to array:
array = realloc(array, sizeof(struct MyStruct*) * (counter + 1);
array[counter] = &myElement;
counter++;
// Create yet another new Element
struct MyStruct myElement;
myElement.someData = someOtherValue;
array = realloc(array, sizeof(struct MyStruct*) * (counter + 1);
array[counter] = &myElement;
counter++;
// Now remove the last element
free(array[counter -1]); // may have something more complicated than that, depending on your struct
array = realloc(array, sizeof(struct MyStruct*) * (counter - 1);
counter--;
}
this code is not tested!
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.
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).