stack implementation using malloc in c [BEGINNER] - c

for learning purpose I'm implementing a stack with it's functions in c.
I added some small additional functionality to use malloc the first time and try to understand it properly.
I wrote a function which is initially creating my stack struct. The return value of the function is a new struct with an already allocate memory. What is the best way to handle a malloc exception in a function which return value should be a struct? Maybe should I design the function different? I'm aware that the printf is not doing it's job ;)
My Stack struct:
typedef struct Stack
{
int count;
int capacity;
int *data;
} Stack;
Creating a Stack instance:
Stack create_stack(int initialcapacity)
{
Stack new_stack;
new_stack.count = 0;
new_stack.capacity = initialcapacity;
if (!(new_stack.data = malloc(initialcapacity * sizeof(int))))
printf("not enough memory!");
return new_stack;
}
The function is called with the initial capacity of the stack:
Stack stack = create_stack(10);
A second question came up while I was writing a function to delete the Stack instance.
int delete_stack(Stack *stack)
{
stack->count = 0;
stack->capacity = 0;
free(stack->data);
stack->data = NULL;
return 0;
}
Am I able to remove also the struct instance itself? It feels not complete to just set the values back to 0 and direct int* to NULL.
Last but not least, I have a question to my push function. Also here I added some functionality which allows me to push something on the stack while it is already full:
void push(int value, Stack *stack)
{
if (stack->count == stack->capacity)
{
int *temp = malloc(stack->capacity * sizeof(int));
int i;
for (i = 0; i < stack->count; i++)
temp[i] = stack->data[i];
free(stack->data);
stack->data = NULL;
stack->data = malloc(stack->capacity * 2 * sizeof(int));
for (i; i > -1; i--)
stack->data[i] = temp[i];
free(temp);
temp = NULL;
stack->data[stack->count] = value;
stack->count++;
stack->capacity = stack->capacity * 2;
}
else
{
stack->data[stack->count] = value;
stack->count++;
}
}
Is it necessary to "free" the smaller array and put the pointer to NULL before I allocate a new array double the size?
If there is anything from my code which is unnecessary or not written properly, please let me know, I'm grateful for any hint which makes me better.
Cheeers,
me

I would do it with pointers. That is, your create_stack() would allocate a new Stack struct using malloc, then set the values to the struct and usee malloc again to allocate space for the Stack->data. Like this:
Stack* create_stack(int initialcapacity) {
Stack* new_stack = malloc(sizeof(Stack));
if (new_stack == NULL)
return NULL; // return null to tell the caller that we failed
new_stack->count = 0;
new_stack->capacity = initialcapacity;
new_stack->data = malloc(initialcapacity * sizeof(int))
if (new_stack->data == NULL)
{
free(new_stack);
return NULL;
}
return new_stack;
}
With this, we "handle" a malloc error by returning NULL, so the caller knows we failed.
Now that we have used malloc to allocate the Stack struct, you can (read: MUST) free the space taken by it using free(stack); in delete_stack().
In push(), the temporary array is not needed, that is, you could just right away allocate a bigger array, copy the contents to it from the original stack->data, free stack->data and set it to the newly malloc'd array:
int *temp = malloc(stack->capacity * 2 * sizeof(int));
// TODO: what if malloc fails?
int i;
for (i = 0; i < stack->count; i++)
temp[i] = stack->data[i];
free(stack->data);
stack->data = temp;
stack->data[stack->count] = value;
stack->count++;
stack->capacity = stack->capacity * 2;

