so I'm trying to build a stack in C, using pointers and malloc.
My stack.h has a struct
typedef struct
{
int *top;
int *prev;
} intstack_t;
I'm initialising the stack like this:
int stackInit(intstack_t* self) {
if(malloc(sizeof(self != NULL))) {
self->top = malloc(sizeof(self->top));
self->prev = malloc(sizeof(self->prev));
return 0;
} else {
return 1;
}
}
void stackPush(intstack_t* self, int i) {
self->prev = self->top;
self->top = newElement(i);
}
int stackPop(intstack_t* self) {
int tmp = *self->top;
free(self->top);
self->top = self->prev;
return tmp;
}
int *newElement(int i) {
int *new = malloc(sizeof(i));
*new = i;
return new;
}
My main:
int main()
{
intstack_t stack;
stackInit(&stack);
stackPush(&stack, 1);
stackPush(&stack, 2);
stackPush(&stack, 3);
stackPop(&stack);
printf("stackTop: %i \n", stackTop(&stack));
stackPop(&stack);
printf("stackTop: %i \n, stackTop(&stack));
}
While I can push onto the stack, only the first pop yields the desired output. When I pop again the result is something completely different.
stackTop: 0
stackTop: 1
stackTop: 2
stackTop: 3
stackTop: 2
stackTop: 34792624
Could someone please point me in the right direction, as I dont see where I'm going wrong?
if(malloc(sizeof(self != NULL))) is nonsense code. I can't even make out any sense of your intention here. You need to store the allocated data somewhere and sizeof(self != NULL) is the size of a boolean expresion...
Inside int stackInit(intstack_t* self) you don't return the allocated pointer to the caller, so no matter what you do inside that function it won't get returned to the caller.
It is not clear why you must dynamically allocate the stack itself in the first place. intstack_t stack; already allocates this variable on the stack (the program's stack) before you call stackInit(&stack);.
You must free() memory that you allocate.
And so on. Overall, the code makes no sense at all. It would seem that you are trying to write this program through trial & error programming, which will never work.
One essential problem is that struct intstack_t does not contain any pointer to intstack_t - the previous element in the stack. It only contains pointers to two ints. That is, your implementation of stack cannot store more than two ints at all.
Related
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.
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).
I'm trying to create a stack where I can push integers into it. So far I have this:
#include <stdio.h>
#define N 20
typedef struct {
int data[N]; // array of at most size N
// N should be a constant declared globally
int top;
} stack_t;
void push(stack_t *stack, int element);
int main(){
void push(stack_t *stack, int n) {
if (stack->top == N - 1) {
printf("Warning: Stack is full, You can't add'\n");
return;
} else {
stack->data[++stack->top] = n;
}
}
stack_t * e_stack; // Empty stack created
push(e_stack, 2);
}
However, this code gives a runtime error. I assume it's because this part is wrong:
stack_t * e_stack; // Empty stack created
(That probably didn't create an empty stack)
But I know how is it wrong
You're right, all you've done is created a pointer that points at...something, but probably not a stack_t. You need to allocate something to point at. See malloc. Then you'll need to initialize stack_t::top to -1 or some other value. Zero probably won't work here since that index would likely be the first item in the stack.
Here is an example that I wrote a while ago. It basically pushes integers onto a stack, and pops the most recently added item to the stack. Note, the popping of items is probably not the best way to doing it, there are certainly better ways.
Example code:
#include <stdio.h>
#include <stdlib.h>
#define N 20
typedef struct {
int data[N]; //better to use a dynamic array instead here
int top;
} stack_t;
stack_t *create_empty_stack(void);
void push(stack_t *stack, int value);
int pop(stack_t *stack);
int
main(void) {
stack_t *stack;
stack = create_empty_stack();
push(stack, 10);
push(stack, 20);
push(stack, 30);
printf("Popped: %d\n", pop(stack));
printf("Popped: %d\n", pop(stack));
printf("Popped: %d\n", pop(stack));
printf("Popped: %d\n", pop(stack));
free(stack);
return 0;
}
void
push(stack_t *stack, int value) {
if (stack->top == N - 1) {
printf("Warning: Stack is full, You can't add'\n");
return;
} else {
stack->data[stack->top] = value;
(stack->top)++;
}
}
int
pop(stack_t *stack) {
if (stack->top > 0) {
(stack->top)--;
return stack->data[stack->top];
} else {
//definetly better way to do this. I will let you decided how you want to implement this.
printf("Tried to pop empty stack!\n");
exit(EXIT_FAILURE);
}
}
// Since you are using a fixed sized array, creating an empty stack in this case is easy.
stack_t
*create_empty_stack(void) {
stack_t *stack = malloc(sizeof(*stack));
if (stack == NULL) {
printf("Cannot allocate stack\n");
exit(EXIT_FAILURE);
}
stack->top = 0;
return stack;
}
Either (as other answers suggest) allocate a memory zone and get a pointer to stack_t on the heap and initialize it correctly (perhaps thru a create_empty_stack function) or declare a stack_t local variable (on the call stack), initialize it explicitly, and pass a pointer to it:
stack_t locstack = {.data={}, .top=0};
push(&locstack, 2);
BTW, as commented by Jonathan Leffler, your code is not standard C99 or C11, because nested functions are not allowed in standard C. You are (probably incorrectly) using some GCC extension. You should define the push function outside of (and before) main. If you care about efficiency, define it as static inline void push(stack_t *stack, int n) .... to get it inlined.
Notice that if you want to accept arbitrarily sized stacks, consider using some flexible array member, and grow them (once in a while) as needed (think of some int newsize = 4*stack->size/3+2; when the stack gets full, then stack_t*newstack = malloc(sizeof(stack_t)+newsize*sizeof(int)); etc....) and only use heap allocated pointers, you could consider keeping both top and size as fields of stack_t and have data[] as its (last) flexible array member. In that case push would probably return a (possibly updated) pointer.
BTW, as soon as you are using some heap allocation like malloc, you always should handle failure, at the very least as:
stack_t* pstack = malloc(sizeof(stack_t));
if (pstack==NULL) { perror("malloc"); exit(EXIT_FAILURE); };
(if you have some
If using GCC, read more about its command options (their order is important). I recommend compiling with gcc -std=c99 -Wall -Wextra -g (on your original code, that should give some useful diagnostics), improve your code till you get no warnings, then use the gdb debugger.
For example, take this example functions:
#include <stdlib.h>
#define MAX 100
typedef struct stack {
int sp;
int val [MAX];
} STACK;
void initStack (STACK *s){
s->sp = 0;
}
int push (STACK *s, int x){
if(s->sp == MAX) return -1;
else s->val[s->sp++] = x;
return 0;
}
int main(){
STACK s;
int pushval, p;
initStack(&s);
p = push(&s, 1);
pushval = s.val[s.sp-1];
printf("pushval %d\n", pushval);
return 0;
}
So in this case if I do s.val[s.sp] I get gibberish. If I do s.val[s.sp-1] I get the value I pushed on to the stack. I don't know if the stack pointer should point to the "next available space" aka be equal to the number of elements in the array, or should be equal to the index of the last element of the array aka number of elements in the array - 1
This is just a matter of convention. Many implementations let the top stack pointer points to the "next available space", but you can really do what you prefer, provided that externally your stack behave as intented.
For me, the most natural implementation of an array-based stack is one that grows "downwards", with the stack pointer pointing to the most recently pushed element:
void initStack (STACK *s)
{
s->sp = MAX;
}
int push (STACK *s, int x)
{
if( !s->sp )
return 0;
else
s->val[--s->sp] = x;
return 1;
}
int pop(STACK *s, int *x)
{
if ( s->sp == MAX )
return 0;
else
*x = s->val[s->sp++];
return 1;
}
The checks are simpler IMO, and since it never decrements below 0, you can safely use an unsigned type as your stack pointer (which I tend to do for reasons that probably aren't completely rational).
Note that this mimics the x86 (and many other architectures') stack behavior, in that the SP grows "downwards", towards 0.
Notice that I changed the return value on success and failure, since in C 0 means "false" and non-zero means "true". This way you can write code like
if ( push( stack, val ) )
{
...
}
else
{
// push failed, handle as appropriate
}
Again, this is just a more natural implementation IMO.
EDIT
One big drawback of this method is that it's difficult to grow the stack if necessary. If you allocate the backing array dynamically, you can use realloc to extend it, but you will have to move all the existing data to the new stack "bottom", which would be expensive and a pain in the ass. By contrast, if you grow the stack upwards, you don't have that problem. But, if I wanted a stack that could grow or shrink as necessary, I wouldn't use an array-based stack, I'd use one based on a linked list, where items are pushed by adding them to the head of the list and popped by removing them from the head.
Lately I've been writing code in C for a generic stack using an array of void pointers. After doing some tests everything seemed to be fine, until this last test:
while(i < 9) {
push_pila(mi_pila,(int*)&i);
i++;
}
As you can see I'm passing an i as an argument into the push_pila function. This is the code for the push_pila function in the stack:
typedef struct {
void **vec;
int tope;
int16_t max_elementos;
}PILA;
int push_pila(PILA *mi_pila,void *val) {
if(pila_llena(mi_pila)) {
return -1;
}
else {
mi_pila->tope = mi_pila->tope + 1;
mi_pila->vec[mi_pila->tope] = val;
return 0;
}
}
Here is where the problem is, because my stack is an array of void* containing the values of the address of val. When I pass the value of i I'm passing the address of it. The problem in this case is that all the values inside the stack will contain the same address therefore all the value in the stack will be the same, so when I pop the stack using the pop function I will return the same value which is the last value of i, in my case 9.
Is there any solution to this problem?. Or is just that this is not the best way to push elements in the array?
If you want to pass in memory values, you need to make each entry have a distinct memory value, rather than incrementing the same address over and over again and passing the same address. You need to allocate memory from the heap with malloc, set that memory to whatever integer value you want (1-9 in this case), and then push that pointer onto the stack.
Something like this:
while(i < 9) {
int* int_ptr = (int*) malloc(sizeof(int));
*int_ptr = i;
push_pila(mi_pila, int_ptr);
i++;
}
Later, when you're done with the stack, you will need to pop off each pointer and free it.
You must allocate fresh storage to hold each integer:
while(i < 9) {
int *i_boxed = safe_malloc(sizeof(int));
*i_boxed = i;
push_pila(mi_pila, i_boxed);
i++;
}
Note safe_malloc just calls malloc and handles allocation failure gracefully.