How can I dynamically update the array within a struct? - c

So I have this struct
#define MAX 128
typedef struct this_struct {
Type items[MAX];
} *SVar;
Lets say we create something like this
SVar first = malloc(sizeof(struct this_struct));
Now when I push values into the array and it fills to the MAX which is 128, I need to dynamically create a new array but I don't know how since the array is inside.
Here are my current thoughts on how I want to do it:
Create a new SVar names "second" with second->items[MAX *2]
free(first)
How can I go about doing this?

The typical way to do that is make your struct contain three values: first, a pointer to an array of variables, and second a count of the currently allocated array size, and in practice, you will need a third item to track the number of array slots you're actually using.
So, with your struct, it would be something like this:
Type *items;
int item_length; /* Number allocated */
int item_count; /* Number in use */
you initially allocate a "batch" of entries, say 100:
first = malloc(sizeof(this_struct));
first->items = malloc(sizeof(Type) * 100);
first->item_length = 100;
first->item_count = 0;
Then you add items one at a time. Simplistically, it's this:
first->items[first->item_count] = new_item;
first->item_count += 1;
But really you need to make sure each time you're not going to overflow the currently-allocated space, so it's really like this:
if (first->item_count == first->item_length) {
first->item_length += 100;
first->items = realloc(first->items, sizeof(Type) * first->item_length);
}
first->items[first->item_count] = new_item;
first->item_count += 1;
You're basically just using slots one at a time as long as your currently allocated space is large enough. Once you've used all the space you've allocated, realloc will either extend the array in place if there is room in the address space, or it will find and allocate a new larger space and move all the existing data to the new spot (and freeing up the old space).
In practice, you should check the return valueon the malloc and realloc calls.

