In the pop() function i am trying to change the value of the Last global variable. It works fine in the push(n) function, while in the pop() one it changes it inside the function (verifying it with prints) but then it resets to the previous value just after leaving the method. Can't get my head around it.
#include "stack.h"
#include <stdio.h>
#include <stdlib.h>
int *Stack;
int Last = -1;
void make_empty( void ){
free(Stack);
Last = -1;
Stack = NULL;
//Stack = malloc(4);
return;
}
int is_empty( void ){
if (Last == -1)
return 1;
return 0;
}
int top( void ){
if (is_empty()) {
printf("La pila è vuota");
}
return Stack[Last];
}
int pop( void ){
if (is_empty()) {
printf("La pila è vuota");
return 0;
}
int temp = Stack[Last];
printf("last: %d\n", Last);
Stack = realloc(Stack, (--Last+1)*sizeof(int));
printf("last: %d\n", Last);
return temp;
}
void push( int n ){
Stack = realloc(Stack, (++Last+1)*sizeof(int));
Stack[Last] = n;
return;
}
void print_stack( void ){
printf("last: %d\n", Last);
for (int c=0; c<=Last; c++)
printf("%d ", Stack[c]);
printf("\n");
}
You're not allocating enough space for your stack.
At the start Last is -1. Then you push an element to the stack and allocate space:
Stack = realloc(Stack, ++Last*sizeof(int));
After the increment, Last is 0. So you're allocating 0*sizeof(int) == 0 bytes. You then write to Stack[Last] which doesn't exist. This invokes undefined behavior, which in your case manifests by causing a variable to change when you don't expect.
Since Last contains the last valid index, you want to add 1 to this to get the proper number of elements to allocate:
Stack = realloc(Stack, (++Last + 1)*sizeof(int));
You make a similar mistake when popping:
Stack = realloc(Stack, --Last*sizeof(int));
You also need to add 1 here:
Stack = realloc(Stack, (--Last + 1)*sizeof(int));
The implementation of the stack contains undefined behavior.
For example initially Last is equal to -1.
int Last = -1;
then in the push operation
void push( int n ){
Stack = realloc(Stack, ++Last*sizeof(int));
Stack[Last] = n;
return;
}
there is allocated memory of the size equal to 0 because ++Last is equal to 0. You may not change the memory allocated with the size equal to 0.
A similar problem exists for the method pop. When Last is equal to 0 then in this statement
Stack = realloc(Stack, --Last*sizeof(int));
the expression --Last is equal -1 that is converted to the maximum value of the type size_t due to the type of the operand sizeof(int).
You could write for example the method push the following way
void push( int n ){
Stack = realloc(Stack, ( ++Last + 1 ) *sizeof(int));
Stack[Last] = n;
return;
}
And in the pop method you could use
if ( Last == 0 )
{
free( Stack );
Stack = NULL;
}
else
{
Stack = realloc(Stack, ( Last *sizeof(int));
}
--Last;
Pat attention to this if statement
if ( Last == 0 )
{
free( Stack );
Stack = NULL;
}
when the stack is empty all allocated memory must be freed and Stack must be set to NULL.
Related
Numbers are pushed onto the stack, you need to pop the full stack, after which, the stack in which elements less than 10 are removed. Example code when all elements of the stack are removed:
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <stdio.h>
#include <math.h>
#include <malloc.h>
struct kkk
{
float elem[15];
int top; // index of the top rlrment
};
struct kkk* st, * element; // pointers
void Init(struct kkk* st) // initialization
{
st->top = NULL;
}
void Push(struct kkk* st, float f) // push an item onto the stack
{
if (st->top < 15)
{
st->elem[st->top] = f;
st->top++;
}
else
printf("Stack full\n");
}
float Pop(struct kkk* st) // pop an item from the stack
{
float el;
if ((st->top) > 0)
{
st->top--;
el = st->elem[st->top];
return el;
}
else
{
printf("Stack is empty \n");
return 0;
}
}
float Vulychtop(struct kkk* st) // deleting the top of the stack
{
if ((st->top) > 0) {
return(st->elem[st->top - 1]);
}
else {
printf("Stack is empty!\n");
return 0;
}
}
int Gettop(struct kkk* st) // top element of the stack without delting
{
return(st->top);
}
int Isempty(struct kkk* st) // check
{
if ((st->top) == 0)
return 1;
else return 0;
}
void Vuvid(struct kkk* st) // Output of all elements
{
int i;
i = st->top;
if (Isempty(st) == 1) return;
do {
i--;
printf("%f\n", st->elem[i]);
} while (i > 0);
}
int main()
{
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
int i, n, k;
float znach;
element = (struct kkk*)malloc(sizeof(struct kkk));
Init(element);
printf("Enter the number of items in the stack \n");
scanf("%d", &n);
for (i = 0; i < n; i++) {
printf("Enter the number %d: ", i);
scanf("%f", &znach);
Push(element, znach);
}
printf("In stack %d elements \n", Gettop(element));
printf("\n");
Vuvid(element);
printf("Top element %f\n", Vulychtop(element));
do {
printf("The element to be removed %f, ", Pop(element));
printf("Items left in the stack %d \n", Gettop(element));
} while (Isempty(element) == 0);
return 0;
}
Result: https://i.stack.imgur.com/wLczr.png
I create a stack, after which I start entering numbers into it. With that, I'm fine. Next, I find the top element of the stack and pop it out. After that, I need to remove those numbers from the stack, the value of which is less than 10, and I manage to completely clear the stack one by one. Can't make a condition for this.
One approach would be to use another stack as temporary storage. In pseudo-code something like:
* create tmp-stack
* while org-stack isn't empty
* data = pop org-stack
* if (data >= 10) push data to tmp-stack
* while tmp_stack isn't empty
* data = pop tmp_stack
* push data to org-stack
* free tmp-stack
This can be implemented using the already existing function.
Better performance can be achieved by operating directly on the array holding the stacks data. Based on ideas from #SergeBallesta it may look like:
* write-index = 0;
* read-index = 0;
* while read-index < top
* if array[read-index] >= 10
* array[write-index] = array[read-index]
* write-index = write-index + 1
* read-index = read-index + 1
* top = write-index
It seems you are using an old MS compiler. For example the header <malloc.h> is not a standard C header. Instead you should use the header <stdlib.h>. Also neither declaration from the header <math.h> is used. So you may remove the inclusion of the header.
The function Gettop does not do what is written in the comment for the function
// top element of the stack without delting
Actually it returns the current value of the data member st->top that is how many elements are present in the stack.
On the other hand, the comment for the function Vulychtop
// deleting the top of the stack
is incorrect. The function does not delete an element from the stack because the value of the data member st->top is not decreased. Also such a function should not output any message. It is the function Pop that removes an element from the stack.
The function Vulychtop could be defined the following way
int Vulychtop( struct kkk *st, float *value )
{
if ( st->top != 0 ) *value = st->elem[st->top - 1];
return st->top != 0;
}
The function Pop also should not issue any message and return an element of the stack.
Also there is no great sense to declare the pointer element in the file scope. It could be declared in main.
The pointer st declared in the file scope
struct kkk* st, * element; // pointers
^^
is not used in the program.
Also there is no need to allocate an object of the type struct kkk dynamically.
You could just write in main
struct kkk element;
Init( &element );
To remove elements that are less than 10 from the original stack using the open interface of the stack you need an auxiliary stack.
For example
struct kkk st;
Init( &st );
while( !Isempty( element ) )
{
float value;
Vulychtop( element, &value ); // here I am using the function definition I showed above
if ( !( value < 10.0f ) ) Push( &st, value );
Pop( element );
}
while( !Isempty( &st ) )
{
float value;
Vulychtop( &st, &value ); // here I am using the function definition I showed above
Push( element, value );
Pop( &st );
}
You can yourself add messages in the while loops about what elements are popped, pushed or removed.
Pay attention that as you allocated an object of the type struct kkk dynamically you should free it before exiting the program
free( element );
So i created a program that makes a stack and all of its operations, using a structure called stack.
Structure:
typedef struct {
int *v; /* contents of the stack */
int cap; /* capacity of v, i.e. how many elements can fit in v */
int sz; /* number of elements currently stored in v */
} stack;
The program works fine but when i use fsantize it says that there is a buffer overflow on the heap in the Push function and i dont understand why because ive reallocated the bytes that i needed and freed the ones that i didnt need.
Program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int *v; /* contents of the stack */
int cap; /* capacity of v, i.e. how many elements can fit in v */
int sz; /* number of elements currently stored in v */
} stack;
void init(stack * s)
{
s->v = (int*) calloc(4,sizeof(int));
s->cap = 4;
s->sz = -1;
}
int is_empty(stack * s)
{
if (s->sz == -1)
return 1;
else
return 0;
}
void push(stack * s, int e)
{
if (s->sz+1 <= s->cap)
{
s->sz++;
s->v[s->sz] = e;
}
else
{
int *nv;
s->cap++;
s->sz++;
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
s->v = nv;
s->v[s->sz] = e;
}
}
int pop(stack * s)
{
if (is_empty(s) == 0)
{
int top = s->v[s->sz];
s->sz--;
return top;
}
else
{
printf("Impossible the stack isn't empty\n");
return 0;
}
}
void destroy(stack * s)
{
//frees the stack bytes that were allocated
free(s->v);
free(s);
}
int main()
{
int i;
stack *pilha = (stack*) malloc(sizeof(stack));
init(pilha);
if (is_empty(pilha) == 1)
printf("The stack is empty\n");
pop(pilha);
for (i = 0; i<=4;i++)
push(pilha,i);
push(pilha,5);
printf("The top is:%d\n",pilha->v[pilha->sz]);
if (is_empty(pilha) == 0)
printf("The stack isn't empty\n");
destroy(pilha);
return 0;
}
This line:
if (s->sz+1 <= s->cap)
contains a logical error: if s->sz+1 == s->cap you need more space. For example, if s->cap is 4 you only have space for 4 elements (indexes from 0 to 3), but in the case of s->sz == 3 you enter the if and the result is:
s->sz++; // 4
s->v[s->sz] = e; // s->v[4] overflow!
The right way to check would be if (s->sz+1 < s->cap), or even incrementing the value first:
s->sz++;
if (s->sz < s->cap) {
// ...
This:
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
s->v = nv;
Is also wrong. First, you are assuming that realloc() allocates new memory and that you need to free() the old buffer: you don't, realloc() does that for you if needed. Secondly, you are assuming that realloc() does not fail (as you are doing anywhere else in your code, malloc(), calloc(), etc). Third, you are casting the return value (again as you are doing anywhere else in your code), which you shouldn't (see Do I cast the result of malloc?).
What you should do instead is:
nv = realloc(s->v, sizeof(int)*s->cap);
if (nv == NULL) {
// Handle error, abort execution.
}
s->v = nv;
The check if (nv == NULL) should be done after every single call of malloc(), realloc() or calloc().
The function push is invalid.
This condition in the if statement
if (s->sz+1 <= s->cap)
can be a reason of undefined behavior. Let's assume for simplicity that s->cap is equal to 1. So you may push only one element without resizing the dynamically allocated array. So after pushing a new value s->sz will be equal to 0. And you may not push one more a new value without resizing the array. However the condition in the if statement will evaluate to true and you will write to memory outside the allocated array.
Also this code snippet
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
is invalid. In the case when the call of realloc was successful the memory pointed to by s->v was freed (or rreused). So the call of free again will invoke undefined behavior. That is whether there will be an attempt to free the already reallocated memory or the new allocated memory will be freed.
The function push can be defined for example the following way
int push( stack *s, int e )
{
int success = 0;
if ( ( success = s->sz+1 < s->cap ) )
{
s->v[++s->sz] = e;
}
else
{
int *nv = realloc( s->v, sizeof( int ) * ( s->cap + 1 ) );
success = nv != NULL;
if ( success )
{
s->v = nv;
++s->cap;
s->v[++s->sz] = e;
}
}
return success;
}
But in any case it would be better to set the initial value to the data member sz to 0. In this case the data member would reflect the current size of the stack.
The return value of the function pop is ambiguous. The returned value 0 can be a valid value stored in the stack. Also the function shall shall not issue any message. It is the caller of the function that will decide whether to issue a message if any or not.
Also there is no need to allocate the object itself of the type stack dynamically. It can have the automatic storage duration and be a local variable.
And it is much better when the function that initialize the stack also has a second parameter that allows to specify the capacity of the created stack instead of using the magic number 4.
Below there is a demonstrative program that shows how the stack and its functions can be defined.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int *v; /* contents of the stack */
size_t cap; /* capacity of v, i.e. how many elements can fit in v */
size_t sz; /* number of elements currently stored in v */
} stack;
int init( stack * s, size_t capacity )
{
s->sz = 0;
s->cap = 0;
s->v = calloc( capacity, sizeof( int ) );
int success = s->v != NULL;
if ( success )
{
s->cap = capacity;;
}
return success;
}
int is_empty( const stack *s )
{
return s->sz == 0;
}
int push( stack *s, int e )
{
int success = 0;
if ( ( success = s->sz < s->cap ) )
{
s->v[s->sz++] = e;
}
else
{
int *nv = realloc( s->v, sizeof( int ) * ( s->cap + 1 ) );
success = nv != NULL;
if ( success )
{
s->v = nv;
++s->cap;
s->v[s->sz++] = e;
}
}
return success;
}
int pop( stack *s, int *value )
{
int success = !is_empty( s );
if ( success )
{
*value = s->v[--s->sz];
}
return success;
}
void destroy( stack *s )
{
free( s->v );
s->v = NULL;
s->cap = 0;
s->sz = 0;
}
int main( void )
{
stack pilha;
init( &pilha, 4 );
if ( is_empty( &pilha ) )
{
printf( "The stack is empty\n" );
}
const int N = 5;
for ( int i = 0; i < 5; i++ )
{
push( &pilha, i );
}
push( &pilha, N );
while ( ! is_empty( &pilha ) )
{
int value;
pop( &pilha, &value );
printf( "the current top value is %d\n", value );
}
destroy( &pilha );
if ( is_empty( &pilha ) )
{
printf("The stack isn't empty\n");
}
return 0;
}
The program output is
The stack is empty
the current top value is 5
the current top value is 4
the current top value is 3
the current top value is 2
the current top value is 1
the current top value is 0
The stack isn't empty
Our teacher gave us homework to check for palindrome of a word using data structure "Stack".
Below is the code which I have written for the following problem: -
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <stdbool.h>
struct Stack
{
int top;
int capacity;
char *array;
};
void push(struct Stack stack, char a) //Push function.
{
stack.array[++stack.top] = a; //Helps to push charater to a stack.
}
char pop(struct Stack stack) //Pop function.
{
return stack.array[stack.top--]; //Helps to pop character from a stack.
}
int main(void)
{
struct Stack original; //Original stack where the "Original" word will be pushed.
original.top = -1;
original.capacity = 10;
original.array = calloc(original.capacity, sizeof(char));
struct Stack checker; //Another stack that "Checks" whether the word is palindrome or not.
checker.top = -1;
checker.capacity = 10;
checker.array = calloc(checker.capacity, sizeof(char));
while(getchar()!='\0') //Getting all the characters from the stdin buffer and pushing it into "Original" stack.
{
push(original, getchar());
}
while(original.top != -1)
{
push(checker,pop(original)); //Popping from "Original" stack and pushing it to "Checker" stack.
}
while(checker.top != -1)
{
original.top = checker.top;
if(original.array[original.top] != checker.array[checker.top]) //Checking every character in the stack if it is excatly same or not.
{
printf("It is not a palindrome.\n");
return EXIT_SUCCESS;
}
else
{
checker.top = checker.top - 1;
}
}
if(checker.top == -1)
{
printf("It is a palindrome.\n");
}
return 0;
}
Howsoever I am getting problem in the following line: -
while(getchar()!='\0') //Getting all the characters from the stdin buffer and pushing it into "Original" stack.
{
push(original, getchar());
}
The following loop is running infinitely. My purpose of adding the following line is that I want to add individual characters from stdin buffer and push it in the original stack until it encounters '\0'.
What have I done wrong here? Is it illegal to do it this way?
Addendum: -
Sample Input 1: -
civic
Expected Output: -
It is a palindrome.
Sample Input 2: -
madama
Expected Output: -
It is not a palindrome.
P.S.
The following code: -
while(getchar()!='\0') //Getting all the characters from the stdin buffer and pushing it into "Original" stack.
{
push(original, getchar());
}
has now been replaced with: -
int c;
int i = 0;
while ( i < original.capacity && ( c = getchar() ) != EOF && c != '\n' )
{
push(original, c );
++i;
}
And is now working perfectly, howsoever now, for every word, my code is giving the output: -
It is a palindrome.
Where have I applied the concept of stack incorrectly?
This loop
while(getchar()!='\0') //Getting all the characters from the stdin buffer and pushing it into "Original" stack.
{
push(original, getchar());
}
is in any case wrong because it reads characters twice: in the condition of the loop and within the body of the loop.
And you have explicitly to enter 0 using for example keypad.
What you need is the following
int c;
int i = 0;
while ( i < original.capacity && ( c = getchar() ) != EOF && c != '\n' )
{
push(original, c );
++i;
}
Also there is one more problem. These functions deal with a copy of the passed arguments.
void push(struct Stack stack, char a) //Push function.
{
stack.array[++stack.top] = a; //Helps to push charater to a stack.
}
char pop(struct Stack stack) //Pop function.
{
return stack.array[stack.top--]; //Helps to pop character from a stack.
}
You have to declare them like
void push(struct Stack *stack, char a) //Push function.
{
stack-?array[++stack->top] = a; //Helps to push charater to a stack.
}
char pop(struct Stack *stack) //Pop function.
{
return stack->array[stack->top--]; //Helps to pop character from a stack.
}
That is to pass the original stack by reference through pointer.
And call these functions as for example
push( &original, c );
Otherwise the data member top will not be changed.
Here is your updated program
# include <stdio.h>
# include <stdlib.h>
struct Stack
{
int top;
int capacity;
char *array;
};
void push(struct Stack *stack, char a) //Push function.
{
stack->array[++stack->top] = a; //Helps to push charater to a stack.
}
char pop(struct Stack *stack) //Pop function.
{
return stack->array[stack->top--]; //Helps to pop character from a stack.
}
int main(void)
{
struct Stack original; //Original stack where the "Original" word will be pushed.
original.top = -1;
original.capacity = 10;
original.array = calloc(original.capacity, sizeof(char));
struct Stack checker; //Another stack that "Checks" whether the word is palindrome or not.
checker.top = -1;
checker.capacity = 10;
checker.array = calloc(checker.capacity, sizeof(char));
int c;
int i = 0;
while ( i < original.capacity && ( c = getchar() ) != EOF && c != '\n' )
{
push( &original, c );
++i;
}
while(original.top != -1)
{
push(&checker,pop(&original)); //Popping from "Original" stack and pushing it to "Checker" stack.
}
while(checker.top != -1)
{
original.top = checker.top;
if(original.array[original.top] != checker.array[checker.top]) //Checking every character in the stack if it is excatly same or not.
{
printf("It is not a palindrome.\n");
return EXIT_SUCCESS;
}
else
{
checker.top = checker.top - 1;
}
}
if(checker.top == -1)
{
printf("It is a palindrome.\n");
}
return 0;
}
Take into account that these headers
#include <string.h>
#include <stdbool.h>
are redundant.
I'm working on a homework assignment and I need to basically create a character buffer. One of the functions I need to create is called "b_reset". It's purpose is to reinitialize the given buffer so that it will point to the first position in the char buffer. This is needed because later on, when a new char is added to the buffer, it needs to be added to the first position in the buffer.
This is the code I have thus far:
The struct:
typedef struct BufferDescriptor {
char * ca_head ;
int capacity ;
char inc_factor;
int addc_offset ;
int mark_offset ;
char r_flag;
char mode;
} Buffer ;
The code:
int b_reset ( Buffer *pB )
{
Buffer *temp = NULL;
int i = 0;
int j = 1;
if (pB == NULL)
{
return R_FAIL_1;
}
else
{
temp = (Buffer*)malloc(sizeof(Buffer*));
if (temp == NULL)
{
return R_FAIL_1;
}
temp->ca_head = (char*)malloc(pB->capacity);
if (!temp->ca_head)
{
temp = NULL;
return R_FAIL_1;
}
for(i = 0;i < ca_getsize(pB);++i)
{
temp->ca_head[j] = pB->ca_head[i];
j++;
}
pB->ca_head = temp->ca_head;
//free(temp->ca_head);
//free(temp);
return 0;
}
}
My goal in this code was to create a temporary buffer that would basically shift over everything 1 time based on the actual given buffer. This would make the first position empty so another char could be added.
The problem I'm running into is that the original buffer doesn't seem to be returning the right values after I reset it.
When I do this for example:
temp->ca_head[0] = 'a';
temp->ca_head[1] = 'b';
temp->ca_head[2] = 'c';
temp->ca_head[3] = 'd';
temp->ca_head[4] = 'e';
b_reset(temp); //this will return the size as 0, when it's actually 5
//temp->ca_head[0] = 'i'; //if this is executed, it returns the size as 6
//and prints out the right values, but if it's not,
//it will not print out anything
printf("%d", ca_getsize(temp));
for(i = 0;i < ca_getsize(temp);++i)
{
printf("%c", temp->ca_head[i]);
}
I know something is going wrong here, but I'm not too sure what. Any suggestions would be greatly appreciated.
This code is based on your followup comment:
well I'm not trying to resize the buffer, I just want to create an
empty space in the first position, so basically shifting everything to
the right 1 time. The assumption is that there is a enough space in
the buffer to handle this process.
I don't think you need to do any malloc() ing beyond the initial one. You can just shift everything up in a loop:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define R_FAIL_1 1
#define BUFFER_SIZE 10
typedef struct BufferDescriptor {
char * ca_head ;
int capacity ;
char inc_factor;
int addc_offset ;
int mark_offset ;
char r_flag;
char mode;
} Buffer ;
void allocate_buffer(Buffer *pB, int size)
{
pB->ca_head = malloc(size);
assert(pB->ca_head);
pB->capacity = size;
}
int ca_getsize( Buffer *pB)
{
return pB->capacity;
}
int b_reset ( Buffer *pB )
{
int i = 0;
if (pB == NULL)
{
return R_FAIL_1;
}
else
{
if ( ca_getsize(pB) <= 0 || pB->ca_head == NULL )
return R_FAIL_1;
}
// shift data up by 1 byte
for( i = ca_getsize(pB) - 1 ; i > 0;i-- )
{
pB->ca_head[i] = pB->ca_head[i-1];
}
pB->ca_head[0] = '\0';
return 0;
}
void print_buffer(Buffer *pB)
{
printf("capacity: %d \n", ca_getsize(pB));
for (int i = 0;i < ca_getsize(pB);++i)
{
printf("buffer(%d): [%d] ",i, pB->ca_head[i]);
}
printf("\n");
}
int main(void)
{
Buffer a_buffer;
allocate_buffer(&a_buffer,BUFFER_SIZE);
strcpy(a_buffer.ca_head,"abcdefgh");
print_buffer(&a_buffer);
int ret = b_reset(&a_buffer);
assert(ret == 0);
print_buffer(&a_buffer);
}
temp = (Buffer*)malloc(sizeof(Buffer*));
You need to allocate enough space to hold a Buffer, but you only allocate enough space to hold a pointer to a buffer. This should be:
temp = (Buffer*)malloc(sizeof(Buffer));
You are managing your memory incorrectly. You are allocating memory for a new Buffer struct when actually you only need to handle the memory of the ca_head member (if my interpretation of your homework problem is correct).
Each time you invoke b_reset, you will allocate memory for this struct that will not be released. If you don't handle your memory correctly, you will experience unexpected results as the one you are reporting in your question.
I suggest you to make a research on the function realloc and use it properly in your b_reset function.
Good luck with your homework.
I've implemented a stack in C, using a stackADT struct and a set of functions:
#ifndef _stack_h
#define _stack_h
// Macros
#define MaxStackSize 100
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// The type of element that may
// be stored in the stack
typedef int stackElementT;
// The stackADT represents the abstract type used to store
// the elements that have been pushed
typedef struct stackCDT
{
// A pointer to an array of elements
stackElementT* elements;
// Number of elements on the stack
int count;
// Number of elements we can push onto
// the stack before having to resize
int size;
}* stackADT;
// This function allocates and returns a new stack, which is
// initially empty... AKA - The Constructor
stackADT NewStack(void)
{
// The stack to return
stackADT stack;
// Instanitate a new stack
stack = (stackCDT*)(malloc(sizeof(stackCDT)));
// Start with 0 elements of course
stack->count = 0;
// Allocate memory for 50 integers
stack->elements = (stackElementT*)(malloc(50*sizeof(stackElementT)));
// Establish the size of the stack
stack->size = 50;
return stack;
}
/********* GETTER FUNCTIONS *********/
// Returns the number of elements currently pushed
// onto the stack
int StackDepth(stackADT stack)
{
return (stack->count);
}
// This function returns the element a the specified index in
// the stack, where the top is defined as index 0
stackElementT GetStackElement(stackADT stack, int index);
// Function to print contents of stack
void PrintStack(stackADT stack)
{
int i = 0;
printf("count = %d\nsize = %d\n",stack->count,stack->size);
for(i = (stack->count - 1); i >= 0; i--)
{
if((i%10 == 0) && (i != 0))
printf("\n");
printf("%d\t",*(stack->elements + i));
}
}
// Functions to determine if stack is empty or full
int StackIsEmpty(stackADT stack)
{
if(stack->count == 0)
return 1;
else
return 0;
}
int StackIsFull(stackADT stack)
{
if(stack->count == stack->size)
return 1;
else
return 0;
}
// This function pushes the specified element onto the stack
void Push(stackADT stack, stackElementT element)
{
// A temporary array that we may use later on
stackElementT* temp = NULL;
int oldCount = stack->count;
int i = 0;
// If the stack if full we need to do a
// a transfer, resize, and retransfer, then push
if(StackIsFull(stack))
{
// temp will be the same size as the old stack
temp = (stackElementT*)(malloc((oldCount)*sizeof(stackElementT)));
// Now we perform the transfer
for(i = 0; i < oldCount; i++)
{
*(temp + i) = *((stack->elements) + i);
}
// Free the old memory
free(stack->elements);
stack->elements = NULL;
// Recreate the stack with a 50% increase in size/capacity
stack->elements = (stackElementT*)(malloc((3*oldCount/2)*sizeof(stackElementT)));
// Re-establish the size
stack->size = 3*oldCount/2;
// Now we perform the transfer back
for(i = 0; i < oldCount; i++)
{
*((stack->elements) + i) = *(temp + i);
}
// Free the temp array and
// remove dangling pointer
free(temp);
temp = NULL;
// Now we push the element onto the stack
*((stack->elements) + oldCount) = element;
// Increase the count
stack->count = oldCount + 1;
}
// If the stack isn't full
else
{
*((stack->elements) + oldCount) = element;
stack->count = oldCount + 1;
}
}
// This function pops the top element from the stack and returns
// that value
stackElementT Pop(stackADT stack);
// This function frees the storage associated with the stack
void FreeStack(stackADT stack)
{
// Start by freeing the elements on the stack
// and remove dangling pointers
free(stack->elements);
stack->elements = NULL;
// Finally free the stack
free(stack);
stack = NULL;
}
#endif
Obviously I'm not completely finished (needs a pop function). My concern is with the bottom function (FreeStack). I tested the code below as such:
#include <stdio.h>
#include <stdlib.h>
#include "Stack.h"
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
int main(void)
{
stackADT stack;
int i = 0;
stack = NewStack();
PrintStack(stack);
for(i = 0; i < 60; i++)
{
Push(stack,i);
}
PrintStack(stack);
FreeStack(stack);
_CrtDumpMemoryLeaks();
return 0;
}
The _CrtDumpMemoryLeaks() function is for Visual Studio and it indicates if there is a memory leak. Apparently I've sealed off any leaks when calling the FreeStack(stackADT stack) function. However, the stack pointer still holds a memory address, which is the issue because the FreeStack function is supposed to free the memory pointed to by the stack variable and set it equal to NULL. This occurs within the function, but when I return to the main function during debugging, I see the memory address still there. What is it I'm missing here? If I'm able to release the memory, why can't I remove the dangling pointer?
You pass the stack to the function by value, instead of by address, modify the function to receive (stackADT *) and you'll be good to go.
Clarification: as Christian commented, the function call, and the use of stack will have to be changed as well of course (since now it's a pointer to pointer...)
You're passing that stackADT object (pointer) by value in your pop method:
void FreeStack(stackADT stack)
So stack refers to the local copy of that pointer. When you set that pointer = NULL, you modify it only within FreeStack. The main method has its own copy of said pointer, not pointing to NULL.