How to create a dynamic array that holds static arrays in C? - c

My program parses code, and as it parses code I need to keep track of how many instances of each keywords it goes through every x number of lines (probably every 10 lines or so), from this information I plan on later creating a histogram with gnuplot but that's not important.
So there's 13 keywords, I can easily keep count of them with an array of 0s where each index represents a keyword and whenever I find a keyword I increase it's index by 1. Ok simple
int keywordcount[13]={0};
The thing is that I need to create a new keywordcount every 10 lines, and I don't know how many code lines the file has. So this tells me thatI should have a dynamic array of keywordcount arrays.
How do I declare this dynamic array of arrays in C and how do I add to it keywordcount arrays? I'm still confused by multidimensional arrays in C. I don't know if I should declare it as an array of pointers or what, and I don't know how I would go about assigning it a new keywordcount array which would not disappear when the function that creates keywordcount returns. Let me know if something isn't clear.

You can use malloc() or calloc() to create a dynamic array of static arrays. For example, this defines keywordcount_arr as a pointer to an array of 13 ints (here enough memory is allocated for max_lines such arrays):
size_t max_lines = 10;
int (*keywordcount_arr)[13] = calloc(max_lines, sizeof *keywordcount_arr);
It may make the code a little easier to read and write if a typedef is used here:
typedef int KW_Count[13];
/* ... */
KW_Count *keywordcount_arr = calloc(max_lines, sizeof *keywordcount_arr);
You can index into the allocated memory using 2d array indexing:
for (size_t i = 0; i < 13; i++) {
keywordcount_arr[0][i] = i;
}
Or, if an existing array must be stored in the dynamic array, memcpy() can be used. If the dynamic array needs to grow, realloc() can be used. And realloc() can be used again to trim the dynamic allocation to final size:
max_lines *= 2;
KW_Count *temp = realloc(keywordcount_arr,
sizeof *keywordcount_arr * max_lines);
Here is an example program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_KEYWORDS 13
typedef int KW_Count[NUM_KEYWORDS];
int main(void)
{
size_t max_lines = 10;
size_t num_lines = 0;
KW_Count *keywordcount_arr = calloc(max_lines, sizeof *keywordcount_arr);
if (keywordcount_arr == NULL) {
perror("Allocation failure");
/* Handle error... perhaps: */
exit(EXIT_FAILURE);
}
/* Store keyword counts directly in keywordcount_arr[] */
++num_lines;
for (size_t i = 0; i < NUM_KEYWORDS; i++) {
keywordcount_arr[0][i] = i;
}
/* Or use memcpy() if an existing array must be stored */
++num_lines;
KW_Count keywordcount = { 0, 2, 0, 0, 3, 1, 0, 0, 0, 1, 2, 0, 1 };
memcpy(keywordcount_arr[1],
keywordcount,
sizeof *keywordcount * NUM_KEYWORDS);
/* Use realloc() to grow the dynamic array as needed */
max_lines *= 2;
KW_Count *temp = realloc(keywordcount_arr,
sizeof *keywordcount_arr * max_lines);
if (temp == NULL) {
perror("Unable to reallocate");
/* Handle error */
} else {
keywordcount_arr = temp;
}
/* Use realloc() to trim the dynamic array to final size */
temp = realloc(keywordcount_arr, sizeof *keywordcount_arr * num_lines);
if (temp == NULL) {
perror("Unable to reallocate");
/* Handle error */
} else {
keywordcount_arr = temp;
}
/* Display array contents */
for (size_t i = 0; i < num_lines; i++) {
for (size_t j = 0; j < NUM_KEYWORDS; j++) {
printf("%5d", keywordcount_arr[i][j]);
}
putchar('\n');
}
/* Cleanup */
free(keywordcount_arr);
return 0;
}
Program output:
0 1 2 3 4 5 6 7 8 9 10 11 12
0 2 0 0 3 1 0 0 0 1 2 0 1