Q. What is the best way to handle a malloc exception in a function which return value should be a struct?
There are at least three ways:
1) Instead of returning structure itself, return a pointer to it. This means two mallocs: one is for structure itself and another one is for data field. Returning NULL pointer means that something went wrong during construction.
struct Stack* create_stack(int initialcapacity) {
struct Stack* stack = malloc(sizeof(struct Stack));
...
return stack;
}
2) More flexible way is to pass pointer to already allocated structure. Flexibility comes from idea that calling code controls where to allocate structure: on stack or in dynamic memory. Return value of function may be used solely to notify calling code about errors:
bool create_stack(int initialcapacity, struct Stack* stack) {
...
}
// if calling code wants structure on stack (yeah, "stack" on stack)
struct Stack stack;
if (!create_stack(50, &stack)) {
die();
}
// if calling code wants it in dynamic memory
struct Stack* stack = malloc(sizeof(struct Stack));
if (!stack) {
die();
}
if (!create_stack(50, stack)) {
die();
}
3) If your program is not a 10,000+ LOC production code, easiest way may be to simply print error message and abort program immediately if allocation fails. Usually allocation errors are fatal: you can't recover in any meaningful way if there is not enough memory. You may even create a wrapper function over malloc to automatically catch such errors and exit:
void* my_malloc(size_t count) {
void* ptr = malloc(count);
if (ptr == NULL) {
fprintf(stderr, "Allocation failed");
exit(EXIT_FAILURE);
}
return ptr;
}
Q. Am I able to remove also the struct instance itself?
No, you can't. Because it is allocated on stack (the structure itself, not the data). If you want to delete structure itself, you need to use approach #1 from above.
And, by the way, there is no need to set zeroes and NULLs to fields. It doesn't delete anything. Such approach is used rarely and with only purpose to catch bugs (when calling code first deletes some structure and then tries to use it afterwards).
Q. Is it necessary to "free" the smaller array and put the pointer to NULL before I allocate a new array double the size?
Once again, you don't need to NULLify anything -- it doesn't delete anything. Instead of two mallocs and manual copying use realloc, which will do most of the work for you.

