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()).
Related
I get a segfault while runnig this code to implement a stack in C. Please note that the code is kind of incomplete. I just wanted to check and see if I could push a few elements on to the stack and print them out. But it throws back a segfault. Any help would be much appreciated!!
#include<stdlib.h>
#include<stdio.h>
struct stack
{
int *elems;
int ll;
int al;
};
void stack_new(struct stack *s)
{
s->ll=0;
s->al=4;
s->elems=malloc(4*sizeof(int));
}
void stack_del(struct stack *s)
{
free(s->elems);
}
void stack_push(struct stack *s,int value)
{
if(s->ll==s->al)
{
printf("overflow");
/*s->al*=2;
s->elems=realloc(s->elems, s->al*sizeof(int));*/
}
s->elems[s->ll]=value;
s->ll++;
}
void stack_pop(struct stack *s)
{
s->ll--;
return (s->elems[s->ll]);
}
void main()
{
struct stack *s;
stack_new(s);
stack_push(s,3);
stack_push(s,4);
stack_push(s,8);
printf("%d", s->elems[0]);
//stack_pop(s);
//stack_del(s);
}
Declaring
struct stack *s;
doesn’t allocate any memory for a struct stack. Do that:
struct stack *s = malloc(sizeof *s);
Or just put your stack on the stack:
struct stack s;
stack_new(&s);
…
Using more descriptive field names is also a good idea.
You have several errors
You never initialize the pointer s in your main function, so in your stack_new function dereferencing s causes a segmentation fault.
You should allocate space for the stack first, wherever you want but you must.
Another thing is if you want to initialize your al field with a constant number and then allocate an array of constant size, you don't need the field al, and you can declare elems as int elems[CONSTANT_NUMBER] but if you want it to be dynamic, which is what I think you want from your check if(s->ll == s->al) in the stack_push function, then you can simply pass the value you want al to have to the stack_new function.
This is some of your code, fixed so you can see what I actually mean.
#include<stdlib.h>
#include<stdio.h>
struct stack
{
int *elems;
int ll;
int al;
};
struct stack *stack_new(int al) /* you can pass the maximum number of elements allowed */
{
struct stack *s;
s = malloc(sizeof(struct stack));
if (s == NULL)
return NULL;
s->ll = 0;
s->al = al;
s->elems = malloc(al * sizeof(int)); /* and you dynamically allocate space for them here */
return s;
}
void stack_del(struct stack *s)
{
if (s != NULL) /* always check the pointers to prevent `SEGMENTATION FAULT` */
{
if (s->elems != NULL)
free(s->elems);
free(s);
}
}
void stack_push(struct stack *s, int value)
{
if (s == NULL)
return;
if(s->ll == s->al)
{
printf("overflow");
/*s->al*=2;
s->elems=realloc(s->elems, s->al*sizeof(int));*/
}
if (s->elems != NULL)
s->elems[s->ll] = value;
s->ll++;
}
int stack_pop(struct stack *s)
{
if ((s == NULL) || (s->elems == NULL))
return 0;
s->ll--;
return (s->elems[s->ll]);
}
int main()
{
struct stack *s;
s = stack_new(4);
stack_push(s, 3);
stack_push(s, 4);
stack_push(s, 8);
printf("%d", s->elems[0]);
stack_pop(s);
stack_del(s);
return 0;
}
```
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);
I'm trying to get the hang of c and I can't figure out why this code is producing a segfault.
// In src/test.c
#include <stdio.h>
typedef struct {
int length;
int *arr[1000];
} Stack;
void push(Stack *stack, int el) {
(*stack->arr)[stack->length++] = el;
}
int pop(Stack *stack) {
return (*stack->arr)[--stack->length];
}
int main(int argc, char* argv[]) {
Stack stack;
push(&stack, 5);
printf("%d\n", pop(&stack));
return 0;
}
Then I compile and run:
$ gcc src/test.c -o test && ./test
[1] 79484 segmentation fault ./test
You have a few problems.
Like others have mentioned, your int length struct member is never set to zero and thus could contain anything.
You must set the length to 0.
Second, int *arr[1000] is an array of integer pointers. So simply assigning an int to a particular array position is wrong.
You want something more like this:
// In src/test.c
#include <stdio.h>
typedef struct {
int length;
int arr[1000]; // Code change (create an array of integers)
} Stack;
void push(Stack *stack, int el) {
stack->arr[stack->length++] = el; // Code change (no need for additional
// structure member dereference).
}
int pop(Stack *stack) {
return stack->arr[--stack->length]; // Code change (no need for additional
// structure member dereference).
}
int main(int argc, char* argv[]) {
Stack stack;
stack.length = 0; // Code change (set the starting length value to 0)
push(&stack, 5);
printf("%d\n", pop(&stack));
return 0;
}
In your structure, "length" is never initialized, so it contains garbage. WHen you then reference:
(*stack->arr)[stack->length++]
it is indexing memory at an undefined location. So, you need some function, like "init_stack()" to initialize the structs data members to well known values (like zero).
The type of the array in the structure is wrong; it should be int arr[1000];.
As written, you're using uninitialized variables all over the place; neither the length nor any of the pointers in your arr are set to anything reliable (though the pointers should be plain int anyway). Because you have pointers instead of int in your stack, you have a very complex expression to access the stack (the (*stack->arr)[stack->length++], etc), which should be much simpler, as in this rewritten code below.
#include <stdio.h>
typedef struct
{
int length;
int arr[1000];
} Stack;
void push(Stack *stack, int el)
{
stack->arr[stack->length++] = el;
}
int pop(Stack *stack)
{
return stack->arr[--stack->length];
}
int main(void)
{
Stack stack = { 0, { 0 } };
push(&stack, 5);
printf("%d\n", pop(&stack));
return 0;
}
#include <stdio.h>
typedef struct {
int length;
int arr[1000];
} Stack;
void push(Stack *stack, int el) {
(stack->arr)[stack->length++] = el;
}
int pop(Stack *stack) {
return (stack->arr)[--stack->length];
}
int main(int argc, char* argv[]) {
Stack stack;
memset(&stack,0,sizeof(Stack));
push(&stack, 5);
printf("%d\n", pop(&stack));
return 0;
}
The thumb rule is allocate memory before accessing it.
Original Q: I'm trying to create this calculator in C for a project. I got the math functions working, but not I am stuck on how to handle the push an pop. Can somebody help me get started? I know what push and pop are supposed to do from java, but I am not sure how to use them without using nodes or an array.
My includes and stack struct:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stack.h"
#include "debug.h"
#define DEFAULT_CAPACITY 16
struct stack {
size_t capacity;
size_t size;
stack_item *data;
};
My attempted push and pop:
UPDATED
void push_stack (stack *this, stack_item item) {
if (full_stack (this)) realloc_stack (this);
this->data[this->size++]=item;
}
stack_item pop_stack (stack *this) {
assert (! empty_stack (this));
if(this->data == NULL){
fprintf(stderr, "fail");}
else{
stack_item tempPop = this->data[this->size--];
return tempPop;}
}
Updated Q: This is now what I am doing for my push/pop method. I am getting no warnings and no errors, but when I run it, it seg faults after it should pop.
My new question is, does it appear that something I am doing in this block of code is causing my seg fault?
Use linked lists.
struct stack_element {
struct stack_element* next; // reserved for stack control
int data0; // whatever
int data1;
int data2;
};
void push_stack(struct stack_element** stack, struct stack_element* element)
{
element->next = *stack;
*stack = element;
}
struct stack_element* pop_stack(struct stack_element** stack)
{
struct stack_element* element = *stack;
if (element)
*stack = element->next;
return element;
}
struct stack_element* stack = NULL; // your stack. its empty
Creating new stack element and adding to stack:
struct stack_element* element = malloc(sizeof(struct stack_element)); // created new element
element->data0 = 123;
element->data1 = 456;
element->data2 = 789;
push_stack(&stack, element); // stored in stack
Fetching an element from stack:
struct stack_element* element = pop_stack(&stack);
if (element == NULL)
printf("Stack was empty, no elements to fetch.");
PS: The same element can never be pushed to the stack more than once.
You can also have the stack control separated from the data, in which case you will be able to store the same element more than once:
struct stack_control {
struct stack_control* next;
void* data;
};
void push_stack(struct stack_control** stack, void* data)
{
struct stack_control* temp = malloc(sizeof(struct stack_control));
temp->data = data;
temp->next = *stack;
*stack = temp;
}
void* pop_stack(struct stack_control** stack)
{
void* data = NULL;
struct stack_control* temp = *stack;
if (temp)
{
data = temp->data;
*stack = temp->next;
free(temp);
}
return data;
}
struct stack_control* stack = NULL; // empty stack
This code the way it is can be used to stack pointers of any type, because void* is generic.
//Validation sample code of behavior
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if 0
#include "stack.h"
#include "debug.h"
#else
typedef char* stack_item;
#endif
#define DEFAULT_CAPACITY 16
struct stack {
size_t capacity;
size_t size;
stack_item *data;
};
typedef struct stack stack;
stack *Stack(void){
stack *s = malloc(sizeof(stack));
s->capacity = DEFAULT_CAPACITY;
s->size = 0;
s->data = malloc(s->capacity * sizeof(stack_item));
return s;
}
int full_stack(stack *this){
return this->capacity == this->size;
}
int empty_stack(stack *this){
return this->size == 0;
}
void realloc_stack(stack *this){
this->capacity += DEFAULT_CAPACITY;
this->data = realloc(this->data, this->capacity*sizeof(stack_item));
}
void push_stack (stack *this, stack_item item) {
if (full_stack (this))
realloc_stack (this);
this->data[this->size++]=item;
}
stack_item pop_stack (stack *this) {
assert (!empty_stack (this));
if(this->data == NULL){
fprintf(stderr, "fail");
exit(1);//Maybe malloc or realloc
}
return this->data[--(this->size)];
}
int main(void){
stack *s = Stack();
push_stack(s, "sin");
push_stack(s, "+");
push_stack(s, "cos");
while(!empty_stack(s)){
puts(pop_stack(s));
}
//Stack_(s);//call destructor
return 0;
}
I understand what you mean when you say "I know what push and pop are supposed to do from java", but please bear in mind that push and pop are just operations that you can do to a data structure that is known as a stack. A stack is more of an idea and that concept can be implemented in any language.
To start of, I would advice you not to use a array. A stack imposes an order in the way you access elements and its perfectly fine with a nice linked list because you only need to remove from the head and add elements to the same head. You typically use an array when you want to access elements at any position in O(1) complexity. The effect of using a linked list is that you dont really have a bound in the number of elements you can add to the stack (unless you really want to).
If you decide to go for a linked list I would advice you to use two structures:
struct stack_node {
int data;
stack_node* next;
};
struct stack {
int current_size;
int max_size;
struct stack_node head;
};
The you can always do
void push(struct stack* s, int x){
if(s->max_size > s->current_size+1){
add to the stack
} else {
stack is full!!
}
}
int pop(struct stack* s) {
if(s->current_size == 0){
Ops! No data in stack, throw error or something
} else {
return head and remove item from stack
}
}
Note that this is only a template to give you an idea... Also, I dont really understand in your code what does "realloc_stack". I think the main problem in your code is that you might still be in a bit of a java minset and programming C requires you to think a bit more low level and do more thinks yourself...
A language has not array as a data type but it has stack as a data type and one can declare stack's; and push, pop and isempty operations are defined.
So how can we implement array using two stacks and above operations?
Horribly inefficient - but:
Stack 1 Contains the details
Stack 2 is empty.
To go through the array, Pop Stack 1 , when you want the next one, push the previous one into stack 2 and pop stack 1 again. Repeat until 'isempty'.
If you want the Nth value, pop the not empty stack N times while pushing the unneeded ones into the other stack. Then when you're done playing with it, empty it into the other stack. Note that this;ll flip the order.
With two stacks you can get some sort of random access (which is what you're interested in an array) like this:
Put everything on a stack.
Every time you have to access something that's not the top of the stack (pop), you pop all elements from this stack and push them in order to the second one.
By passing elements from one stack to another you simulate iteration.
First element of array is a bottom of stack1;
Last element of array is a bottom of stack2;
Current element of array is a top of stack1;
Iterates through the array by shifting the elements of the stack1 to stack2(move to the begin) and vice versa (move to end).
#include <stdio.h>
#include <stdlib.h>
#define Type int
#define DefaultValue 0
#define bool int
typedef struct stack{
Type *stack;
Type *sp;
size_t size;
} Stack;
Stack* Stack_make(size_t size){
Stack *s;
s = (Stack*)malloc(sizeof(Stack));
s->stack = (Type*)malloc(sizeof(Type)*size);
s->sp = s->stack -1;
s->size = size;
return s;
}
bool Stack_empty(Stack *s){//isempty
return s->sp < s->stack;
}
void Stack_push(Stack *s, Type value){
if(s->sp >= s->stack + s->size -1){
fprintf(stderr, "stack over flow\n");
exit(-1);
}
*(++s->sp) = value;
}
Type Stack_pop(Stack *s){
if(Stack_empty(s)){
fprintf(stderr, "stack is empty\n");
exit(-2);
}
return *s->sp--;
}
void Stack_free(Stack *s){
if(s!=NULL){
free(s->stack);
free(s);
}
}
typedef struct array {
Stack *front;
Stack *back;
size_t size;
size_t index;
} Array;
Array* Array_make(size_t size){
Array *a;
int i;
a = (Array*)malloc(sizeof(Array));
a->front = Stack_make(size);
a->back = Stack_make(size);
a->size = size;
//initialize
Stack_push(a->front, DefaultValue);
for(i=0;i<size;++i){
Stack_push(a->back, DefaultValue);
}
a->index = 0;
return a;
}
void Array_pos_set(Array *a, size_t index){
if(index < 0 || index >= a->size){
fprintf(stderr, "out of range\n");
exit(-11);
}
if(a->index < index){
while(a->index < index){
Stack_push(a->front, Stack_pop(a->back));
++a->index;
}
} else if(a->index > index){
while(a->index > index){
Stack_push(a->back, Stack_pop(a->front));
--a->index;
}
}
}
Type Array_set(Array *a, size_t index, Type value){
Array_pos_set(a, index);//a->index == index
Stack_pop(a->front);
Stack_push(a->front, value);
return value;
}
Type Array_get(Array *a, size_t index){
Type value;
Array_pos_set(a, index);//a->index == index
value = Stack_pop(a->front);
Stack_push(a->front, value);
return value;
}
void Array_free(Array *a){
Stack_free(a->front);
Stack_free(a->back);
free(a);
}
int main(){
Array *a;
int i;
a = Array_make(10);
for(i=0;i<10;i++){
Array_set(a, i, i+1);//a[i] = i+1;
}
for(i=0;i<10;i++){
printf("%d\n", Array_get(a, i));// a[i];
}
Array_free(a);
return 0;
}