A usual trick is to do something like this:
typedef struct {
int max_items; /* enough memory allocated for so many items */
...
Whatever_type items[1]; /* must be the last member */
} Dyn_array;
...
int n = 127;
Dyn_array *p = malloc(sizeof(Dyn_array) + n*sizeof(p.items[0]);
p->max_items = n + 1;
...
n = 1023;
p = realloc(p, sizeof(Dyn_array) + n*sizeof(p.items[0]);
p->max_items = n + 1;
and so on. The code using the structure performs out-of-bound reads and writes to the items array, which is declared to store one item only. This is OK, however, since C does not do any bounds checking, and the memory allocation policy must guarantee that there is always enough space available for num_items items.

Related

Program Crashes When Accessing array inside Struct

I'm trying to implement the first part of an autocomplete feature that takes in a string, calculates an index for a particular letter, and then allocates another struct pointer at that index. It also stores possible completions of words in a string array. For some reason, the program crashes when I try to access the string array field, and I can't figure out why. How can I fix this?
Thanks
struct table {
struct table *next[26];
char **complete;
int lastIndex;
int size;
};
static struct table Base={{NULL},NULL,0,0};
void insert(const char *string){
int index=string[0]-'a';
if(Base.next[index]==NULL){
Base.next[index]=(struct table*)malloc(sizeof(struct table));
*Base.next[index]=(struct table){{NULL},NULL,0,0};
}
struct table *pointer=Base.next[index];
if(pointer->lastIndex==pointer->size){ //expand complete array
pointer->complete[pointer->lastIndex] = strdup(string); //program crashes here
pointer->lastIndex=pointer->lastIndex+1;
}
}
The crash in this line
pointer->complete[pointer->lastIndex] = strdup(string);
is because pointer->complete is NULL. In other words, you forgot to allocate memory for complete.
How can I fix this?
You must allocate memory. It seems that you want a dynamic sized array of char pointers. So you'll need to use realloc so that you both extend the allocated memory and preserve previous values.
Something like:
char** tmp = realloc(pointer->complete, (pointer->lastIndex + 1) * sizeof(char*));
if (tmp == NULL)
{
// Out of memory
exit(1);
}
pointer->complete = tmp;
// Then you can do your normal code
pointer->complete[pointer->lastIndex] = strdup(string);
Notice: Though it's possible to use realloc every time you insert a string, it may perform rather bad.
So instead of reallocating memory for every new string, it may be better to reallocate a chunk of memory each time you call realloc. Like:
if (pointer->lastIndex == pointer->size)
{
// Need more memory
// - if it's the first time just start with 10 (or another number)
// - else double the size
pointer->size = (pointer->size != 0) ? 2 * pointer->size : 10;
char** tmp = realloc(pointer->complete, (pointer->size) * sizeof(char*));
if (tmp == NULL)
{
// Out of memory
exit(1);
}
pointer->complete = tmp;
}
Here I decided to double the allocated memory when doing realloc. You can of cause use ant approach you like instead, e.g. always add 10 more instead of doubling.
BTW: The name lastIndex seems poor as it's really a nextIndex variable.
A final word on data structure
Your data structur, i.e. struct table seems a bit strange to me. At base-level, you only use table. At the next level you don't use table but only the other variables.
Seems to me that you should split up the struct into two structs like:
struct StringTable {
char **complete;
int lastIndex;
int size;
};
struct table {
struct StringTable strings[26];
};
That would save you both memory and some of the dynamic memory allocation.
You are assuming that
const char * string
will contain only small case alphabets. Dictionaries also have apostrophes
add that case.

Add item to empty array in C and getting array length

I've taking many attempts at solving this problem but failed every time.
I have an array
char *array[1024] = {};
Now I would like to add an item to the array and would also access the items by numbers
For example:
array[0] would be the first item
array[1] would be the second
array[2] would be the third item
But also I would like to know how many items are in the array so I could use something like
for(int i = 0; i <= totalitemsinarray; i++) {
print(array[i]);
}
You cannot change the size of an array in C. You can however allocate a sufficiently large array and then fill it up with entries. First, declare an array with a sufficient size, say, 1024.
char *array[1024];
Then declare a variable fill that counts the number of used slots in array. Initialize it to 0 as 0 slots are used in the beginning. Then, each time you insert an item, increment fill:
array[fill++] = ...;
...
array[fill++] = ...;
Make sure that you never attempt to insert more than 1024 items into the array, C doesn't check that for you.
For a more flexible approach, use malloc() to allocate memory for the array and then periodically enlarge it with realloc() when it's full. If you increase the array size in exponential steps (say, multiply with Φ = 0.5 + 0.5 √2 &approx; 1.61), this runs in O(1) amortised time per entry inserted.
There is no way to do what you're asking directly with C. One option could be if you knew that only certain values were valid. For example, you have an array of char *s so often people use NULL as a flag/invalid value. In that case you could initialize your array to have all NULLs and use that to know the size of the array:
char *array[1024];
memset(array, 0, sizeof(array));
/* .... */
for (int i = 0; i < sizeof(array)/sizeof(char*); i++) {
if (array[i]) {
printf("%s\n", array[i]);
}
}
char *array[1024] = {};
First, that is an array with 1024 char pointers/strings. Those elements can be 0s or plain garbage. If you don't plan to set them all you may want to nullify the array.
For the matter of storing the values and the count you might want to have a look at structs. For example:
typedef struct elem {
int count;
char *value;
} elem;
Then elem.count would be the number and elem.value would be the value accordingly.
And then initialize them in a for loop.
The only really valid way to approach this, is to dynamically grow the array. Allocate the array on the heap, and manage two counts: 1. the count of currently used elements, and 2. the count of elements for which you currently have memory allocated. Something like this:
//the setup
size_t arrayLength = 0, allocatedSize = 8;
int* array = malloc(sizeof(*array) * allocatedSize);
//grow the array -> first check that we have space to add an element
if(arrayLength == allocatedSize) {
array = realloc(array, allocatedSize *= 2);
assert(array);
}
assert(arrayLength < allocatedSize);
//grow the array -> add an element
array[arrayLength++] = ...;
You see, the realloc() call is not too much hassle, but it will protect you from bugs when the requirements change. My experience is that any fixed limit in the code, as insanely large as it may seem to be, will eventually be exceeded, and miserable failure will result. The only safeguard is to use as much memory as needed everywhere.

how to allocate memory for unknown size struct array in C

I am trying to read a big ticks file in C and save them a struct for every second. In each second, I will have different tickers in this struct. However, my code will get crash if in some second we saw too much high volume of tickers.
For example,
In second 1, it only have 10 tickers.
In second 1000, it is seeing 10000.
My code will allocate the same size of memory for each second so it waste too many memory for quiet second but not big enough for busy second.
Please find my add struct code below,
long int addTickArray(long int TickTime, int maximumOrderSize, struct TickArray*TickArray, long int TickPos) {
int i;
for (i = TickPos; i < maximumOrderSize; i++) {
if (TickArray[i].TickTime == NULL) {
break;
} else if (TickArray[i].TickTime == TickTime) {
return i;
}
}
struct TickArray newTickArray;
newTickArray.Ticker = malloc(4000 * sizeof (char*) *10);
newTickArray.askprice = malloc(4000 * sizeof (float*));
newTickArray.bidprice = malloc(4000 * sizeof (float*));
newTickArray.TickTime = TickTime;
newTickArray.TickTimePos = 0;
TickArray[i] = newTickArray;
return(i);
}
I am not sure is there any smart way to allocate a flexible memory for the struct.
You can create and use List structure to resolve your problem. List structure allow you allocate one element every time you add new element.
Or you can double resizing mechanism to resize your array. you must use two variables: one to store the current size, one to store the max size of array. When the current size larger than the max size, you use "realloc" function to re allocate your array with the new size by the double of current max size
Ex:
if (currentSize+1 > maxSize)
{
maxSize *= 2;
T* newArray = (T*) realloc (currentArray, maxSize * sizeof(T));
}
currentArray[currentSize++] = newElement;
Use realloc to allocate more memory when the initial block has been filled.
struct TickArray {
size_t maxSize;
size_t currSize;
// Declaration of ticker, askprice, bidprice
};
When currSize reaches maxSize:
maxSize = maxSize * 2;
tickData.ticker = realloc(tickData.tickarray, maxSize * ...
I believe there is a design issue in your code: for some reason you read the data (code not included in the question) and allocate memory for that data (addTickArray function) in two different functions. This leads to waste of resources and introduces additional failure conditions.
What you should do is to create a single function which does both - reads the file and allocates memory for new data - at the same time. For example, you could temporarily read new ticks into an array large enough for the worst case, check the actual size of the data and allocate a new TickArray element of exact needed size.

How should I malloc/realloc with a struct that includes an array?

I'm pretty new to c, so if my steps are wrong, please let me know. Let's say that I have something like the following:
struct graphNode{
int val;
graphNode* parent;
int succSize;
int succMaxSize;
graphNode* succ[1];
};
I will create a new node with:
graphNode *n;
n = malloc(sizeof(struct graphNode));
assert(n);
n->val = 1;
n->parent = NULL;
n->succSize = 0;
n->succMaxSize = 1;
Then, if I want to add a successor to the node
if (n->succSize == n->succMaxSize){
n->succ = realloc(n->succ, sizeof(graphNode*) * n->succMaxSize * 2);
n->succMaxSize *= 2;
}
n->succ[succSize] = n2; //n2 is of type graphNode*
succSize++;
Is this correct? Do I need to realloc for the struct as well or is realloc of the array enough? Do I need to malloc for the initial array? Should the initial array size be included in my malloc call for n?
The usual way to define a "stretchy" array member in C is to either specify a size of 0 or no size at all, e.g.:
struct foo {
int stuff;
bar theBars[]; // or theBars[0]
};
With this definition, sizeof(struct foo) will include all the elements other than the array at the end, and you can allocate the right size by saying malloc(sizeof(struct foo) + numberOfBars * sizeof(bar)).
If you need to reallocate it to change the number of bar elements, then you'll use the same formula (but with a new numberOfBars).
To be clear, you can't just realloc part of a struct. You have to realloc the whole thing.
realloc(ptr,size) needs 2 parameters, not 1 as used in realloc(sizeof(graphNode*) * n->succMaxSize * 2)
// Something like ...
graphNode *n;
n->succSize = 0;
n->succMaxSize = 0; // set to 0
n->succ = NULL; // Initialize to NULL
// Then, if OP wants to add a successor to the node
if (n->succSize <= n->succMaxSize){
n->succ = realloc(n->succ, sizeof(graphNode*) * n->succMaxSize * 2);
n->succMaxSize *= 2;
}
n->succ[succSize++] = n2;
As with all memory allocations, check for NULL return. In realloc(), one should save the original value, so if the realloc() fails, the original pointer is not lost.
Usually when you see struct definition where the last field is an array of size 0 or 1 it means the author is going to do some subtle stuff with malloc when the struct is malloced.
For example
struct foo {
int x;
:
:
type a[0];
};
With a malloc like
struct foo *p = malloc(sizeof(*p) + (n * sizeof(type));
What this does is it allocates a contiguous chunk of memory for the struct and the trailing array. In this case the array size is n. So references to the array in this case are:
p->a[i] // where i >= 0 and i < n
One reason for doing this is to save memory.
I'm sure there are better explanations for this on StackOver; it's a very common C idiom.
It's generally not used when the array is dynamic. Rather, it is used when the array size is known at malloc() time. You can use dynamically, of course, but you have to realloc the entire memory chunk, not just the struct or array by itself. To increase the size to 2n you would say
p = realloc(p, sizeof(*p) + (2 * n * sizeof(type)));
Now your array is twice is big as it was, and it's still one chunk of memory.
If you only want a single array, just make succ a single pointer and only use malloc/realloc etc. to allocate memory for the array.
graphNode* succ;
What you are doing is almost certain to break.
I too am new to C, but there's some things that I can see right off the bat. First of all, you can't re-allocate arrays. In c89, they're compile-time fixed-size. In C99 and C11, they can be dynamically allocated, but not reallocated (as far as I'm aware). So for this, you need to allocate a
graphnode *succ;
pointer, and malloc(nodes * sizeof(node)).
graphNode* succ[1];
This creates an array of size one, not an array with a maximum index of one. So, it is the same (almost) functionally as
graphNode* succ;
except that you can't change its size once you've made it.
I think what you want is to make a tree, with a dynamically re-allocable amount of branches. In this case, you only need to reallocate the size of the graphNode* pointer, and then access each element via index as you would an array.

How to know exist element of structure?

i have a simple structure:
typedef struct {
int test;
} struct1_t;
typedef struct {
struct1_t** tests;
} struct2_t;
struct2_t *str
for(i=0;i<1000;i++) {
(str->tests)[i]=(test1_t *) malloc(sizeof(test1_t));
(str->tests)[i]->test = i;
}
How to know exist str->tests)[i] element on not ?
if (str->tests)[i] != NULL
call Segmentation failed :).
Simply put, you can't. There is no way to know the length of an array in C, you have to keep track of it manually as your array changes or grows.
C arrays are really just blocks of memory, so what you really
want to do as add a field to your structs that keeps track of how
much space has been allocated and make sure you initialize
everything to sane values. You also have to be careful when using
pointers of structs containing to pointers to pointers of structs,
since in your example you failed to properly allocate memory for
everything.
Try this:
typedef struct {
int test;
} test_t;
typedef struct {
test_t* tests; /* We only need a regular pointer here */
size_t numtests; /* This is so we know how many tests we allocated */
} mystruct_t;
/* .... Now skip to the actual usage: */
mystruct_t *str;
int i;
str = malloc(sizeof(mystruct_t)); /* Remember to allocate memory for
the container! */
str->numtests = 1000; /* Set our size inside the container and use it! */
/* Now to allocate an array of tests, we only need to allocate
a single chunk of memory whose size is the number of tests
multiplied by the size of each test: */
str->tests = malloc(sizeof(test_t)*str->numtests);
/* Now let's initialize each test: */
for (i=0; i<str->numtests; i++) { /* Notice we use str->numtests again! */
str->tests[i]->test = 1; /* Notice we don't need all the extra
parenthesese. This is due to the operator
precedence of [] and -> */
}
Now when you need to see if a test element exists, you can just see if the
index is within the size of the container:
if (i >= 0 && i < str->numtests) {
str->tests[i]->test = 2; /* This code only runs if the index would exist. */
}
But that means you have to take care to always initialize str->numtests to be
a sane value. For example, with no allocated tests:
mystruct_t *str = malloc(sizeof(mystruct_t));
/* Initialize the container to sane starting values! */
str->tests = NULL;
str->numtests = 0;
And that's how you know if something exists -- you keep track of it inside
the structures you define. That's because C code maps very directly to
assembly language, and C structs and arrays map very directly to bits and bytes
in computer memory, so if you want to maintain meta information like how
many elements are inside your array, you have to make room for that information
and store it yourself.
It is pretty fundamental that you can't do it this way in C. Your struct2_t would need an extra field such as int no_of_tests, which you would update.
In fact to do what your trying to do there, you also need 2 mallocs -
struct2_t str;
str.tests = malloc( 1000 * sizeof(int) );
str.no_of_tests = 1000;
for(i=0;i<1000;i++) {
str.tests[i] = malloc( sizeof(struct1_t) );
str.tests[1]->test = i;
}
There is nothing in the language to do this for you, you need to keep track yourself. A common solution is to make the last pointer in an arbitrary-size array of pointers be a NULL pointer, so you know to stop looping when you hit NULL.
If your compiler supports _msize you can find out the size that you allocated. For example:
if (i < _msize((str->tests)/sizeof(test1_t))
then i is valid and points to an element of the allocated array

Resources