Make an assumption of how many keywordcounts will be created. Let's say that you are almost sure that 10 of them will be created.
You can dynamically declare a 2D array, of 10 rows and 13 columns.
Now keywordcount[0] will be the index of the first keywordcount array (which has size 13), and so on.
Now, if in action you see that you need more than 10 keywordcount arrays, you could use realloc() to dynamically increase the size of your 2D array.
PS: A good tip would be to double the size of your 2D array in rows every time you need to increase its size (instead of increasing by one row every time, so that you can avoid rellocations, which can be harm performance in some cases).

Don't touch 2D arrays, arrays of arrays, arrays of pointers, pointers to arrays or any such nonsense.
Wrap your statically-sized array in a struct.
typedef struct
{
int keyword_count[13];
} fragment_info;
Have a dynamic array of fragment_info like you would create any other dynamic array:
fragment_info* infos = malloc(initial_capacity * sizeof(*infos));
....
fragment_info* new_infos = realloc(infos, new_capacity * sizeof(*new_infos));
Now if you want to store additional information about your 10-line fragments, you have a natural place to keep it. Just add more fields to the struct.

Related

Import a matrix of any size in C [duplicate]

How am I supposed to use dynamic memory allocations for arrays?
For example here is the following array in which i read individual words from a .txt file and save them word by word in the array:
Code:
char words[1000][15];
Here 1000 defines the number of words the array can save and each word may comprise of not more than 15 characters.
Now I want that that program should dynamically allocate the memory for the number of words it counts. For example, a .txt file may contain words greater that 1000. Now I want that the program should count the number of words and allocate the memory accordingly.
Since we cannot use a variable in place of [1000], I am completely blank at how to implement my logic. Please help me in this regard.
You use pointers.
Specifically, you use a pointer to an address, and using a standard c library function calls, you ask the operating system to expand the heap to allow you to store what you need to.
Now, it might refuse, which you will need to handle.
The next question becomes - how do you ask for a 2D array? Well, you ask for an array of pointers, and then expand each pointer.
As an example, consider this:
int i = 0;
char** words;
words = malloc((num_words)*sizeof(char*));
if ( words == NULL )
{
/* we have a problem */
printf("Error: out of memory.\n");
return;
}
for ( i=0; i<num_words; i++ )
{
words[i] = malloc((word_size+1)*sizeof(char));
if ( words[i] == NULL )
{
/* problem */
break;
}
}
if ( i != num_words )
{
/* it didn't allocate */
}
This gets you a two-dimensional array, where each element words[i] can have a different size, determinable at run time, just as the number of words is.
You will need to free() all of the resultant memory by looping over the array when you're done with it:
for ( i = 0; i < num_words; i++ )
{
free(words[i]);
}
free(words);
If you don't, you'll create a memory leak.
You could also use calloc. The difference is in calling convention and effect - calloc initialises all the memory to 0 whereas malloc does not.
If you need to resize at runtime, use realloc.
Malloc
Calloc
Realloc
Free
Also, important, watch out for the word_size+1 that I have used. Strings in C are zero-terminated and this takes an extra character which you need to account for. To ensure I remember this, I usually set the size of the variable word_size to whatever the size of the word should be (the length of the string as I expect) and explicitly leave the +1 in the malloc for the zero. Then I know that the allocated buffer can take a string of word_size characters. Not doing this is also fine - I just do it because I like to explicitly account for the zero in an obvious way.
There is also a downside to this approach - I've explicitly seen this as a shipped bug recently. Notice I wrote (word_size+1)*sizeof(type) - imagine however that I had written word_size*sizeof(type)+1. For sizeof(type)=1 these are the same thing but Windows uses wchar_t very frequently - and in this case you'll reserve one byte for your last zero rather than two - and they are zero-terminated elements of type type, not single zero bytes. This means you'll overrun on read and write.
Addendum: do it whichever way you like, just watch out for those zero terminators if you're going to pass the buffer to something that relies on them.
While Ninefingers provided an answer using an array of pointers , you can also use an array of arrays as long as the inner array's size is a constant expression. The code for this is simpler.
char (*words)[15]; // 'words' is pointer to char[15]
words = malloc (num_words * sizeof(char[15]);
// to access character i of word w
words[w][i];
free(words);
If you're working in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_LEN 15
int resizeArray(char (**wordList)[WORD_LEN], size_t *currentSize, size_t extent)
{
int result = 1;
char (*tmp)[WORD_LEN] = realloc(*wordList,
(*currentSize + extent) * sizeof **wordList);
if (tmp)
{
*currentSize += extent;
*wordList = tmp;
}
else
result = 0;
return result;
}
int main(void)
{
char *data[] = {"This", "is", "a", "test",
"of", "the", "Emergency",
"Broadcast", "System", NULL};
size_t i = 0, j;
char (*words)[WORD_LEN] = NULL;
size_t currentSize = 0;
for (i = 0; data[i] != NULL; i++)
{
if (currentSize <= i)
{
if (!resizeArray(&words, &currentSize, 5))
{
fprintf(stderr, "Could not resize words\n");
break;
}
}
strcpy(words[i], data[i]);
}
printf("current array size: %lu\n", (unsigned long) currentSize);
printf("copied %lu words\n", (unsigned long) i);
for (j = 0; j < i; j++)
{
printf("wordlist[%lu] = \"%s\"\n", (unsigned long) j, words[j]);
}
free(words);
return 0;
}
If you intend to go for C++, STL is very useful for something dynamic allocation and is very easy. You can use std::vector ..
In modern C (C99) you have an additional choice, variable length arrays, VLA, such as that:
char myWord[N];
In principle you could also do such a thing in two dimensions, but if your sizes get too big, you may risk a stack overflow. In your case the easiest thing would be to use a pointer to such an array and to use malloc / realloc to resize them:
typedef char Word[wordlen];
size_t m = 100000;
Word* words = malloc(m * sizeof(Word));
/* initialize words[0]... words[m-1] here */
for (size_t i = 0; i < m; ++i) words[i][0] = '\0';
/* array is too small? */
m *= 2;
void *p = realloc(words, m*sizeof(Word));
if (p) words = p;
else {
/* error handling */
}
.
free(words);
This code should work (modulo typos) if wordlen is a constant or a variable, as long as you keep everything inside one function. If you want to place it in a function you should declare your function something like
void myWordFunc(size_t wordlen, size_t m, char words[m][wordlen]);
that is the length parameters must come first to be known for the declaration of words.
If the 15 in your example is variable, use one of the available answers (from Ninefingers or John Boker or Muggen).
If the 1000 is variable, use realloc:
words = malloc(1000 * sizeof(char*));
// ... read 1000 words
if (++num_words > 1000)
{
char** more_words = realloc(words, 2000 * sizeof(char*));
if (more_words) {printf("Too bad");}
else {words = more_words;}
}
In my code above, the constant 2000 is a simplification; you should add another variable capacity to support more than 2000 words:
if (++num_words > capacity)
{
// ... realloc
++capacity; // will reallocate 1000+ words each time; will be very slow
// capacity += 1000; // less reallocations, some memory wasted
// capacity *= 2; // less reallocations but more memory wasted
}
Here is a little information on dynamically allocating 2d arrays:
http://www.eskimo.com/~scs/cclass/int/sx9b.html
char ** words = malloc( 1000 * sizeof(char *));
int i;
for( i = 0 ; i < 1000 ; i++)
*(words+i) = malloc(sizeof(char) * 15);
//....
for( i = 0 ; i < 1000 ; i++)
free(*(words+i));
free(words);

Undefined behavior when deleting an element from dynamic array of structs

I have an n sized array of structs dynamically allocated, and each position of the array is an array too, with different sizes for each position (an array of arrays).
I created a function to delete a given array[index] but I'm facing some undefined behavior, for example:
If the array is of size 3, if I delete array[0],I can't access array[1]. This happens with other combinations of indexes too. The only way it works flawlessly is when I delete from end to start.
Here is the code I have:
Structures:
typedef struct point{
char id[5];
char type[5];
char color[10];
int x;
int y;
} Point;
typedef struct {
char lineID[5];
int nPoints;
Point *pt;
}railData;
typedef struct railway {
railData data;
}railway;
This is how the array was created:
headRail = (railway**)calloc(lineNum,sizeof(railway*));
And each Rail:
headRail[i] = (railway*)calloc(pointsNum,sizeof(railway));
These are the functions to delete a rail:
railway **delRail(railway **headRail, int j)
{
int nPts = 0;
if (!headRail)
{
puts(ERRORS[NULLPOINTER]);
return NULL;
}
// Number of rail points on jth rail
nPts = headRail[j]->data.nPoints;
// Free each rail point from jth rail
for (int i = 0; i < nPts; ++i)
{
free(headRail[j][i].data.pt);
}
// Free allocated memory for jth rail
free(headRail[j]);
return headRail;
}
And this is where I call the previous function:
railway **removeRail(railway **headRail)
{
char userID[20];
int index = 0;
// Quit if no rails
if (!headRail)
{
backToMenu("No rails available!");
return NULL;
}
// Get user input
getString("\nRail ID: ",userID,MINLEN,MAXLEN); // MINLEN = 2 MAXLEN = 4
// get index of the asked rail
getRailIndex(headRail,userID,&index);
if (index != NOTFOUND)
{
headRail = delRail(headRail, index);
// Update number of rails in the array (global var)
NUMOFRAILS--;
backToMenu("Rail deleted!\n");
}
else
backToMenu("Rail not found!");
return headRail;
}
So my question is how can I modify my code so that when position i is eliminated, all other indexes are shifted left and the last position, which would be empty, is discarded (something like realloc but for shrinking)
Is what I'm asking doable without changing the array's structure?
When removing element i, do memmove all the data from i+1 to i to the end of the array and then realloc with the size decremented by 1.
Note that arrays in C do not track their size in any way, so you need to pass the size by an external way.
Your data abstraction is strange. I would expect that headRail[j][0].data.nPoints is used to store the number of points inside the headRail[j][0].data structure, yet there you store the count of headRails in the j row headRail[j][<this count>]. I would advise to rewrite the abstraction, have one "object" for the railway and another for hadling two dimensional arrays of railways with dynamic sizes in all directions.
Like:
railway **delRail(railway **headRail, int j)
{
...
// this is strange, it's equal to
// nPts = headRail[j][0].data.nPoints;
// dunno if you mean that,
// or if [j][0].data.nPoints refers to the size of
// headRail[j][0].data.pt or to the size of the whole array
size_t nPts = headRail[j]->data.nPoints;
for (size_t i = 0; i < nPts; ++i) {
free(headRail[j][i].data.pt);
}
free(headRail[j]);
// note that arrays in C does not know how many elements are there in the array
// so you typically pass that along the arguments, like
// railway **delRail(railway **headRail, size_t railcount, int j);
size_t headRailCount = lineNum; // some external knowledge of the size
memmove(&headRail[j], &headRail[j + 1], (headRailCount - j - 1) * sizeof(*headRail));
void *pnt = realloc(headRail, (headRailCount - 1) * sizeof(*headRail));
if (pnt == NULL) return NULL; // that would be strange
headRail = pnt; // note that the previous headRail is no longer valid
--lineNum; // decrement that object where you store the size of the array
return headRail;
}
What about some encapsulation and more structs instead of 2d array? 2d arrays are really a bit of pain for C, what about:
typedef struct {
// stores a single row of rail datas
struct railData_row_s {
// stores a pointer to an array of rail datas
railData *data;
// stores the count of how many datas of rails are stored here
size_t datacnt;
// stores a pointer to an array of rows of rail datas
} *raildatas;
// stores the size of the pointer of rows of rail datas
size_t raildatascnt;
} railway;
The count of mallocs will stay the same, but thinking about data will get simpler. And each pointer that points to an array of data has it's own size tracking variable. An allocation might look like this:
railway *rail_new(size_t lineNum, size_t pointsNum) {
railway *r = calloc(1, sizeof(*r));
if (!r) { return NULL; }
// allocate the memory for rows of raildata
r->raildatascnt = lineNum;
r->raildatas = calloc(r->raildatascnt, sizeof(*r->raildatas));
if (!t->raildatas) { /* error hadnling */ free(r); abort(); }
// for each row of raildata
for (size_t i = 0; i < r->raildatascnt; ++i) {
struct railData_row_s * const row = &r->raildatas[i];
// allocate the memory for the column of raildata
// hah, looks similar to the above?
row->datacnt = pointsNum;
row->data = calloc(row->datacnt, sizeof(*row->data));
if (!row->data) { /* error ahdnling */ abort(); }
}
return r;
}

Dynamic array Vector in C

● int vectorInsert(Vector * array, int index, Data value);
I am doing
If this can be corrected according to the given statement.
I am calling it using
Vector *vect = initVector();
Data data_array[20];
for(i = 0 ; i < 20 ; i++){
data_array[i].value = (rand() % 20) + 1;
vectorInsert(vect, i, data_array[i]);
}
There are a couple of errors in your code, but the most important one is in your initVector function, you actually need to allocate memory for the vector.
You also need to do the following things:
in initVector return v instead of v->data or &v
in vectorInsert print array->data[index].value instead of array->data[index]
in vectorInsert return 1 on success, add error checking in your allocation and return 0 on memory error.
All of these except the original malloc were warnings returned by the compiler.
First, according to your specifications, max_size should be an unsigned integer, so I changed Vector to reflect this, using size_t. I also changed the related format specifiers from %d to %zu to match this new type.
Your initVector() function needed to allocate memory for a Vector, so that has been added. Furthermore, there was no need to allocate memory for the dynamic array of Data structs here, so v->data is set to NULL. This function should also return the pointer to the newly allocated memory, v, instead of a pointer to the .data field of this Vector, as you originally had.
In the vectorInsert() function, you neglected to check for memory allocation errors, so I added a check after the attempted allocation which returns 0 if there is an error. After inserting the new Data struct, your check to increment .current_size is wrong. First, you need to increment if array->current_size <= index. Next, you need to add one to the .current_size, not set .current_size to one larger than the index value. Also, when printing the inserted value here, you forgot to access the .value field. I think that this may have been due to the confusing name that you used for the Data struct that you passed into vectorInsert(). You call this struct value, so in the previous line we have array->data[index] = value, where you are assigning the struct value to array->data[index]. But in the call to printf() you want to show the value held by the struct value. Choosing better names is always a win! Finally, this function returns 1 on a successful insertion.
I added to your test code to display the contents of vect and vect->data, and also added a Data struct, test_insert, to test insertion into an arbitrary index.
Finally, you need to free memory allocations after all of this, so I added a couple of calls to free().
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int value;
}Data;
/* Specs say that max_size should be an unsigned integer */
typedef struct{
size_t max_size; //initialize to 0
size_t current_size; //initialize to 0
Data *data; // array of integers we're storing
} Vector;
/* Modified function */
Vector * initVector(void){
Vector *v = malloc(sizeof(*v));
v->max_size=0;
v->current_size=0;
v->data = NULL;
return v;
}
int vectorInsert(Vector * array, size_t index, Data value)
{
if(index >= array->max_size)
{
array->max_size = index * 2 + 1;
printf("Inside Vect max_size is : %zu\n", array->max_size);
Data *new_array = malloc(sizeof(Data) * array->max_size);
/* Added check for allocation error */
if (new_array == NULL)
return 0;
if(array->data != NULL)
{
memcpy(new_array, array->data, sizeof(Data)*array->current_size);
free(array->data);
array->data = NULL;
}
array->data = new_array;
}
array->data[index] = value;
printf("Main : %d\n", array->data[index].value);
/* Modified current_size increment logic */
if(array->current_size <= index)
{
array->current_size += 1;
}
/* Successful insertion */
return 1;
}
int main(void)
{
size_t i;
Vector *vect = initVector();
Data data_array[20];
Data test_insert = { -5 }; // to test index insertion
for(i = 0 ; i < 20 ; i++){
data_array[i].value = (rand() % 20) + 1;
vectorInsert(vect, i, data_array[i]);
}
/* Display results */
printf("vect->max_size = %zu\n", vect->max_size);
printf("vect->current_size = %zu\n", vect->current_size);
printf("vect->data contains:\n");
for (i = 0; i < vect->current_size; i++)
printf("%d ", vect->data[i].value);
putchar('\n');
/* Insert test_insert at index 5 */
vectorInsert(vect, 5, test_insert);
/* Display results */
printf("vect->max_size = %zu\n", vect->max_size);
printf("vect->current_size = %zu\n", vect->current_size);
printf("vect->data contains:\n");
for (i = 0; i < vect->current_size; i++)
printf("%d ", vect->data[i].value);
putchar('\n');
/* Free memory allocations */
free(vect->data);
free(vect);
return 0;
}
And here is a sample of the results:
vect->max_size = 31
vect->current_size = 20
vect->data contains:
4 7 18 16 14 16 7 13 10 2 3 8 11 20 4 7 1 7 13 17
vect->max_size = 31
vect->current_size = 20
vect->data contains:
4 7 18 16 14 -5 7 13 10 2 3 8 11 20 4 7 1 7 13 17
Enable all warnings and debug info in your compiler (e.g. compile with gcc -Wall -g). Then it should warn you about
Vector * initVector(){
Vector *v; /// UNINITALIZED
v->max_size=0;
v->current_size=0;
v->data = malloc(sizeof(int)*v->max_size);
return v->data;
// return (&v);
}
So you have an undefined behavior, and that is awfully bad.
(Of course the compiler will give a lot of other warnings, and you should improve your code till you got no warnings at all. Then you should use the gdb debugger)
You might want to read about flexible array members.
Consider perhaps having at least:
Vector* createVector(int maxsize) {
if (maxsize<=0)
{ fprintf(stderr, "bad maxsize=%d\n", maxsize); exit(EXIT_FAILURE); };
Vector* v = malloc(sizeof(Vector));
if (!v) { perror("malloc Vector"); exit(EXIT_FAILURE); };
v->data = malloc(sizeof(Data)*maxsize);
if (!v->data) { perror("malloc data"); exit(EXIT_FAILURE); };
v->max_size = maxsize;
v->current_size = 0;
memset(v->data, 0, sizeof(Data)*maxsize);
return v;
}

