I'm trying to create a stack using a dynamic array and I'm getting an error when I try to run the DeleteStack() function, however, if I set a breakpoint before the function and run the main program up till that point, then continue past it, it executes properly. Would someone please tell me what I'm doing wrong and why I'm seeing this behavior?
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "dynamic_array_stack.h"
int main() {
// create stack
DynArrayStack *S = CreateStack();
// fill stack
for (int i = 1; i <= 10; i++)
Push(S, i);
// try pushing past capacity, no error (realloc's)
Push(S, 42);
// top of stack
printf("Top of stack is %d\n", Top(S));
// pop all elements of stack
while (Top(S) != INT_MIN) {
printf("%d\n", Pop(S));
}
// delete stack, check pointer again
DeleteStack(S);
return 0;
}
dynamic_array_stack.h:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct dynarraystack {
int top;
int capacity;
int *array;
} DynArrayStack;
DynArrayStack* CreateStack() {
DynArrayStack* S = malloc(sizeof(DynArrayStack));
if (!S) {
printf("Error: Could not create stack.\n");
return NULL;
}
S->capacity = 1;
S->top = -1;
S->array = malloc(S->capacity * sizeof(int));
if (!S->array) {
printf("Error: could not create stack.\n");
return NULL;
}
return S;
}
int isFullStack(DynArrayStack *S) {
return (S->top == S->capacity-1);
}
void DoubleStack(DynArrayStack *S) {
S->capacity *= 2;
S->array = realloc(S->array, S->capacity);
}
void Push(DynArrayStack *S, int data) {
if (isFullStack(S))
DoubleStack(S);
S->array[++S->top] = data;
}
int isEmptyStack(DynArrayStack *S) {
return S->top == -1;
}
int Top(DynArrayStack *S) {
if(isEmptyStack(S))
return INT_MIN;
return S->array[S->top];
}
int Pop(DynArrayStack *S) {
if (isEmptyStack(S)) {
printf("Array is empty. Returning INT_MIN.\n");
return INT_MIN;
}
return S->array[S->top--];
}
void DeleteStack(DynArrayStack *S) {
if (S) {
if (S->array)
free(S->array);
free(S);
printf("Stack deleted.\n");
}
}
edit: Actually it only does not error if I set two breakpoints, one before the while loop (so I step through it manually), and another before the DeleteStack() function. Still confused though.
Related
I have tried creating a program that uses simple stack functions like push to add the contents of the statement onto a stack from where I then print out each character and then reverse the statement. I have used the '.' and '->' member access variables to change the contents of the struct based stack. Upon compiling it prints out the original statement, but after that it gives a segmentation error, saying I am attempting to dereference an uninitialised pointer. Can someone guide me as to how I should solve this problem as it isn't stating the line I have made the problem either.
#include <stdio.h>
#define MAX 1000
#define FULL (MAX - 1)
#define EMPTY -1
typedef struct stack {char s[MAX]; int top;} stack;
int top = EMPTY;
int isFull()
{
if(top == FULL)
return 1;
else
return 0;
}
int isEmpty()
{
if(top == EMPTY)
return 1;
else
return 0;
}
void reset(stack *stk)
{
stk -> top = EMPTY;
}
void push(char c, stack *stk)
{
stk -> top++;
(*stk).s[(*stk).top] = c;
}
char pop(stack *stk)
{
return (*stk).s[(*stk).top--];
}
void print(stack *stk)
{
int i;
while(1)
{
if(isEmpty())
{
printf("Stack underflow\n");
break;
}
for(i = 0; i <= top; i++)
{
printf("%c\n", (*stk).s[i]);
}
printf("\n");
return;
}
}
void reverse(stack *stk)
{
int i;
while(1)
{
if(isEmpty())
{
printf("Stack underflow\n");
break;
}
for(i = top; i >= 0; i--)
{
printf("%c", (*stk).s[i]);
}
printf("\n");
return;
}
}
char peek(const stack *stk)
{
while(1)
{
if(isEmpty())
{
printf("Stack underflow\n");
break;
}
return (*stk).s[(*stk).top];
}
}
int main()
{
stack stack_of_char;
char *str = "i am otto am i";
int i;
reset(&stack_of_char);
printf("original is: %s\n", str);
while(str[i] != '\0')
{
push(str[i++], &stack_of_char);
}
print(&stack_of_char);
reverse(&stack_of_char);
return 0;
}
There are several issues with your program. Let's begin with the global variable top. This is causing problems because on the one hand you have a stack struct responsible for maintaining a stack, and that has its own top. But then you have this global which you're not even using anywhere. It's almost like you added it to get around compiler errors that you didn't understand ;)
So let's ditch that, and fix your stack functions. I'm rearranging the parameters of the push function so that the stack is the first argument. This is a bit more conventional.
typedef struct stack {
char s[MAX];
int top;
} stack;
int isFull(stack *stk)
{
return stk->top == FULL;
}
int isEmpty(stack *stk)
{
return stk->top == EMPTY;
}
void reset(stack *stk)
{
stk->top = EMPTY;
}
void push(stack *stk, char c)
{
if (isFull(stk))
return;
stk->s[++stk->top] = c;
}
char pop(stack *stk)
{
if (isEmpty(stk))
return '\0';
return stk->s[stk->top--];
}
For the pop function, I arbitrarily return a NUL character if the stack is empty, because something must be returned. But really, you should never call this function if the stack is empty.
Let's look at your display functions now. The first thing I notice is that these are really convoluted. There is no need for that complexity. Look here:
void print(stack *stk)
{
for(int i = 0; i <= stk->top; i++)
{
printf("%c\n", stk->s[i]);
}
printf("\n");
}
void reverse(stack *stk)
{
for(int i = stk->top; i >= 0; i--)
{
printf("%c", (*stk).s[i]);
}
printf("\n");
}
char peek(const stack *stk)
{
if (isEmpty(stk))
{
printf("Stack empty!\n");
return '\0';
}
return stk->s[stk->top];
}
And so all that remains is a little tidy-up of your main function, and adjust the parameter order for push.
int main()
{
const char *str = "i am otto am i";
printf("original is: %s\n", str);
stack stack_of_char;
reset(&stack_of_char);
for (int i = 0; str[i]; i++)
{
push(&stack_of_char, str[i]);
}
print(&stack_of_char);
reverse(&stack_of_char);
}
Note also that you shouldn't really be walking over your stack with those functions. The typical way you would use a stack to reverse something is to push values onto it and then pop them off. So, you can print the string in reverse like this:
// Pop characters from stack to print in reverse
while (!isEmpty(&stack_of_char))
{
char c = pop(&stack_of_char);
putc(c, stdout);
}
putc('\n', stdout);
Without initialization, the integer will be a random value. It is the root cause of the memory access error.
You will need to initialize the variable properly. In main function, instead of
int i;,
you should use
int i = 0;.
Assume that you plan to access the value starting from index 0.
The question asks us to "Write the program by completing the main function that calls the push function at least three times, then prints out the updated stack, then calls the pop function and prints out the updated stack again."
The code tells me that the compilation failed due to the following reasons:
Line 10 | {
Which to me does not make sense. I tried removing it but it gives other errors
Additionally, the code gives a warning saying " warning: array ‘stack’ assumed to have one element" Which I have no idea what that means.
This is the code:
#include <stdio.h>
#define STACK_EMPTY '0'
#define STACK_SIZE 20
char stack[], item;
int *top, max_size;
void
push(char stack[], char item, int *top, int max_size),
{
if (*top < max_size-1)
{
--(*top);
stack[*top] = item;
}
}
char
pop (char stack[], /* input/output - the stack */
int *top) /* input/output - pointer to top of stack */
{
char item; /* value popped off the stack */
if (*top >= 0)
{
item = stack[*top];
--(*top);
}
else
{
item = STACK_EMPTY;
}
return (item);
}
int
main (void)
{
char s [STACK_SIZE];
int s_top = -1; // stack is empty
if (*top <= -1)
{
item = STACK_EMPTY;
}
return (0);
}
Issue is in how you are handling the top pointer.
you decrement the pointer i.e., --top, NOT the value pointed by it.
Also push should increment it i.e., ++top.
---Here is the corrected code ----
#include <stdio.h>
#define STACK_SIZE 20
#define STACK_EMPTY '0'
char item;
int top_idx = 0;
void
push(char *stack, char item)
{
if (top_idx < STACK_SIZE)
{
stack[top_idx] = item;
top_idx++;
}
}
char
pop (char *stack) /* input/output - pointer to top of stack */
{
char item; /* value popped off the stack */
if (top_idx >= 0)
{
top_idx--;
item = stack[top_idx];
}
else
{
item = STACK_EMPTY;
}
return (item);
}
int
main (void)
{
char s [STACK_SIZE];
push(s,'a');
push(s,'b');
printf("Pop = %c \n",pop(s));
printf("Pop = %c \n",pop(s));
return 0;
}
The error regarding "stack assumed to have one element" is because you put no number between the square brackets char stack[];. I suspect you meant
char stack[STACK_SIZE];
I am working on this code to allocate some memory and return pointer, but I am getting segmentation fault error. Please help me figure it out.
#include <stdio.h>
#include <stdlib.h>
#include "memalloc.h"
int total_holes,sizeofmemory;
void* start_of_memory;
void setup( int malloc_type, int mem_size, void* start_of_memory ) {
/**
* Fill your code here
*
**/
sizeofmemory=mem_size;
//initionlize memory
start_of_memory = (int *) malloc(mem_size*sizeof(int));
if(malloc_type==0)
{
//first of
printf("first fit");
void firstfit();
}
else if(malloc_type==1)
{
//first of
printf("best fit");
void bestfit();
}
else if(malloc_type==2)
{
//first of
printf("worst fit of");
void worstfit();
}
else if(malloc_type==3)
{
//first of
printf("Buddy system");
void buddyfit();
}
}
void *my_malloc(int size) {
/**
* Fill your code here
*
**/
//chek pointer in null or not
if((start_of_memory = malloc(size)) == NULL) {
printf("no memory reserve");
}
else{
//add more memory in void pointer
start_of_memory=start_of_memory+size;
}
return (void*)-1;
}
void my_free(void *ptr) {
/**
* Fill your code here
*
**/
free(ptr);
}
int num_free_bytes() {
/**
* Fill your code here
*
**/
//count number of free bytes i
int sum=0;
for(int i=0;i<sizeofmemory;i++)
{
if(start_of_memory+i==0)
{
sum++;
}
}
return sum;
}
int num_holes() {
/**
* Fill your code here
*
**/
// call function num_free_bytes and check free space
total_holes=num_free_bytes();
return total_holes;
}
//memalloc.h
void setup(int malloc_type, int mem_size, void* start_of_memory);
void *my_malloc(int size);
void my_free(void* ptr);
int num_free_bytes();
int num_holes();
#define FIRST_FIT 0
#define BEST_FIT 1
#define WORST_FIT 2
#define BUDDY_SYSTEM 3
The code below is possibly closer to what you want. Usually custom malloc function returns pointer to the beginning of the allocated memory not to the end of it. Your original function never returns any allocated memory but
(void *)(-1)
void *my_malloc(int size) {
void * start_of_memory;
//check pointer if null or not
if((start_of_memory = (void *)malloc(size)) == NULL) {
printf("no memory reserve");
return NULL; // no memory
}
else{
return (start_of_memory);
}
}
There really isnt much I can say here.
Here is my lexer file:
#include <ctype.h>
#include <stdio.h>
#include "vector.h"
enum TokenType
{
tok_let = -1,
tok_iden = -2,
tok_int = -3,
tok_end = -4
};
typedef struct
{
int type;
char* str_d;
int int_d;
} Token;
char* seed;
int i=0;
char next_char()
{
i++;
return seed[i-1];
}
vector* get_tokens(char* in)
{
vector *toks;
vector_new(toks);
seed = in;
char tap;
if(isalpha(tap = next_char()))
{
char* iden_str="";
iden_str += tap;
char nc;
while(isalnum((nc = next_char())))
iden_str += nc;
if(iden_str == "let")
{
Token* tp;
tp->type = tok_let;
vector_push(toks, (void*)tp);
goto out;
}
Token* tp;
tp->type = tok_iden;
tp->str_d = iden_str;
vector_push(toks, (void*)tp);
}
out:
return toks;
}
int main()
{
vector* toks;
toks = get_tokens("let");
Token* ftok = (Token*)vector_get(toks, 0);
switch(ftok->type)
{
case tok_let:
printf("Its a let\n");
break;
default:
printf("Ummm lol nup\n");
break;
}
}
And here is my vector file:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct d_vector
{
void **items;
int capacity;
int total;
} vector;
void vector_new(vector *v)
{
v->capacity = 4;
v->total = 0;
v->items = malloc(sizeof(void*)*v->capacity);
}
int vector_total(vector *v)
{
return v->total;
}
static void vector_resize(vector *v, int capacity)
{
void** items = realloc(v->items, sizeof(void*) * capacity);
if(items)
{
v->items = items;
v->capacity = capacity;
}
}
void vector_push(vector *v, void* item)
{
if(v->capacity == v->total)
vector_resize(v, v->capacity * 2);
v->items[v->total++] = item;
}
void vector_set(vector *v, int index, void* item)
{
if(index >= 0 && index < v->total)
v->items[index] = item;
}
void* vector_get(vector *v, int index)
{
if(index >= 0 && index < v->total)
return v->items[index];
return NULL;
}
void vector_remove(vector *v, int index)
{
if(index < 0 || index >= v->total)
return;
v->items[index] = NULL;
for (int i = 0; i < v->total - 1; i++) {
v->items[i] = v->items[i + 1];
v->items[i + 1] = NULL;
}
v->total--;
if (v->total > 0 && v->total == v->capacity / 4)
vector_resize(v, v->capacity / 2);
}
void vector_free(vector *v)
{
free(v->items);
}
When I run the code above, I get a Seg-Fault.
How can this be happening? Here is the output of gdb:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400656 in vector_new (v=0x1) at vector.h:14
14 v->capacity = 4;
As you can see, its segfaulting when i set the vector capacity!
But why?
It segfaults because you dereference a garbage pointer:
vector* get_tokens(char* in)
{
vector *toks;
vector_new(toks);
The variable toks is not assigned to anything meaningful, just whatever garbage value happens to be floating about. This gets passed into vector_new() which immediately dereferences it:
void vector_new(vector *v)
{
v->capacity = 4;
Then BAM! it blows up because v points nowhere appropriate.
Try mallocing a vector before making your call to vector_new() or put the malloc in vector_new() and have it return the pointer to the new vector instead. It's also a good idea to check the return value from malloc().
You might try something like:
vector *vector_new(void)
{
vector *v;
if ( (v = malloc(sizeof(*v))) == NULL ) {
/* Replace with something appropriate */
exit(EXIT_FAILURE);
}
v->capacity = 4;
v->total = 0;
if ( (v->items = malloc(sizeof(*v->items)*v->capacity)) == NULL ) {
/* Replace with something appropriate */
exit(EXIT_FAILURE);
}
return v;
}
Then change how you call it:
vector* get_tokens(char* in)
{
vector *toks;
toks = vector_new();
And for every malloc(), let there be a free(). Don't forget to clean up this allocation too or you'll leak memory:
void vector_free(vector *v)
{
free(v->items);
free(v);
}
(You defined a vector_free(), but never called it. You might want to consider doing that too.)
invalid pointer dereference happened
vector *toks;
vector_new(toks);
Should be
vector *toks = (vector*)malloc(sizeof(vector));
vector_new(toks);
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Im trying to replicate the push and pop functions using integers and an int array. However Im having trouble with finding the size of the array in the push function. How would I find the size or 'push' a new value into the array
typedef int data_t;
int
main(int argc, char **argv){
int *S, i;
S = malloc(10*sizeof(int));
S = NULL;
push(1,S);
push(3,S);
for(i = 0; S[i]; i++){
printf("%d\n",S[i]);
}
return 0;
}
void
push(data_t n,int *S ){
int size = 0, i = 0;
if (S == NULL){
S[0] = n;
}
else{
while(S[i] != NULL){
size++;
i++;
}
S[size] = n;
}
}
You first allocate an array of ten integers and assign the pointer to S. You then reassign S, making it point to NULL. That is not a valid pointer you can dereference. Dereferencing a null-pointer leads to undefined behavior.
You need to keep the size of the stack separately, and pass it along to the functions. Or use a structure containing both the pointer and the size.
I've written the below code on the fly! It seems to run good! It implements a stack management with stack overflow/underflow controls.
The main contains code to demonstrate the use of all the stack functions:
int initStack(StackType * stack, size_t numOfElement);
int freeStack(StackType * stack);
int push(StackType * stack, int value);
int mayPush(StackType *stack);
int pop(StackType * stack, int * value);
int pop2(StackType * stack);
int mayPop(StackType *stack);
StackError getError(StackType * stack);
The code uses the following basic stack operations:
stack init: sp="stack dimension".
push: stack[--sp]=value;
pop: stack[sp++]=value;
Stack overflow: (sp==0) [when we try to push a value]
Stack underflow: (sp=="stack dimension") [when we try to pop a value]
The code:
#include <stdio.h>
#include <malloc.h>
typedef enum {
NO_ERROR,
MEMORY_ERROR,
STACK_OVERFLOW,
STACK_UNDERFLOW
} StackError;
typedef struct {
int * stack;
size_t numOfElem;
size_t sp; //stack pointer
StackError err;
} StackType;
int initStack(StackType * stack, size_t numOfElement);
int freeStack(StackType * stack);
int push(StackType * stack, int value);
int mayPush(StackType *stack);
int pop(StackType * stack, int * value);
int pop2(StackType * stack);
int mayPop(StackType *stack);
StackError getError(StackType * stack);
int initStack(StackType * stack, size_t numOfElement)
{
if ( (stack->stack=malloc(sizeof(*stack->stack)*numOfElement))==NULL ) {
stack->err=MEMORY_ERROR;
return stack->err;
}
stack->err=NO_ERROR;
stack->numOfElem=numOfElement;
stack->sp=numOfElement; //The stack is void!
return stack->err;
}
int freeStack(StackType * stack)
{
if (stack->stack==NULL){
stack->err=MEMORY_ERROR;
return stack->err;
}
stack->err=NO_ERROR;
free(stack->stack);
stack->stack=NULL;
return stack->err;
}
int push(StackType * stack, int value)
{
if (stack->stack==NULL) {
stack->err=MEMORY_ERROR;
return stack->err;
}
if (!stack->sp) {
stack->err=STACK_OVERFLOW;
return stack->err;
}
stack->err=NO_ERROR;
stack->stack[--stack->sp]=value;
return stack->err;
}
int pop(StackType * stack, int * value)
{
if (stack->stack==NULL) {
stack->err=MEMORY_ERROR;
return stack->err;
}
if (stack->sp>=stack->numOfElem) {
stack->err=STACK_UNDERFLOW;
return stack->err;
}
stack->err=NO_ERROR;
*value=stack->stack[stack->sp++];
return stack->err;
}
int pop2(StackType * stack)
{
int value;
pop(stack,&value);
return value;
}
int mayPush(StackType *stack)
{
return (stack->stack!=NULL && stack->sp>0)?1:0;
}
int mayPop(StackType *stack)
{
return (stack->stack!=NULL && stack->sp<stack->numOfElem)?1:0;
}
StackError getError(StackType * stack)
{
return stack->err;
}
int main(void)
{
StackType stack;
int res,i,j;
size_t max=20;
if ( (res=initStack(&stack, max))!=NO_ERROR ) {
printf("Error: %d\n",res);
return res;
}
//Fill the stack;
printf("Pushing: ");
i=0;
while(mayPush(&stack)) {
push(&stack,++i);
printf("%d ",i);
}
puts("");
//Try to push another element into the stack
res=push(&stack,i);
if (res!=NO_ERROR) {
printf("Push error: %d\n",res);
}
//Read all the stack
printf("Popping: ");
while(mayPop(&stack)) {
printf("%d ",pop2(&stack));
}
puts("");
//Try to pop another element into the stack form 1
res=pop(&stack,&i);
if (res!=NO_ERROR) {
printf("Pop error: %d\n",res);
}
//Try to pop another element into the stack form 2
i=pop2(&stack);
res=getError(&stack);
if (res!=NO_ERROR) {
printf("Pop error: %d\n",res);
}
//Fill an half of the stack
printf("Pushing: ");
for(i=1;i<=(int)max/2;i++) {
push(&stack,i);
printf("%d ",i);
}
puts("");
//Get some value from the stack
printf("Popping: ");
for(i=1;i<=(int)max/4;i++) {
printf("%d ",pop2(&stack));
}
puts("");
//Put some value in the stack (also generates errors)
for (j=0;j<3;j++) {
printf("Pushing: ");
for(i=1;i<=(int)max/3;i++) {
printf("%d ",i*3+j);
if ( (res=push(&stack,i*3+j))!=NO_ERROR ) {
printf("Push error: %d\n",res);
}
}
puts("");
}
//Get some value from the stack (also generates errors)
printf("Popping: ");
for(i=0;i<(int)max+2;i++) {
if ( (res=pop(&stack,&j))!=NO_ERROR ) {
printf("\nPop error: %d",res);
} else {
printf("%d ",j);
}
}
puts("");
puts("Deallocating the stack!");
freeStack(&stack);
printf("Pushing: ");
if ( (res=push(&stack,415))!=NO_ERROR ) {
printf("Push error: %d\n",res);
}
puts("Re-Deallocating the stack!");
if ( (freeStack(&stack))!=NO_ERROR ) {
printf("freeStack Error: %d\n",res);
}
return 0;
}
Firstly, so glad to see that you didn't cast the result of malloc.
Your
int
main(int argc, char **argv){
Be assured that it doesn't have any side effect on the code behaviour, but as I have seen most of the people doing it this way, improves readability. should be,
int main(int argc, char **argv){
This
S = malloc(10*sizeof(int));
S = NULL;
should be
S = NULL;
S = malloc(10*sizeof(int));
I don't comprehend what you are trying through this:
for(i = 0; S[i]; i++)
May be this should be something like,
for(i = 0; i < MAX_LENGTH; i++) //MAX_LENGTH should be some integer #defined somewhere in the code
Apart from these obvious mistakes, you can actually think about adding a check to ensure that, in the while loop in the function push() you don't overrun the value of size than what s can accommodate.
Then, instead of doing
if (S == NULL){
S[0] = n;
}
in push(), I would have preferred checking if the memory is allocated after malloc. So,
S = malloc(10*sizeof(int));
if (S == NULL)
{
//Error handling supposed to be done if no memory is allocated
}
This should do what you are looking forward to:
#include <stdio.h>
#include <stdlib.h>
typedef int data_t;
int top;
void push(data_t,int*);
int pop(int*);
int
main(int argc, char **argv)
{
int *S = NULL, i;
top = -1;
S = malloc(10*sizeof(int));
if(S == NULL)
{
printf("Memory Allocation failed");
//other error handling implementation if any
}
push(1,S);
push(2,S);
push(3,S);
for(i = 0; i <= top; i++){
printf("%d\n",S[i]);
}
printf("\n Popping:\n");
pop(S);
for(i = 0; i <= top; i++){
printf("%d\n",S[i]);
}
return 0;
}
void
push(data_t n,int *S )
{
//Check if Stack is full
if (top == 10)
{
printf("Stack Full");
//other implementation
}
else
{
++top;
S[top] = n;
}
}
int
pop(int *S)
{
//Check if Stack is empty
if (top == -1)
{
printf("Stack Empty");
//other implementation
}
else
{
return S[top--];
}
}
The code is untested as I am travelling.