The question is in the title
void deleteLastValue(dynIntArray* t){ //function should responds to unexpected values
if(t->tab == NULL){ //if the array is empty we should return an error
fprintf(stderr,"The array is empty");
exit(1);
}
t->tab[(t->size)-1] = 0; /**I'm not sure what to do here should I free the pointer using free function**/
//t->tab[(t->size)-1] = NULL; is it necessary ?
//free(t->tab[(t->size)-1]);
t->tab = (int*)realloc(t->tab,((t->size)-1)*sizeof(int)); //we reallocate but with the new size
t->size--;//size - 1; but capacity stills the same
}
typedef struct{ //structure of an dynamic array
int * tab; //an array of
unsigned int capacity; // the space in memory
unsigned int size;// size of array
} dynIntArray;
If you can review my code, I had issues with what to do with the last element of the array. And should I do more if I want the program to respond to unexpected inputs to make it work properly. Thank you.
You are awesome!
Apparenty it's not quite clear to you how capacity and size are related.
realloc can be a pretty expensive function that may take quite some time. So if you call realloc each and every time the size changes your code will work, but it might be pretty slow. Therefore the capacity is used.
Roughly it is done like this:
You initialize the dynamic array with a size = 0 and capacity = 100 (or some appropriate value larger than 0).
Now you can add 100 elements to the array without realloc ever being called.
If you add one element more, you add 100 to capacity and you call realloc
Now the capacity is 200 and you can add another 100 elements without realloc being called.
If you want to decrease the size of the dynamic array, you just can decrease size without calling realloc leaving capacity alone.
If the difference between size and capacity becomes larger than some value or maybe if the capacity is larger than twice the size, then you can decrease the capacity and call realloc
There are several strategies about how size and capacity are related and when to increase/decrease capacity.
void deleteLastValue(dynIntArray* t) {
if (t->tab == NULL) {
fprintf(stderr, "The array is empty");
exit(1);
}
t->size--; // that's all you need to do
// now optionally you might want to decrease the capacity
// if the capacity is larger than twice the size
// or based on some other strategy
if (t->capacity > 2 * t->size)
{
t->capacity = t->size;
t->tab = realloc(t->tab, t->capacity);
if (t->tab == NULL) {
fprintf(stderr, "realloc error in deleteLastValue");
exit(1);
}
}
}
Be aware that you still need to check if the array is empty (IOW if size is 0. I leave this as an exercise.
If you want more information, you should show us the other functions.
Review of your function:
void deleteLastValue(dynIntArray* t) {
if (t->tab == NULL) {
fprintf(stderr, "The array is empty");
exit(1);
}
t->tab[(t->size) - 1] = 0; // this is useless, the element is no longer part of the array
// you don't need to overwrite it with 0
// the call to free below is completly wrong, t->tab[(t->size) - 1] is not a pointer but an int
// free(t->tab[(t->size) - 1]);
// this reallocation is correct (except there is no error checking and the (int*) cast is useless)
t->tab = (int*)realloc(t->tab, ((t->size) - 1) * sizeof(int));
t->size--;
// you leave the capacity alone which is maybe what you want
}
As you realloc every time, you only need the size of the array. You can also use a flexible array simplifying the allocation and deallocation.
typedef struct{ //structure of an dynamic array
unsigned int size;// size of array
int tab[]; //an array of
} dynIntArray;
dynIntArray *deleteLastValue(dynIntArray* t)
{
if(t && t -> size)
{
t = realloc(sizeof(*t) + (t -> size - 1) * sizeof(t -> tab[0]));
if(t) t -> size--;
}
return t;
}
Thank y'all! It worked perfectly fine. I submit the answer here for posterity. (For the sake of the exercise we don't need to change the capacity)
void deleteLastValue(dynIntArray* t){
if(t->tab == NULL || t->size == 0){
fprintf(stderr,"The array is empty");
exit(1);
}
t->size--;
}
Related
I'm trying to write a function that uses realloc() to extend the array as pointed to within in instance of a struct, however I can't seem to get it to work.
The relevant part of my code is:
struct data_t {
int data_size;
uint16_t *data;
};
void extend_data(data_t container, uint16_t value) {
// adds an additional uint16_t to the array of DATA, updates its internal
// variables, and initialises the new uint to VALUE.
int len_data = sizeof(*(container->data)) / sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
container->data = realloc(container->data, sizeof(*(container->data))+sizeof(uint16_t));
container->data_size++;
container->data[container->data_size-1] = value;
len_data = sizeof(*(container->data)) / sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
printf("data_size: %d\n", container->data_size);
return;
}
Can anybody see what the problem is with this?
Edit
As R. Sahu points out, container is not a pointer in this function - when you said the code "wasn't working", I assumed you meant that you weren't growing your array, but what you've written here won't even compile.
Are you sure you've copied this code correctly? If so, does "not working" mean you're getting a compile-time error, a run-time error, or just unexpected output?
If you've copied the code as written, then the first thing you need to do is change the function prototype to
void extend_data(data_t *container, uint16_t value) {
and make sure you're passing a pointer to your data_t type, otherwise the update won't be reflected in calling code.
Original
In the line
container->data = realloc(container->data, sizeof(*(container->data))+sizeof(uint16_t));
sizeof(*(container->data)) evaluates to sizeof (uint16_t). container->data is a pointer to, not an array of, uint16_t; sizeof will give you the size of the pointer object, not the number of elements you've allocated. What you want to do is something like the following:
/**
* Don't assign the result of a realloc call back to the original
* pointer - if the call fails, realloc will return NULL and you'll
* lose the reference to your original buffer. Assign the result to
* a temporary, then after making sure the temporary is not NULL,
* assign that back to your original pointer.
*/
uint16_t *tmp = realloc(container-data, sizeof *container->data * (container->data_size + 1) );
if ( tmp )
{
/**
* Only add to container->data and update the value of container->data_size
* if the realloc call succeeded.
*/
container->data = tmp;
container->data[container->data_size++] = value;
}
You don't calculate the new size correctly. Consider this:
typedef struct {
size_t size;
int *data;
} int_array;
#define INT_ARRAY_INIT { 0, NULL}
void int_array_resize(int_array *const array,
const size_t newsize)
{
if (!array) {
fprintf(stderr, "int_array_resize(): NULL int_array.\n");
exit(EXIT_FAILURE);
}
if (!newsize) {
free(array->data);
array->data = 0;
array->size = 0;
} else
if (newsize != array->size) {
void *temp;
temp = realloc(array->data, newsize * sizeof array->data[0]);
if (!temp) {
fprintf(stderr, "int_array_resize(): Out of memory.\n");
exit(EXIT_FAILURE);
}
array->data = temp;
array->size = newsize;
}
}
/* int_array my_array = INT_ARRAY_INIT;
is equivalent to
int_array my_array;
int_array_init(&my_array);
*/
void int_array_init(int_array *const array)
{
if (array) {
array->size = 0;
array->data = NULL;
}
}
void int_array_free(int_array *const array)
{
if (array) {
free(array->data);
array->size = 0;
array->data = NULL;
}
}
The key point is newsize * sizeof array->data[0]. This is the number of chars needed for newsize elements of whatever type array->data[0] has. Both malloc() and realloc() take the size in chars.
If you initialize new structures of that type using int_array my_array = INT_ARRAY_INIT; you can just call int_array_resize() to resize it. (realloc(NULL, size) is equivalent to malloc(size); free(NULL) is safe and does nothing.)
The int_array_init() and int_array_free() are just helper functions to initialize and free such arrays.
Personally, whenever I have dynamically resized arrays, I keep both the allocated size (size) and the size used (used):
typedef struct {
size_t size; /* Number of elements allocated for */
size_t used; /* Number of elements used */
int *data;
} int_array;
#define INT_ARRAY_INIT { 0, 0, NULL }
A function that ensures there are at least need elements that can be added is then particularly useful. To avoid unnecessary reallocations, the function implements a policy that calculates the new size to allocate for, as a balance between amount of memory "wasted" (allocated but not used) and number of potentially slow realloc() calls:
void int_array_need(int_array *const array,
const size_t need)
{
size_t size;
void *data;
if (!array) {
fprintf(stderr, "int_array_need(): NULL int_array.\n");
exit(EXIT_FAILURE);
}
/* Large enough already? */
if (array->size >= array->used + need)
return;
/* Start with the minimum size. */
size = array->used + need;
/* Apply growth/reallocation policy. This is mine. */
if (size < 256)
size = (size | 15) + 1;
else
if (size < 2097152)
size = (3 * size) / 2;
else
size = (size | 1048575) + 1048577 - 8;
/* TODO: Verify (size * sizeof array->data[0]) does not overflow. */
data = realloc(array->data, size * sizeof array->data[0]);
if (!data) {
/* Fallback: Try minimum allocation. */
size = array->used + need;
data = realloc(array->data, size * sizeof array->data[0]);
}
if (!data) {
fprintf(stderr, "int_array_need(): Out of memory.\n");
exit(EXIT_FAILURE);
}
array->data = data;
array->size = size;
}
There are many opinions on what kind of reallocation policy you should use, but it really depends on the use case.
There are three things in the balance: number of realloc() calls, as they might be "slow"; memory fragmentation if different arrays are grown requiring many realloc() calls; and amount of memory allocated but not used.
My policy above tries to do many things at once. For small allocations (up to 256 elements), it rounds the size up to the next multiple of 16. That is my attempt at a good balance between memory used for small arrays, and not very many realloc() calls.
For larger allocations, 50% is added to the size. This reduces the number of realloc() calls, while keeping the allocated but unused/unneeded memory below 50%.
For really large allocations, when you have 221 elements or more, the size is rounded up to the next multiple of 220, less a few elements. This caps the number of allocated but unused elements to about 221, or two million elements.
(Why less a few elements? Because it does not harm on any systems, and on certain systems it may help a lot. Some systems, including x86-64 (64-bit Intel/AMD) on certain operating systems and configurations, support large ("huge") pages that can be more efficient in some ways than normal pages. If they are used to satisfy an allocation, I want to avoid the case where an extra large page is allocated just to cater for the few bytes the C library needs internally for the allocation metadata.)
It appears you aren't using sizeof correctly. In your struct you've defined a uint16_t pointer, not an array. The size of the uint16_t* data type is the size of a pointer on your system. You need to store the size of the allocated memory along with the pointer if you want to be able to accurately resize it. It appears you already have a field for this with data_size. Your example might be able to be fixed as,
// I was unsure of the typedef-ing happening with data_t so I made it more explicit in this example
typedef struct {
int data_size;
uint16_t* data;
} data_t;
void extend_data(data_t* container, uint16_t value) {
// adds an additional uint16_t to the array of DATA, updates its internal
// variables, and initialises the new uint to VALUE.
// CURRENT LENGTH OF DATA
int len_data = container->data_size * sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
uint16_t* tmp = realloc(container->data, (container->data_size + 1) * sizeof(uint16_t));
if (tmp) {
// realloc could fail and return false.
// If this is not handled it could overwrite the pointer in `container` and cause a memory leak
container->data = tmp;
container->data_size++;
container->data[container->data_size-1] = value;
} else {
// Handle allocation failure
}
len_data = container->data_size * sizeof(uint16_t);
printf("LENGTH OF DATA: %d\n", len_data);
printf("data_size: %d\n", container->data_size);
return;
}
void extend_data(data_t container, ...
In your function container is not the pointer but the struct itself passed by the value so you cant use the -> operator.
The realloced memory will be lost as you work on the local copy of the passed strucure and it will be lost on the function return.
sizeof(*(container.data)) / sizeof(uint16_t)
it will be always 1 as the *(uint16_t *) / sizeof(uint16_t) is always one.
Why: data member is pointer to the uint16_t. *data has the type of uint16_t
sizeof is calculated during the compilation not the runtime and it does not return the ammount of memory allocated by the malloc.
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.
On RHEL6, I'm facing a strange problem with realloc(). At some point in the program, realloc() returns NULL (the old pointer has an address and there's plently of memory available). What's being allocated is 200 structure elements (structure below). For some reason, when I do a realloc() instead, it works, but I then have to assign the old pointer to the new one. Below is a simplified version of my code.
This is perhaps a server tuning issue more than a programming one. What is your opinion?
Thanks.
//hearder file
typedef struct { /* Variable Node Detail Record */
long next;
long mask;
char *value;
// more stuff...
} NODETEST;
extern NODETEST *oldNodes;
extern NODETEST *newNodes;
//program
#define MAXSIZE 200
// do some stuff with oldNodes....
int alloc_nodes (void)
{
// Allocate or grow the table
oldNodes = (NODETEST *) malloc(MAXSIZE * sizeof(NODETEST));
if( oldNodes == NULL ) {
//handle exception...
exit(1);
}
//oldNodes = (NODETEST *) realloc(oldNodes,MAXSIZE * sizeof(NODETEST)); // *** FAILS
newNodes = (NODETEST *) realloc(oldNodes,MAXSIZE * sizeof(NODETEST)); // *** WORKS
if( newNodes == NULL ){
printf("errno=%d\n", errno );
}else{
oldNodes = newNodes; }
}
Your first call malloc with a size S and then realloc with the same size S. This is wrong: you have to pass to realloc the new wanted size (independently of the current size - it is not an increment). Here, there is a big chance realloc returns exactly the same pointer it received. BTW it is not clear why you want to do with a malloc immediately followed by a realloc. Gives us more detail.
If you want a dynamic table whose size auto-adjusts, you need to allocate an initial size storing its size in a variable (e.g. alloc_size) and keep the current number of occupied elements in another variable (e.g. n_elem) . When you add an element you increment this number. When the table is full reallocate it. Here is a sketch
NODETEST *newNodes = NULL;
int allocated_elem = 0;
int n_elem = 0;
#define ALLOC_INCR 200
then at each addition:
if (n_elem >= alloc_size) { // the first time realloc is as malloc since nodes == NULL
alloc_size += ALLOC_INCR;
nodes = (NODETEST *) realloc(nodes, alloc_size * sizeof(NODETEST));
if (nodes == NULL) {
//handle exception...
exit(1);
}
}
// add your element at nodes[n_elem]
n_elem++;
Recall that realloc acts like malloc when the received pointer is NULL (case of the first call). Thus it allocates the initial table. Subsequent calls reallocate it by adjusting the size with a constant increment (here 200). Some other schemes are possible for the enlargement of the table, for instance you can multiply the size by a factor (e.g. 2) starting from 32:
if (n_elem >= alloc_size) { // the first time realloc is as malloc since nodes == NULL
alloc_size = (alloc_size == 0) ? 32 : alloc_size * 2;
Regarind the FAIL and WORKS comments: it is clear that if you assign oldNodes (in the FAIL code) then newNodes is not assigned and keeps its initial value which is zero (NULL) since it is declared as a global variable and not initialized (well I suppose, it is extern here). Thus the test if (newNodes == NULL) will probably fail.
I need an array of strings in which the length of the array is not known at compile time. what I've done is:
char **words;
words = malloc(capacity * sizeof(char *));
char nextword[MAX_LEN + 1];
while (true) {
if (num_entries == capacity) {
capacity += 5;
realloc(words, (sizeof(char *) * capacity));
}
printf("\nEnter a word: ");
fgets (nextword, MAX_LEN, stdin);
remove_newline(nextword);
if (strlen(nextword) == 0) break;
words[num_entries] = malloc(strlen(nextword + 1));
if (words[num_entries] == NULL) {
printf("\nout of space\n");
break;
}
strcpy(words[num_entries], nextword);
num_entries++;
this seems to work to expand the size once, except that the first element after the expansion has become NULL for some reason. The second time realloc is executed I get an error:
"invalid next size".
realloc is not guaranteed to give you back the same chunk of memory, because the block that was originally allocated from the heap may not have enough space to accommodate your new requested size. In this case you will get back a new block of memory, with your old data copied to it.
You need to capture the returned value on each loop and use it to check for the data you expect, and also check for it being 0 (if the realloc cannot be done).
words = realloc(words,..)
is an antipattern - avoid this since your old memory can get lost if the realloc fails.
Your code is almost there, just need a few modifications. An important thing to remember is that realloc does not modify the value that you pass to it, and it is not required to return the pointer to the same chunk of memory that you passed to it. Here is a working example of using realloc. It is rather straightforward, so you should be able to fix your code by simply following the example.
char **more_words = realloc(words, capacity);
if (more_words) {
words = more_words;
} else {
// Do something about realloc failure
}
I need to have an array of structs in a game I'm making - but I don't want to limit the array to a fixed size. I'm told there is a way to use realloc to make the array bigger when it needs to, but can't find any working examples of this.
Could someone please show me how to do this?
Start off by creating the array:
structName ** sarray = (structName **) malloc(0 * sizeof(structName *));
Always keep track of the size separately:
size_t sarray_len = 0;
To increase or truncate:
sarray = (structName **) realloc(sarray, (sarray_len + offset) * sizeof(structName *));
Then set the size:
sarray_len += offset;
Happy to help and hope that helps.
The realloc function can be used to grow or shrink an array. When the array grows, existing entries retain their value and new entries are uninitialized. This may either grow in-place, or if that was not possible, it may allocate a new block elsewhere in memory (and behind the scenes, copy all the values over to the new block and free the old block).
The most basic form is:
// array initially empty
T *ptr = NULL;
// change the size of the array
ptr = realloc( ptr, new_element_count * sizeof *ptr );
if ( ptr == NULL )
{
exit(EXIT_FAILURE);
}
The multiplication is because realloc expects a number of bytes, but you always want your array to have the right number of elements. Note that this pattern for realloc means you do not have to repeat T anywhere in your code other than the original declaration of ptr.
If you want your program to be able to recover from an allocation failure instead of doing exit then you need to retain the old pointer instead of overwriting it with NULL:
T *new = realloc( ptr, new_element_count * sizeof *ptr );
if ( new == NULL )
{
// do some error handling; it is still safe to keep using
// ptr with the old element count
}
else
{
ptr = new;
}
Note that shrinking an array via realloc may not actually return memory to the operating system; the memory may continue to be owned by your process and available for future calls to malloc or realloc.
From http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/
/* realloc example: rememb-o-matic */
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int input,n;
int count=0;
int * numbers = NULL;
do {
printf ("Enter an integer value (0 to end): ");
scanf ("%d", &input);
count++;
numbers = (int*) realloc (numbers, count * sizeof(int));
if (numbers==NULL)
{ puts ("Error (re)allocating memory"); exit (1); }
numbers[count-1]=input;
} while (input!=0);
printf ("Numbers entered: ");
for (n=0;n<count;n++) printf ("%d ",numbers[n]);
free (numbers);
return 0;
}