Fastest way to remove huge number of elements from an array in C

I have dynamic array that contains thousands of elements or even more, in order not to consume a large size of memory, I can remove unwanted elements from it (i.e elements have been used and no need for them any more) so from the beginning I can allocate a smaller memory size by estimating the maximum required size after removing the elements each time.
I use this way but it takes a very very long time to finish, sometime takes 30 minutes!
int x, y ;
for (x = 0 ; x<number_of_elements_to_remove ; x++){
for (y = 0 ; y<size_of_array; y++ ){
array[y] = array[y+1];
}
}
Is there a faster way than this?
Instead of removing elements one at a time, with two loops making for an O(n2) solution, you can make a single loop, with a single read and a single write index. Go through the array, copying items as you go:
int rd = 0, wr = 0;
while (rd != size_of_array) {
if (keep_element(array[rd])) {
array[wr++] = array[rd];
}
rd++;
}
At the end of the loop wr is the number of elements kept in the array.
as I noticed you want to only delete elements from the start of the array, try this:
int x;
for(x = 0 ; x< size_of_array - number_of_elements_to_remove; x++)
array[x] = array[number_of_elements_to_remove + x];
this way you're using one for loop which reduces the complexity alot
It seems you essentially do
int y;
for (y = 0; y<size_of_array; y++){
array[y] = array[y+numbre_of_elements_to_remove];
}
The above should be faster, but there are still some caveats / problems with your code (e.g., access beyond the end od the array).
Here is the code to defragment the array.
int sparse_to_compact(int*arr, int total, int*is_valid) {
int i = 0;
int last = total - 1;
// trim the last invalid elements
for(; last >= 0 && !is_valid[last]; last--); // trim invalid elements from last
// now we keep swapping the invalid with last valid element
for(i=0; i < last; i++) {
if(is_valid[i])
continue;
arr[i] = arr[last]; // swap invalid with the last valid
last--;
for(; last >= 0 && !is_valid[last]; last--); // trim invalid elements
}
return last+1; // return the compact length of the array
}
I copied the code from this answer.
I think more efficient way is to use a link-list of buckets. And the buckets are managed by bit-string memory manager. It is like the following,
struct elem {
uint32_t index; /* helper to locate it's position in the array */
int x; /* The content/object kept in the array */
}
Suppose, our array content is int and it is encapsulated in a structure named struct elem.
enum {
MAX_BUCKET_SIZE = 1024,
MAX_BITMASK_SIZE = (MAX_BUCKET_SIZE + 63) >> 6,
};
struct bucket {
struct bucket*next; /* link to the next bucket */
uint64_t usage[MAX_BITMASK_SIZE]; /* track memory usage */
struct elem[MAX_BUCKET_SIZE]; /* the array */
};
A bucket is defined as an array of struct elem and usage mask.
struct bucket_list {
struct bucket*head; /* dynamically allocated bucket */
}container;
And a bucket list is a linked list containing all the buckets.
So we need to write memory manager code.
At first we need new bucket to be allocated when needed.
struct bucket*bk = get_empty_bucket(&container);
if(!bk) { /* no empty bucket */
/* allocate a bucket */
struct bucket*bk = (struct bucket*)malloc(sizeof(struct bucket));
assert(bk);
/* cleanup the usage flag */
memset(bk->usage, 0, sizeof(bk->usage));
/* link the bucket */
bk->next = container.head;
container.head = bk;
}
Now as we have the bucket we need to set the value in the array when needed.
for(i = 0; i < MAX_BITMASK_SIZE; i++) {
uint64_t bits = ~bk.usage[i];
if(!bits) continue; /* no space */
/* get the next empty position */
int bit_index = _builtin_ctzl(bits);
int index = (i<<6)+bit_index;
/* set the array value */
bk->elem[index].index = index;
bk->elem[index].x = 34/* my value */;
bk.usage[i] |= 1<<bit_index; /* mark/flag the array element as used */
}
Deleting the array elements is easy as to mark them unused. Now when all the elements in a bucket is unused we can delete the bucket from the link-list.
We can sometimes defragment buckets or optimize them to fit in smaller space. Otherwise when we assign new elements we can select more crowded buckets over less crowded one. When we delete we can swap the element of less crowded one into more crowded one.
It is possible to delete elements of array in efficient way,
int remove_element(int*from, int total, int index) {
if(index != (total-1))
from[index] = from[total-1];
return total; // **DO NOT DECREASE** the total here
}
It is done by swapping the element with the last value.

