I was given this code from Uni and I am trying to do operations with it , the push function ask for two pointers and I could not figure out how can I pass the data to the item part.I have tried using another structure containing the data but I failed. I am stuck at the end of the code and I would like to learn how to push data using this code. How can I proceed ?
It would be preferable if the data itself was stored in a structur.
Thanks in advance.
typedef struct stk
{
struct stk* elems[MAX]; int top;
} stack, *stackptr;
void Init(stack* s)
{
s->top = 0;
}
int IsEmpty(stack s)
{
return (s.top == 0);
}
void Push(struct stk* item, stack* s)
{
if (s->top == MAX)
printf("Stack voll!");
s->elems[s->top] = item;
s->top++;
}
struct stk* Pop(stack* s)
{
if (IsEmpty(*s)) return NULL;
s->top--;
return s->elems[s->top];
}
int main()
{
stack* ptr = (stackptr)malloc(sizeof(stack));
Init(ptr);
printf("%d\n", ptr->top); // Ist 0 , OK
}
Here is a working stack implementation that store ints. This will afford you the opportunity to test that the operations work as expected. If you really want to store stack * replace the type. It seems unnecessarily confusing for a entry level class to have an assignment of storing pointers to the same thing you are building.
When you deal with pointers you want to make sure the object they point to outline the pointer. You may also want to think of shallow and deep copies with pointers. If you Pop followed by a Push the pointer that was returned from Pop now will point to the new value which would be surprising. Consider a different designs:
Pass in a reference to a variable (aka out parameter) so Pop(stack *s, *v) (and use an enum or define constants for error values).
return a value instead of a pointer; error would not be an out parameter.
return a pointer to a copy of the value and require client to free it.
#include <stdio.h>
#include <stdlib.h>
#define MAX 10
typedef struct stack {
int elems[MAX];
int top;
} stack;
void Init(stack *s) {
if(!s)
return;
s->top = 0;
}
int IsEmpty(stack *s) {
return (s->top == 0);
}
void Push(stack *s, int elem) {
if (s->top == MAX) {
printf("Stack voll!");
return;
}
s->elems[s->top++] = elem;
}
int *Pop(stack *s) {
if (IsEmpty(s))
return NULL;
return &s->elems[--(s->top)];
}
int main() {
stack *s = malloc(sizeof *s);
Init(s);
printf("%d\n", s->top); // Ist 0 , OK
Push(s, 42);
int *v = Pop(s);
printf("%d\n", *v);
}
and example run:
0
42
Consider using a name prefix like "Stack" for all your symbols to avoid name conflicts.
In c we don't cast void * (from malloc()).
my code is not working but when I change struct stack *sp; to struct stack * sp = (struct stack *) malloc(sizeof(struct stack)); it start working. I am confused in when to allocate memory in heap to struct stack *ptr and when to not. It will be better if u can give me an example when struct stack *ptr can be used and when to use struct stack * sp = (struct stack *) malloc(sizeof(struct stack));
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stack
{
int size;
int top;
char *arr;
};
int stackTop(struct stack* sp){
return sp->arr[sp->top];
}
int isEmpty(struct stack *ptr)
{
if (ptr->top == -1)
{
return 1;
}
else
{
return 0;
}
}
int isFull(struct stack *ptr)
{
if (ptr->top == ptr->size - 1)
{
return 1;
}
else
{
return 0;
}
}
void push(struct stack* ptr, char val){
if(isFull(ptr)){
printf("Stack Overflow! Cannot push %d to the stack\n", val);
}
else{
ptr->top++;
ptr->arr[ptr->top] = val;
}
}
char pop(struct stack* ptr){
if(isEmpty(ptr)){
printf("Stack Underflow! Cannot pop from the stack\n");
return -1;
}
else{
char val = ptr->arr[ptr->top];
ptr->top--;
return val;
}
}
int precedence(char ch){
if(ch == '*' || ch=='/')
return 3;
else if(ch == '+' || ch=='-')
return 2;
else
return 0;
}
int isOperator(char ch){
if(ch=='+' || ch=='-' ||ch=='*' || ch=='/')
return 1;
else
return 0;
}
char* infixToPostfix(char* infix){
struct stack *sp;
sp->size = 10;
sp->top = -1;
sp->arr = (char *) malloc(sp->size * sizeof(char));
char * postfix = (char *) malloc((strlen(infix)+1) * sizeof(char));
int i=0; // Track infix traversal
int j = 0; // Track postfix addition
while (infix[i]!='\0')
{
if(!isOperator(infix[i])){
postfix[j] = infix[i];
j++;
i++;
}
else{
if(precedence(infix[i])> precedence(stackTop(sp))){
push(sp, infix[i]);
i++;
}
else{
postfix[j] = pop(sp);
j++;
}
}
}
while (!isEmpty(sp))
{
postfix[j] = pop(sp);
j++;
}
postfix[j] = '\0';
return postfix;
}
int main()
{
char * infix = "x-y/z-k*d";
printf("postfix is %s", infixToPostfix(infix));
return 0;
}
Two things to always remember when working with pointers in C:
Memory allocation is your problem. You have to think about the allocation of the memory which a pointer variable points to.
You have to be clear in your mind about the distinction between the pointer versus the data that it points to.
So when you say
struct stack *sp;
that will never work, all by itself. It won't work for a program that's implementing a stack, and it won't work for a program that's implementing any other kind of data structure.
When you write
struct stack *sp;
there is one important thing that you have done, and there is one important thing that you have not done.
The compiler allocates space to store one pointer. This pointer is known as sp. But:
The value of this pointer is indeterminate, which means that it does not point anywhere yet. You can't actually use the pointer variable sp for anything. (Yet.)
Or, in other words, going back to the distinction I mentioned earlier, you have taken care of the pointer but you don't have any data that the pointer points to.
But when you say
sp = malloc(sizeof(struct stack));
(and assuming malloc succeeds), now sp points somewhere: it points to a chunk of properly-allocated memory sufficient to hold one struct stack.
This is the code here. Even after debugging I'm not able to find the problem. The code was working fine if I'm not using the pointer.
#include <stdio.h>
#include <stdlib.h>
struct stack{
int size;
int top;
int *arr;
};
int isEmpty(struct stack *ptr){
if ((*ptr).top == -1){
return 1;
}
else{
return 0;
}
}
int main()
{
struct stack *s;
(*s).size = 80;
(*s).top = -1;
(*s).arr = (int *)malloc((*s).size * sizeof(int));
// Check if stack is empty
if(isEmpty(s)){
printf("The stack is empty");
}
else{
printf("The stack is not empty");
}
return 0;
}
You did not allocate any memory for your struct. You may decalre it on the stack: struct stack s; or allocate memory for it: struct stack *s = (struct stack *)malloc(sizeof(struct stack));.
When you have a pointer to a struct, please use the -> operator to access its members like so s->size.
I have been assigned to program a generic stack in ANSI C. It is meant to be for primitive datatypes. Until here there was no big problem whatsoever.
Afterwards I was asked to reprogram my application so that even complex data types can be used on my stack. I have searched and researched for the last week and I found nothing that could be helpful enough.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stddef.h>
#include "genstacklib.h"
void (*freefn) (void*);
/*
* ToDo
*/
void GenStackNew(genStack *s, int elemSize, void (*freefunk) (void*))
{
s->elems = malloc (elemSize * GenStackInitialAllocationSize);
freefn = freefunk;
assert (s->elems != NULL);
s->elemSize = elemSize;
s->logLength = 0;
s->allocLength = GenStackInitialAllocationSize;
}
/*
* ULStackPush adds an element to the stack and allocates new memory if
* needed. If there is not enough memory, ULStackPush does nothing.
*/
void GenStackPush (genStack *s, const void *elemAddr)
{
/*assert (sizeof(*elemAddr) == s->elemSize);*/
assert (s->elems != NULL);
if (s->logLength == s->allocLength)
{
void *temp = NULL;
temp = realloc (s->elems, 2 * s->allocLength * s->elemSize);
assert (temp != NULL);
s->allocLength = 2 * s->allocLength;
s->elems = temp;
}
memcpy(currentval(s), elemAddr, s->elemSize);
s->logLength = s->logLength + 1;
}
void GenStackPop (genStack *s, const void *elemAddr)
{
assert (s->elems != NULL);
assert (s->logLength != 0);
(s->logLength)--;
memcpy((void *)elemAddr, currentval(s), s->elemSize);
}
void *currentval(genStack *s)
{
assert (s->elems != NULL);
return ((size_t*)s->elems + s->logLength * s->elemSize);
}
bool GenStackEmpty (const genStack *s)
{
assert (s->elems != NULL);
return s->logLength == 0;
}
void GenStackDispose (genStack *s)
{
assert (s->elems != NULL);
s->logLength = 0;
free (s->elems);
freefn();
}
/*
* ToDO
*/
void *freefn (void *) {
free
And my header data is:
#ifndef GENSTACKLIB_H
#define GENSTACKLIB_H
#include <stdbool.h>
#define GenStackInitialAllocationSize 4
typedef struct
{
void *elems;
int elemSize;
int logLength;
int allocLength;
} genStack;
void GenStackNew (genStack * s, int elemSize);
bool GenStackEmpty (const genStack * s);
void GenStackPush (genStack * s, const void *elemAddr);
void GenStackPop (genStack * s, const void *elemAddr);
void GenStackDispose (genStack * s);
void *currentval(genStack *s);
#endif
In the first block of code, I believe that what has to be done is in the ToDo markings.
How can I make it to use my stack for complex data types?
Thanks in advance
I dont see any problem with "complex" types like strings... there is no real difference bewteen pointer to string and pointer to int. So just store pointers (or pointers to pointers) and that should work.
So instead of element to be "int".. element is pointer to pointer.
Basic idea in form of very "pseudo" C code
typedef struct Wrapper
{
void * primitiveData;
} Wrapper;
void PrimitivePush(void * data)
{
Wrapper * w = malloc();
w->primitiveData = malloc();
memcpy(w->primitiveData, data);
ClassicComplexTypePush(&w)
}
ClassicComplexTypePush(void ** data)
{
push data to stack
}
Consider using a singularly linked list for implementation, since when
using a stack, we don't know how many items may be needed.
Use a byte* or (char*) to store the contents of memory, instead of a void* (which would also work, but we may need to pad the allocation, to include structs)
Copy memory into a new allocation, which is pushed onto the stack,
then delete that used upon pop.
each node has to be of the same type, or at-least the same size,
errors using wrong type though may be undesired
pop can be either used to check if the stack is empty by passing (NULL)
or to actually pop the stack, by referencing the memory you want to set.
typedef unsigned char byte;
Create the structures which will be used to keep track of the stack
struct gStackNode {
byte *data;
struct gStackNode *next;
};
struct gStack {
unsigned size;
struct gStackNode *head;
};
Initialize the stack, including the size of the type we will be using
void stack_initalize(struct gStack *stk, unsigned size) {
if (!stk)
return;
stk->size = size;
stk->head = (void*)0;
}
Always, we need to manually free the stack, in-case not all were popped
void stack_free(struct gStack *stk) {
if (!stk)
return;
struct gStackNode *temp;
/* step through the remaining stack, deleting each item */
while(stk->head) {
temp = stk->head->next;
free((byte*)stk->head->data);
free((struct gStackNode *)stk->head);
stk->head = temp;
}
}
push an item onto the stack
void stack_push(struct gStack *stk, void *data) {
struct gStackNode *node = (struct gStackNode*)malloc(sizeof(struct gStackNode));
struct gStackNode *temp = stk->head;
node->next = temp;
node->data = (byte*)malloc(sizeof(byte)*(stk->size));
byte * src = (char*)(data);
byte * dest = (char*)(node->data);
unsigned n = stk->size;
/* fill the new allocation with source data */
for(;n;n--)
*(dest++) = *(src++);
/* the node becomes the new head */
stk->head = node;
}
Sometimes we don't want to use a local variable ie: stack_pop_(stack, &type) we can use stack_push_arg_no_ref(stack, 10).
void stack_push_arg_no_ref(struct gStack *stk, void *data) {
stack_push(stk, &data);
}
Now we can pop, and use the same to peek, passing (NULL) to data will result in a peek,
returning (1) if there is an item in the stack, and a (0) if its empty
int stack_pop(struct gStack *stk, void * data) {
if (!stk)
return 0;
if (!stk->head)
return 0;
if (data == (void*)0) {
/*
simply check to see if the stack is empty or not
don't actually pop the stack
*/
return ((!stk->head == (void*)0));
} else {
struct gStackNode *next = stk->head->next;
struct gStackNode *node = stk->head;
unsigned i;
byte *c_temp = (byte*)data;
for(i=0;i<stk->size;i++)
*c_temp++ = node->data[i];
free((byte*)node->data);
free((struct gStackNode*)node);
stk->head = next;
}
}
Finally we can implement the stack
using any ANSI C data types
the size of a character string needs to be fixed
structs can also be used
Using a character string
CAUTION, for this example, the strings need to be NULL terminated, though
it is possible to use non-NULL terminated strings
char ta[32] = "ta: text 1";
char tb[32] = "tb: text 2";
char tc[32];
struct gStack stack_char; stack_initalize(&stack_char, sizeof(ta));
stack_push(&stack_char, ta);
stack_push(&stack_char, tb);
while (stack_pop(&stack_char, &tc))
printf("%s\n", tc);
be sure to free the stack
stack_free(&stack_char);
Using integers
int a = 120, b = -32, c;
struct gStack stack_int; stack_initalize(&stack_int, sizeof(int));
stack_push(&stack_int, &a);
stack_push(&stack_int, &b);
/* or we can use */
stack_push_arg_no_ref(&stack_int, 1776);
/* we can now see the contents of the stack */
while (stack_pop(&stack_int, &c))
printf("%d\n", c);
stack_free(&stack_int);
// Whenever i am increasing function call times of push more than 8, it get crashed before that everything is working good. your help is required. In the below code i have created a program for stack using Dynamic array keeping in mind there should not be any stack overflow by using realloc function to doubling the values whenever the stack gets filled.
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
typedef struct ArrayStack
{
int top;
int capacity;
int *arr;
}*stack;
stack Creation()
{
stack S;
S=(stack)malloc(sizeof(struct ArrayStack));
if(!S)return NULL;
S->top=-1;
S->capacity=1;
S->arr=(int*)malloc(S->capacity*sizeof(int));
if(!S->arr)return NULL;
return S;
}
int is_Full(stack S)
{
return S->top==S->capacity-1;
}
int is_Empty(stack S)
{
return S->top==-1;
}
void Doubling(stack S)
{
S->capacity*=2;
S->arr=realloc(S->arr,S->capacity);
}
void push(stack S,int data)
{
if(is_Full(S))
Doubling(S);
S->arr[++S->top]=data;
}
int pop(stack S)
{
if(is_Empty(S))
printf("\nStack underflow");
else
return S->arr[S->top--];
}
int main()
{
stack S;
int i=0,size=9;
S=Creation();
**for(i=0;i<size;i++)
push(S,19+1);** // As in this case
return 0;
}
S->arr = malloc(S->capacity * sizeof(int));
S->arr = realloc(S->arr, S->capacity);
You only reallocate enough space for S->capacity / sizeof(int) items.