Generally, you should be able to declare a structure, then have an array of say 64 of them, with an integer to say which entry is on the top. Very simple, and no dynamic allocation. But 64 is pretty low, That's because stacks, recursion, and levels of nesting are intimately linked. Usually it should be possible to see that 64 is an insane level of nesting, and no legitimate input will ever even approach it. You then might need a guard to protect from malicious or corrupted input, but that just terminates the program or sub-routine.
If you can't establish a low sanity bound on a stack, it might that you still need one. Either it's a rare case where nesting goes very deep, or it's that you haven't approached the problem in the best way, but a sub-optimal program that still works is better than no program.
So you use the same structure, but the stack is set up with a call to
malloc() and, if it grows out of bounds, regrow with a call to realloc().
You might want to still sanity check it, but now sanity checks are
much higher, a million or so as opposed to 64. You also have to check that
realloc does not fail.
typedef struct
{
int x;
char astring[32];
} ENTRY;
static ENTRY *stack = 0;;
static int top = -1;
static int N = 0;
void push(const ENTRY *e)
{
/* grow logic like this */
ENTRY *temp = realloc(stack, newsize * sizeof(ENTRY));
if(temp)
stack = temp;
else
{
/* reallocation has failed but stack still valid */
free(stack);
N = 0;
top = -1;
/* for the sake of argument do this. We need temp to avoid
a memory leak */
fprintf(stderr, "out of memory\n");
}
/* push here, trivial */
}
int pop(ENTRY *e)
{
/* e is a non-const pointer. Fill and reset stack top */
}
You might want the stack global as in the example or you might want to
wrap it in a structure you pass about. Usually you'll want either pointers
or structures on the stack, but occasionally you might need a stack
of integers or floating point values.
There's no good way of handling memory allocation errors in C, especially
ones which can't happen (a computer with several GB of memory installed
is more likely to develop an electrical fault than to run out
of memory when asked for a couple of kilobytes). The usual rule is to
shunt up. But that makes the push call difficult, because every push
could potentially run the computer out of memory (but it can't really,
it's just your encapsulation allows the function to fail).

Related

Why is my program not reallocating memory in C?

I'm working on this program that creates a stack, pushes and pops values then deletes the stack and deallocates the memory. What I want the function stack_push to do is push values to the stack and if the stack is full, it doubles the amount of memory it has, basically reallocating the memory and doubling it. In this case, it should go from 5 variables to 10. Yet for some reason, it's not doing that. I believe the error stems from my attempt at reallocating memory, what am I doing wrong and how would I go about fixing it?
typedef struct stack
{
int capacity;
int size;
double *data;
} Stack;
Stack *ptr;
Stack *stack_create(void){
ptr = (Stack*)malloc(sizeof(Stack));
ptr->capacity = 5;
ptr->size = -1;
ptr->data = (double*)malloc(sizeof(double) * ptr->capacity);
return ptr;
}
void stack_push(Stack *s, double value){
if (s->size >= s->capacity-1){
ptr = (Stack *)realloc(ptr, 2*sizeof(Stack));
};
ptr->data[++ptr->size] = value;
}
int main(void)
{
// Create an empty stack.
Stack *s = stack_create();
for (int i = 0; i < 10; i++) {
stack_push(s, i);
}
return 0;
}
You're reallocating an additional stack, not more elements in the stack:
ptr = (Stack *)realloc(ptr, 2*sizeof(Stack));
What you want instead is:
ptr->data = realloc(ptr->data, 2 * ptr->capacity * sizeof(double));
if (!ptr->data) {
perror("malloc failed");
exit(1);
}
ptr->capacity *= 2;
The last line keeps track of the updated capacity so that you'll know when you need to reallocate again.
Note that you should always check the return value of malloc and realloc to ensure that the memory was successfully allocated, and that you shouldn't cast the return value as that can mask other errors in your code.
This post highlights the dangers of not reading manuals, FAQs and textbooks when learning. I suggest picking up a copy of K&R2e and doing the exercises as you stumble across them.
ptr = (Stack *)realloc(ptr, 2*sizeof(Stack));
For a start, you're working in C, not C++; you shouldn't be casting the return value of realloc. That's probably not going to cause any headaches beyond what you'd expect from boilerplate crud, but what will cause headaches is if you don't realise the value of ptr may change, and that change will only be local to stack_push because of pass-by-value semantics. Additionally, when ptr does change (but not for the caller), realloc has invalidated the old value, which leads the caller somewhere into this line of frequently asked questions...
See what I mean? Just from this one line of code I can see that your textbooks, college classes and whatnot aren't working out well. Something needs to change. Please 🙏 do consider reading K&R2e and doing those exercises when you can.

What is the point of using a temporary realloc variable, if the program will exit?

Many people recommend doing the following to reallocate memory:
int *temp=realloc(previousVar,newSize);
if(temp==NULL){
printf("error\n");
exit(-1);
}
previousVar=temp;
I understand that, if no new variable was created, the previous pointer would be lost, as NULL would be assigned to it. But what's the point on having all this trouble, if the program will exit in case of failure anyways?
Here's a stack overflow, where the top answer has what I'm referring to:
Proper usage of realloc()
In the example that you provided it really does not matter if you assign the return value to a temporary or not. In the linked answer, the author frees the original buffer, but one could argue that it is not necessary since the process will exit anyway.
However, consider the following example:
typedef struct
{
int *values;
size_t capacity;
size_t size;
} MyBuffer;
bool append(MyBuffer *buffer, int value)
{
if (buffer->size == buffer->capacity)
{
// No more space, double the buffer.
size_t new_capacity = buffer->capacity * 2;
int *temp = realloc(buffer->values, new_capacity);
if (temp == NULL)
{
return false;
}
buffer->values = temp;
buffer->capacity = new_capacity;
}
buffer->values[buffer->size] = value;
buffer->size++;
return true;
}
The function append tries to add a new value to an already allocated buffer. If the buffer is not large enough, it tries to use realloc to obtain a larger buffer. If realloc fails the function returns false.
If we change the realloc call to set directly buffer->values we will leak memory in case of failure:
buffer->values = realloc(buffer->values, new_capacity);
if (buffer->values == NULL)
{
// Here the original `buffer->values` is lost and we can never access it again.
return false;
}
realloc does not free the original buffer, so in case of failure we no longer have access to it. This is a problem: in the best case scenario it is a memory leak, in the worst case we may have lost some data that we still needed (on top of the memory leak).
So this depends on how you handle realloc failures. If you log an error and exit immediately you don't need to use another variable to store the result. If you report the error up the call chain, or there is some cleanup that you want to do you have to do this. If you take the first approach you need to be careful if you refactor that piece of code to return an error instead of exiting, so there is some merit to always assigning the result to another variable.

Heap Buffer Overflow trying to reallocate memory. C Language

I've been writing codes for Min Stack on LeetCode.
Problem I'm having is when I try to reallocate memory(on push method), it tells me "Address Sanitizer: Heap Buffer Overflow."
What's causing this and how can I fix the issue? Thank you
Also, what would be a better way to solve this problem?
typedef struct {
int top;
int *arr;
int min;
int size;
} MinStack;
/** initialize your data structure here. */
MinStack* minStackCreate() {
MinStack* stack = (MinStack*)malloc(sizeof(MinStack));
stack->size = 10;
stack->top = -1;
stack->min = INT_MAX;
stack->arr = (int*) malloc(sizeof(int)*(stack->size));
return stack;
}
void minStackPush(MinStack* obj, int x) {
//if top+1 is equal to the size of the stack(when stack is full),
//I want to multiply the size by 2
//so more numbers can fit in the stack.
if(obj->top+1 == obj->size){
obj->size = obj->size*2; // this line seems to give me issues.
obj->arr = realloc(obj->arr, obj->size);
}
obj->arr[obj->top+1] = x;
obj->top++;
}
The problem seems to be coming from your realloc call, according to the man page:
The realloc() function changes the size of the memory block pointed to by ptr to size bytes.
So you need to have obj->arr = realloc(obj->arr, sizeof(int) * obj->size);
Otherwise your indexing will be off.
It also seems that you're calling realloc on every call, rather than only when you need to increase the size of your array, I'd advise moving that call to inside your if(obj->top+1 == obj->size) statement.
Insufficient/incorrect allocation. realloc() needs the byte count, not just the element count.
// obj->arr = realloc(obj->arr, obj->size);
obj->arr = realloc(obj->arr, sizeof *(obj->arr) * obj->size);
Aside: Robust code would check the realloc() result before assigning to obj->arr. #Eugene Sh.

Freeing all allocated memory in case of failure

I'm working on a C project (assignment for school). One of the demands is that in case of malloc() failure, the program must free() all allocated memory and exit().
Consider a case where function A() constructs a linked-list and in each iteration it calls to another function, B(). Now, if a malloc failure occured at B(), it must free() the memory it allocated but function A() should do that as well.
Things are getting quite complicated when you have a tree of function calls larger than two.
In my previous project I used a flag to notify a malloc() failure - if a function uses another function which may use malloc(), it has to check the flag right after. It worked, but code got kinda messy.
Is there a neat solution for this problem?
Of course, with "real" applications all memory is de-allocated by the OS, but I guess this demand is pedagogical..
I think the easiest approach is to create a custom allocator (as somebody already noted in a deleted post) to keep track of all your allocations, then do a custom deallocator, use these for all your heap memory needs.
if a malloc fails you have the list of previously allocated blocks at easy reach.
e.g.
(you need to redo this cause it is not effective and should be optimized but shows the principle and only ocular compilation)
typedef struct
{
void* pMemory; /* for the allocated memory */
size_t size; /* for better debugging */
} MemoryBlock;
#define MAXBLOCKS 1000
MemoryBlock myheap[MAXBLOCKS]; // global so zero:ed
static int block = 0;
void* myalloc(size_t size)
{
static int block = 0;
// you should check vs MAXBLOCKS
myheap[block].pMemory = malloc(size);
myheap[block].size = size;
// check if it failed.
if ( myheap[block].pMemory == NULL )
{
for (int i = 0; i < block; ++i)
{
myfree(myheap[i].pMemory);
}
fprintf( stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
else
{
return myheap[block++].pMemory;
}
}
void myfree(void* p)
{
for (int i = 0; i < block; ++i)
{
if ( p == myheap[i].pMemory )
{
free(myheap[i].pMemory);
myheap[i].pMemory = NULL;
return;
}
}
}
Yes. The best (and conventional) way is to initialize every pointer value to zero. Then set it during the malloc() assignment. Ex: myPtr = malloc( 10 );
It will be zero in case of failure, and you check that. And finally, when you go about freeing, you always check the pointer value before calling free():
if ( myPtr != 0 )
free( myPtr );
There is no need for an extra flag.
Are you having issue checking for errors or handling them? If you want info on catching them, use donjuedo's suggestion.
For ideas on freeing memory in the event of error, try one of these two methods:
1) For a uni-directional linked-list, keep a special pointer that points to the head of the list. In your cascading free function, start at the head, capture the next-pointer in a temp variable, free the head, move to the next structure in the list using the temp-pointer, and repeat the process until the next-pointer == 0.
2) For a bi-directional linked-list (my preference) you don't need to keep a special pointer to the head of the list. Assuming you are still at the tail, just capture the previous-pointer into a temp variable, free the tail, move back using the temp-pointer, and repeat the process until the previous-pointer == 0
You could look into the atexit() function, to register code that will be executed when the program terminates. Such code can then check if there is anything that needs to be free()d.
Note that atexit() has no way to unregister. So you need to make sure that you register each cleanup function only once, and that it does the right thing when there is nothing to clean up.
#include <stdlib.h>
#include <stdio.h>
int *ptr1;
char *ptr2;
int clean1_registered, clean2_registered;
void clean1(void)
{
printf("clean1 called\n");
if (ptr1) {
free(ptr1);
ptr1 = NULL;
}
}
void clean2(void)
{
printf("clean2 called\n");
if (ptr2) {
free(ptr2);
ptr2 = NULL;
}
}
void B(void)
{
ptr2 = malloc(100);
if (!clean2_registered) {
atexit(clean2);
}
}
void A(void)
{
ptr1 = malloc(100 * sizeof(int));
if (!clean1_registered) {
atexit(clean1);
}
B();
}
int main(int argc, char **argv)
{
A();
}

initializing a data structure in C to manage a pool of memory

i am writing a simple function for a library, that will take in as a parameter the size of memory to be managed by my other functions.
i have a data structure that holds the information of this large memory pool initialized by the user.
typedef struct memBlock{
struct memBlock* next;
unsigned int size; // Size of this block
unsigned int is_used; // bool 0 = not used 1 = used
} memBlock;
I also have this function that i am trying to figure out how to initialize this data structure as well as allocate enough space to be managed initially?
int initialize_memory(unsigned long size){
memBlock *ptr; // the beginning of our whole memory to be handled
ptr = malloc(size); // this is the ptr to the original memory first allocated.
ptr->next = NULL;
ptr->size = NULL;
ptr->is_used = 0;
has_initialized = 1; // the memory has been initialized
}
please help
Change ptr->size = NULL; to ptr->size = size;. You also need to return ptr, or store it somewhere. Your function returns int, but you don't return anything. has_initialized seems unnecessary -- you know you've initialized because your memory pool (the ptr value you will return) isn't NULL. If you need more help than that, you're going to have to explain more.
Addendum: You need to decide whether memBlock.size is the size of the allocated space or the size of the memory block represented by the memBlock ... if the latter, then you need to account for the space occupied by the memblock itself by subtracting that off the amount of space you allocated: ptr->size = size - sizeof(struct memBlock); You also need a way to address your memory pool ... since that immediately follows the memBlock, its address is (ptr + 1) or &ptr[1] (if you don't understand that, look up "pointer arithmetic in C").
P.S. You wrote in a comment "Essentially i also have another function that will act like 'malloc' to reserve a number of bytes but will first check this data structure to see if any memory is available from my pool"
Why do you want to do that? malloc already manages memory far better than your function will, considering the skill level and time invested, and there's no point in layering another memory allocator on top of it. Unless this is a school project to write a memory allocator, in which case you should say that up front.
typedef struct memBlock {
unsigned int size;
unsigned int initialized;
void* block;
} memBlock;
memBlock* new_memBlock(unsigned int size)
{
memBlock* memblock;
memblock = malloc(sizeof(memBlock));
if (memblock)
{
memblock->size = size;
memblock->block = malloc(size);
if (memblock->block)
memblock->initialized = 1;
}
return memblock;
}
void free_memBlock(memBlock** memblock)
{
if (*memblock)
{
free(*memblock->block)
*memblock->block = 0;
}
free(*memblock);
*memblock = 0;
}
void main()
{
memBlock* memblock = new_memBlock(1024);
if (memblock && memblock->initialized)
printf("Initialized\n");
else
printf("Not initialized\n");
free_memBlock(&memblock);
}

Resources