Create vector char array of strings

I am trying to create an array of c string in C, which simulates a behavior similar to that of vector array in c++. The array doubles its capacity whenever the (currentSize + 1) is equal to (MAX_SIZE). This is how I am doing it:
void addLog(char ** dynamicArray, int* size, int *maxSize, int command){
if (*size < *maxSize){
dynamicArray[*size] = "User selects option 1 from main menu.";
(*size)++;
}
else{
//resizing the array here
int originalSize = *maxSize;
*maxSize = *maxSize * 2;
//copy elements of dynamic array in temporary array
char **tempArray = (char**)malloc(originalSize * sizeof(char*));
for (int i = 0; i < originalSize; ++i){
memcpy(&tempArray[i], &dynamicArray[i], sizeof(dynamicArray[i]));
}
//create new array of max * 2 size
dynamicArray = (char**)malloc(*maxSize * sizeof(char*));
//copy temp to dynamic
for (int i = 0; i < originalSize; ++i){
memcpy(&dynamicArray[i], &tempArray[i], strlen(tempArray[i]));
}
for (int i = 0; i < originalSize; i++) {
free(tempArray[i]); <---- this throws an exception on heap
}
free(tempArray);
//insert new element now
dynamicArray[*size] = "User selects option 1 from main menu.";
(*size)++;
}
}
I believe this is a trivial problem for a deep copy scenario. How to resize dynamic array to 2 * capacity and then free the temporary existing elements?
You could create a reusable implementation yourself by extending a struct.
This is a bit long, but it walks you through the entire process and should have everything you need to know:
http://eddmann.com/posts/implementing-a-dynamic-vector-array-in-c/
The structure will take advantage of a fixed-size array, with a counter invariant that keeps track of how many elements are currently present. If the underlying array becomes exhausted, the addition operation will re-allocate the contents to a larger size, by way of a copy."

Resources