I am trying to implement the following functionality
It takes a line of string as input and then tokenizes them and put them in a stack and later on it prints the buffer reverse
"welcome to the den"
whould show up as
den the to welcome
the problem with what I have so far is that it stops working and after debugging I realize that in the push function called in the main , the value of the token is not getting passed to the function .
Can any one please help me with why it does not pass the string of token to the push function .
I think there is some thing wrong with "char* data;" in the struct
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// self-referential structure
struct stackNode
{
char* data;
struct stackNode *pNext;
};
typedef struct stackNode StackNode;
typedef StackNode *StackNodePtr;
// function prototypes
void push( StackNodePtr *pTop, char value );
//int pop( StackNodePtr *pTop );
//int isEmpty( StackNodePtr pTop );
void printStack( StackNodePtr pCurrent );
int main( void )
{
char *pToken = NULL;
int counter;
char input[BUFFER_SIZE];
StackNodePtr pStack = NULL;
printf("Please enter a line of text here :\n");
gets(input);
pToken = strtok(input, " ");
while(pToken != NULL)
{
push(&pStack, pToken);
printf("%p '%s'\n", pToken, pToken);
pToken = strtok(NULL, " ");
}
printf("I am out of while loop");
printStack(pStack);
return 0;
}
// Insert a node at the stack top
void push( StackNodePtr *pTop, char* value )
{
StackNodePtr pNew;
pNew = malloc( sizeof( StackNode ) );
if ( pNew != NULL )
{
pNew->data = value;
pNew->pNext = *pTop; // insert at top of stack
*pTop = pNew;
}
else
{
printf( "%d not inserted. No memory available.\n", value );
}
}
// output stack contents to the console
void printStack( StackNodePtr pCurrent )
{
if ( pCurrent == NULL )
{
printf( "The stack is empty.\n\n" );
}
else
{
printf( "The stack is:\n" );
while ( pCurrent != NULL )
{
printf( "%s", pCurrent->data );
pCurrent = pCurrent->pNext; // move to next element
}
printf( "NULL\n\n" );
}
}
This works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFER_SIZE 256
// self-referential structure
struct stackNode
{
char* data;
struct stackNode *pNext;
};
typedef struct stackNode StackNode;
typedef StackNode *StackNodePtr;
// function prototypes
void push(StackNodePtr* pTop, char* value);
//int pop( StackNodePtr *pTop );
//int isEmpty( StackNodePtr pTop );
void printStack( StackNodePtr pCurrent );
int main( void )
{
char *pToken = NULL;
int counter;
char input[BUFFER_SIZE];
StackNodePtr pStack = NULL;
printf("Please enter a line of text here :\n");
gets(input);
pToken = strtok(input, " ");
while(pToken != NULL)
{
push(&pStack, pToken);
printf("%p '%s'\n", pToken, pToken);
pToken = strtok(NULL, " ");
}
printf("I am out of while loop");
printStack(pStack);
return 0;
}
// Insert a node at the stack top
void push( StackNodePtr* pTop, char* value )
{
StackNodePtr pNew;
pNew = (StackNode*)malloc( sizeof( StackNode ) );
if ( pNew != NULL )
{
pNew->data = value;
pNew->pNext = *pTop; // insert at top of stack
*pTop = pNew;
}
else
{
printf( "%s not inserted. No memory available.\n", value );
}
}
// output stack contents to the console
void printStack( StackNodePtr pCurrent )
{
if ( pCurrent == NULL )
{
printf( "The stack is empty.\n\n" );
}
else
{
printf( "The stack is:\n" );
while ( pCurrent != NULL )
{
printf( "%s", pCurrent->data );
pCurrent = pCurrent->pNext; // move to next element
}
printf( "NULL\n\n" );
}
}
Input:
welcome to the den
Output:
0x7fff31d13fc0 'welcome'
0x7fff31d13fc8 'to'
0x7fff31d13fcb 'the'
0x7fff31d13fcf 'den'
I am out of while loopThe stack is:
denthetowelcomeNULL
I really only modified the code to compile on a reasonable machine. Just make sure you aren't printing character arrays as decimal types. I didn't fix any other issues, so no guarantees, just that THIS bit compiles and runs. I'm assuming you are going to add onto it later. Just make sure you are tracking your memory allocations.
I suspect the main problem is the mismatch between the prototype for push and it's definition.
void push( StackNodePtr *pTop, char value );
Vs
void push( StackNodePtr *pTop, char *value )
When I tried to compile the original it would not even compile, but maybe some broken would compile it and perhaps ignore the definition.
Here is a working version with the only change being to assign the declaration with the definition. Note that there are a shedload of warnings - you should address these as well.
Related
I'm still learning how linked lists works and I'm kinda struggling with the sorting using qsort algorithm and the nodes .
This is what I did so far .
So I'm having a crash somewhere in the code and I don't know if this qsort algorithm works this way with the linked lists or not.
Code Updated
void swapString(char **str1, char **str2)
{
char *temp = *str2;
*str2 = *str1;
*str1 = temp;
}
TCD *partition(TCD *Start, TCD *End, int (*cmp)(const void *, const void*))
{
TCD *partitionIdx = Start;
TCD *i ;
for (i = Start; i != End; i=i->Next)
{
if (cmp(i->Titel, End->Titel) < 0)
{
swapString(&i->Titel, &partitionIdx->Titel);
partitionIdx->Prev = partitionIdx;
partitionIdx = partitionIdx->Next;
}
}
swapString(&partitionIdx->Titel, &End->Titel);
return partitionIdx;
}
void Quicksort(TCD *Start, TCD *End, int (*cmp)(const void *, const void *))
{
if (Start !=NULL && End != Start && End!= Start->Next)
{
TCD *partitionIdx = partition(Start, End, cmp);
Quicksort(Start, partitionIdx->Prev, cmp);
Quicksort(partitionIdx->Next, End, cmp);
}
}
By the way , this is the definition of TCD
typedef struct F
{
char *Titel;
struct F *Next;
struct F *Prev;
}TCD;
There are several problems with your code:
The line partitionIdx->Prev = partitionIdx; does not make sense. It causes a node to point to itself. This cannot be correct. The purpose of a linked list is for a node to point to the next node and the previous node, but never to itself.
Your function partition is crashing because its parameter Start will sometimes point to a place in the linked list beyond the End parameter. This is because you call the function Quicksort without ensuring that its Start parameter does not point to a place beyond the End parameter.
The if condition if ( Start != NULL && End != Start && End != Start->Next ) does not make sense. The sub-expression End != Start->Next tests if the size of the partition is 2. If that is the case, the partition is not processed. However, a partition of size 2 must be sorted, so it must be processed. Only if the size is 1 should it not be processed.
I have changed the code of your algorithm by fixing the issues mentioned above, and it seems to work now. Also, I have added some functions to test the algorithm. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef struct F
{
char *Titel;
struct F *Next;
struct F *Prev;
} TCD;
void swapString( char **str1, char **str2 )
{
char *temp = *str2;
*str2 = *str1;
*str1 = temp;
}
TCD *partition( TCD *Start, TCD *End, int( *cmp )(const void *, const void*) )
{
TCD *partitionIdx = Start;
TCD *i;
for ( i = Start; i != End; i = i->Next )
{
if ( cmp( i->Titel, End->Titel ) < 0 )
{
swapString( &i->Titel, &partitionIdx->Titel );
//NOTE: I disabled the following line from the original code, as it was doing nonsense. It was causing a node to point to itself.
//partitionIdx->Prev = partitionIdx;
partitionIdx = partitionIdx->Next;
}
}
swapString( &partitionIdx->Titel, &End->Titel );
return partitionIdx;
}
void Quicksort( TCD *Start, TCD *End, int( *cmp )(const void *, const void *) )
{
//NOTE: In the following if condition, I disabled part of the original code, because a partition of two elements must be sorted
if ( Start != NULL && End != Start /*&& End != Start->Next*/ )
{
TCD *partitionIdx = partition( Start, End, cmp );
if ( Start != partitionIdx )
Quicksort( Start, partitionIdx->Prev, cmp );
if ( partitionIdx != End )
Quicksort( partitionIdx->Next, End, cmp );
}
}
// NOTE:
// The following functions are not part of the algorithm, but are only
// used to test the algorithm.
void AddToList( TCD **head, TCD **tail, char *str )
{
TCD *p;
//allocate new node and fill it with the data
p = malloc( sizeof(*p) );
assert( p != NULL );
p->Titel = str;
p->Next = NULL;
p->Prev = *tail;
//attach new node to list by updating head or next pointer
if ( *head == NULL )
*head = p;
else
(*tail)->Next = p;
//update tail pointer too
*tail = p;
}
void PrintList( FILE *stream, TCD *head )
{
TCD *p;
for ( p = head; p != NULL; p = p->Next )
{
fprintf( stream, "%s\n", p->Titel );
}
fprintf( stream, "\n" );
}
void FreeList( TCD *head )
{
TCD *p = head;
while ( p != NULL )
{
TCD *tmp = p;
p = p->Next;
free( tmp );
}
}
int main( void )
{
TCD *head = NULL, *tail = NULL;
//create linked list with a bit of unsorted test data
AddToList( &head, &tail, "string8" );
AddToList( &head, &tail, "string4" );
AddToList( &head, &tail, "string2" );
AddToList( &head, &tail, "string7" );
AddToList( &head, &tail, "string3" );
AddToList( &head, &tail, "string5" );
AddToList( &head, &tail, "string1" );
AddToList( &head, &tail, "string6" );
//print list before sorting
fprintf( stderr, "List before sort:\n" );
PrintList( stderr, head );
//do the actual sorting
Quicksort( head, tail, strcmp );
//print list after sorting
fprintf( stderr, "List after sort:\n" );
PrintList( stderr, head );
//free the linked list
FreeList( head );
return 0;
}
I implemented stack as linked list and I wanted to make function which tells if brackets are in good order for example : (()) is good ())( is bad . Logic of function isn't good right now but I don't know why pop() works only once.Here is my code(stog is stack and sljedeci is next):
struct stog {
int x;
stog *sljedeci;
};
typedef struct stog stog;
stog *top;
char pop() {
stog *temp;
temp = (stog*)malloc(sizeof(stog));
temp = top;
char n = temp->x;
top = temp->sljedeci;
top->x = temp->sljedeci->x;
free(temp);
return n;
}
void init() {
top = NULL;
}
void push(char x) {
stog *temp;
temp=(stog*)malloc(sizeof(stog));
temp->x = x;
temp->sljedeci = top;
top = temp;
}
void Brackets(const char* msg) {
char z;
for (int i = 0; i < strlen(msg); i++) {
if (msg[i] == '(') {
push('(');
}
if (msg[i]==')'){
z = pop();
printf("Bad\n");
}
}
}
int main() {
const char* msg = "(())";
init();
Brackets(msg);
return 0;
}
Output is:
Bad
It should be:
Bad
Bad
EDIT: Added init() and push() functions
This line in pop doesn't make sense:
top->x = temp->sljedeci->x;
In the prior line, you assign temp->sljedeci to top. So the x member referenced here is actually the same one on both sides, so assuming both top and temp->sljedeci are not null it does nothing. If either one is NULL, you invokes undefined behavior because you derefrence a null pointer. So get rid of this line.
You also have a memory leak here in pop:
temp = (stog*)malloc(sizeof(stog));
temp = top;
You allocate memory and assign its address to temp, but then you immediately overwrite that address with the value of top.
There's no need to allocate more memory here, so remove the malloc call.
We, beginners, should help each other.:)
I am doing your assignment the first time in my life.:)
For starters always use English words for identifiers. Otherwise a program text can be unreadable.
It is unclear why the data member x has the type int instead of char though the stack deals with characters of a string.
struct stog {
int x;
stog *sljedeci;
};
You did not show all your stack implementation nevertheless for example the function pop is invalid. It produces a memory leak.
At first you allocated memory and its address assigned to the pointer temp and at once in the next line you reassigned the pointer. So the allocated memory will not be freed.
temp = (stog*)malloc(sizeof(stog));
temp = top;
This statement
top->x = temp->sljedeci->x;
can invoke undefined behavior if top is equal to NULL.
Also in the function Brackets this if statement
if (msg[i]==')'){
z = pop();
printf("Bad\n");
}
does not make sense. The function will always output "Bad" as soon as the character ')' is encountered.
Here is a solution I have done.
#include <stdio.h>
#include <stdlib.h>
struct stack
{
char c;
struct stack *next;
};
char * top( struct stack **stack )
{
return *stack == NULL ? NULL : &( *stack )->c;
}
int push( struct stack **stack, char c )
{
struct stack *current = malloc( sizeof( struct stack ) );
int success = current != NULL;
if ( success )
{
current->c = c;
current->next = *stack;
*stack = current;
}
return success;
}
void pop( struct stack **stack )
{
if ( *stack )
{
struct stack *current = *stack;
*stack = ( *stack )->next;
free( current );
}
}
int empty( struct stack **stack )
{
return *stack == NULL;
}
void clear( struct stack **stack )
{
while ( *stack ) pop( stack );
}
int bracket_balance( const char *s )
{
struct stack *stack = NULL;
int balanced = 1;
for ( ; *s && balanced; ++s )
{
if ( *s == '(' )
{
push( &stack, *s );
}
else if ( *s == ')' )
{
if ( ( balanced = !empty( &stack ) && *top( &stack ) == '(' ) )
{
pop( &stack );
}
}
}
balanced = balanced && empty( &stack );
clear( &stack );
return balanced;
}
int main(void)
{
const char * s[] =
{
"", "(", ")", "()", ")(", "( ( ) )", "( )( )", "( ) ) (", "Hello"
};
for ( size_t i = 0; i < sizeof( s ) / sizeof( *s ); i++ )
{
if ( bracket_balance( s[i] ) )
{
printf( "\"%s\" has balanced brackets\n", s[i] );
}
else
{
printf( "\"%s\" does not have balanced brackets\n", s[i] );
}
}
return 0;
}
The program output is
"" has balanced brackets
"(" does not have balanced brackets
")" does not have balanced brackets
"()" has balanced brackets
")(" does not have balanced brackets
"( ( ) )" has balanced brackets
"( )( )" has balanced brackets
"( ) ) (" does not have balanced brackets
"Hello" has balanced brackets
i'm currently implementing a binary tree in c. After getting the code to work for inserting ints I now want the tree to be able to store any date type i.e. char etc. I'm kind of stumped about how to go about this. I've heard/seen that I can use a void* within my node struct but unsure how you then implement this with regards to inserting elements and comparing void* to see which is bigger or smaller. Any help would be very much appreciated! Thanks
#include <stdio.h>
#include <stdlib.h>
//struct for node of the binary tree
struct node
{
void *value;
struct node *p_left;
struct node *p_right;
};
//recursive function to allow users to input into the tree
void insert(void* key, struct node** leaf )
{
if( *leaf == NULL )
{
*leaf = (struct node*) malloc( sizeof( struct node ) );
(*leaf)->value = key;
(*leaf)->p_left = NULL;
(*leaf)->p_right = NULL;
printf( "\nnew node " );
}
else if( key < (*leaf)->value )
{
printf( "\ngoing left " );
insert( key, &(*leaf)->p_left );
}
else if(key > (*leaf)->value)
{
printf( "\ngoing right " );
insert( key, &(*leaf)->p_right );
}
}
int main(void)
{
struct node *p_root = NULL;
int value ; //i want value to be of any kind
printf( "\nPlease enter a value: " );
scanf( "%d", &value );
insert(value, &p_root);
return 0;
}
You should use void pointers for inserting values and then cast them to their supposed types after.
The thing is, you do not wan't to get "anything" if you know you want to compare which is bigger or smaller later. I suppose you might want to have an additional info in your node which specifies what type is the value actually.
I suppose you want to do this for practice, but in reality would you really want to compare arrays of characters with integers?
#include <stdio.h>
#include <stdlib.h>
struct node {
void *value;
struct node *p_left;
struct node *p_right;
};
typedef int (*Compare)(const void *, const void *);
void insert(void* key, struct node** leaf, Compare cmp){
if( *leaf == NULL ){
*leaf = (struct node*) malloc( sizeof( struct node ) );
(*leaf)->value = key;
(*leaf)->p_left = NULL;
(*leaf)->p_right = NULL;
printf( "\nnew node " );
} else if( cmp(key, (*leaf)->value) < 0) {
printf( "\ngoing left " );
insert( key, &(*leaf)->p_left, cmp);
} else if( cmp(key, (*leaf)->value) > 0){
printf( "\ngoing right " );
insert( key, &(*leaf)->p_right, cmp);
} else {
free(key);
}
}
int CmpInt(const int *a, const int *b){
return *a < *b ? -1 : *a > *b;
}
int *GetInteger(void){
char line[16];
printf("Please enter a value : ");
if(fgets(line, sizeof line, stdin)){
int v, *ret;
char *p;
v = strtol(line, &p, 10);
if(*p == '\n' || *p == '\0'){
int *ret = malloc(sizeof(*ret));
*ret = v;
return ret;
}
}
return NULL;
}
void print_tree(struct node *root, void (*print_func)(const void*) ){
if(root){
print_tree(root->p_left, print_func);
print_func(root->value);
print_tree(root->p_right, print_func);
}
}
void print_int(const void *p){
printf("%d ", *(int*)p);
}
int main(void){
struct node *p_root = NULL;
void *value;//int *value;
while(value = GetInteger()){//upto input EOF or invalid input
insert(value, &p_root, (Compare)CmpInt);
}
print_tree(p_root, print_int);
//release tree omit
return 0;
}
I cant understand how works AddToList, if gHeadPtr point always to the first (minimal) rating structure I understand it, but gHeadPtr not point to it, or i mistake with that? Or somebody can tell me how works AddToList? I not know what mean it last string, why we need double pointer and on what struct point gHeadPtr and when gHeadPtr point to the first (minimal) rating structure, when to the struct we just add(with max rating)
struct DVDInfo
{
char rating;
char title[ kMaxTitleLength ];
char comment[ kMaxCommentLength ];
struct DVDInfo *prev;
struct DVDInfo *next;
};
char GetCommand( void );
struct DVDInfo *ReadStruct( void );
void AddToList( struct DVDInfo *curPtr );
void ListDVDs( bool forward );
char *TrimLine( char *line );
struct DVDInfo *gHeadPtr, *gTailPtr;
int main (int argc, const char * argv[])
{
char command;
while ( (command = GetCommand() ) != 'q' )
{
switch( command )
{
case 'n':
AddToList( ReadStruct() );
break;
case 'l':
case 'r':
ListDVDs( command=='l' );
break;
}
printf( "\n----------\n" );
}
printf( "Goodbye...\n" );
return 0;
}
char GetCommand( void )
{
char buffer[ 100+1 ];
printf( "Enter command (q=quit, n=new, l=list, r=reverse list): " );
fgets( buffer, sizeof(buffer), stdin );
return *TrimLine( buffer );
}
struct DVDInfo *ReadStruct( void )
{
struct DVDInfo *infoPtr;
infoPtr = malloc( sizeof( struct DVDInfo ) );
if ( infoPtr == NULL )
{
printf( "Out of memory!!! Goodbye!\n" );
exit( 1 );
}
char buffer[ 500+1 ];
printf( "Enter DVD Title: " );
fgets( buffer, sizeof(buffer), stdin );
strlcpy( infoPtr->title, TrimLine( buffer ), sizeof(infoPtr->title) );
printf( "Enter DVD Comment: " );
fgets( buffer, sizeof(buffer), stdin );
strlcpy( infoPtr->comment, TrimLine( buffer ), sizeof(infoPtr->comment) );
int num;
do
{
printf( "Enter DVD Rating (1-10): " );
fgets( buffer, sizeof(buffer), stdin );
num = atoi( TrimLine( buffer ) );
}
while ( ( num < 1 ) || ( num > 10 ) );
infoPtr->rating = num;
return( infoPtr );
}
void AddToList( struct DVDInfo *curPtr )
{
struct DVDInfo **nextPtrPtr = &gHeadPtr;
struct DVDInfo *prevPtr = NULL;
while ( *nextPtrPtr != NULL && curPtr->rating > (*nextPtrPtr)->rating )
{
prevPtr = *nextPtrPtr;
nextPtrPtr = &(prevPtr->next);
}
curPtr->prev = prevPtr; // link to previous struct
curPtr->next = *nextPtrPtr; // link to next struct
if ( curPtr->next != NULL )
curPtr->next->prev = curPtr; // link prev of next struct to curPtr
else
gTailPtr = curPtr; // no next struct: curPtr is now the tail
*nextPtrPtr = curPtr; // link next or previous struct (or head) to curPtr
} //когда функция передах структкру, а потом получает новую, указатели сохраняются?
void ListDVDs( bool forward )
{
struct DVDInfo *curPtr = ( forward ? gHeadPtr : gTailPtr );
bool separator = false;
if ( curPtr == NULL )
{
printf( "No DVDs have been entered yet...\n" );
}
else
{
while ( curPtr != NULL )
{
if ( separator )
printf( "--------\n" );
printf( "Title: %s\n", curPtr->title );
printf( "Comment: %s\n", curPtr->comment );
printf( "Rating: %d\n", curPtr->rating );
curPtr = ( forward ? curPtr->next : curPtr->prev );
separator = true;
}
}
}
char *TrimLine( char *line )
{
size_t length = strlen( line );
while ( length > 0 && isspace( line[length-1] ))
{
line[length-1] = '\0';
length--;
}
return line + strspn( line, " \t" );
}
struct DVDInfo **nextPtrPtr = &gHeadPtr;
struct DVDInfo *prevPtr = NULL;
The nextPtrPtr is required since the programmer does not want to mess with the global Head Pointer (gHeadPtr). We are simply using this pointer to iterate through the list as using a Pointer to Pointer is better than using the Head Pointer itself for iteration.
while ( *nextPtrPtr != NULL && curPtr->rating > (*nextPtrPtr)->rating )
{
prevPtr = *nextPtrPtr;
nextPtrPtr = &(prevPtr->next);
}
The code above from AddToList deals with finding out the location where the new node should go inside the List (ie descending rating of movies).
curPtr->prev = prevPtr; // link to previous struct
curPtr->next = *nextPtrPtr; // link to next struct
Lines above are used for insertion into the Linked List.
if ( curPtr->next != NULL )
curPtr->next->prev = curPtr; // link prev of next struct to curPtr
else
gTailPtr = curPtr;
These lines above are used if the new node (curPtr) is the first node or the last node in the linked list.
struct DVDInfo **nextPtrPtr = &gHeadPtr;
...
...
*nextPtrPtr = curPtr;
The value of a double pointer is address of another pointer. For AddToList(), you need double pointer because that way the value pointed by the nextPtrPtr automatically starts with the address of the list header (gHeadPtr) and if needed, updates it. If there was no need to update the gHeadPtr, you could have easily used "struct DVDInfo *nextPtrPtr".
For AddToList(), there are two cases and we definitely need the double pointer for the first case. The first case is that if gHeadPtr is NULL and that means there is no elements in the list. For such cases, "**nextPtrPtr = &gHeadPtr" would mean that hte value of nextPtrPtr would be NULL. That is what we are checking with "*nextPtrPtr != NULL". Since it is NULL, it would skip the while loop and *nextPtrPtr would point to curPtr". Thus, gHeadPtr would start to point to curPtr. The secodn case is that if the head (gHeadPtr) is not NULL, then we would enter the while loop and the nextPtrPtr would point to the last element based on the rating criteria. Due to that the curPtr would be added as the node after the nextPtrPtr node.
To further illustrate this, let us say AddToList() used a single pointer and the gHeadPtr
was NULL (I am providing the following code, which makes nextPtrPtr a pointer for the
sake of explanation). In this case, the nextPtrPtr would point to gHeadPtr and that means, it would
take the address of gHeadPtr (let us say 0x1010). Because nextPtrPtr is NULL (you probably
should initialize gHeadPtr with NULL, btw), it would now skip the while loop and the last
statement would be executed "nextPtrPtr = curPtr;". With this, nextPtrPtr now points to curPtr (let
us say has address 0x2020) -- this way, the gHeadPtr never got updated to point to
0x2020.
/* Note: Incorrect version for the sake of explanation */
void AddToList( struct DVDInfo *curPtr ) {
struct DVDInfo *nextPtrPtr = gHeadPtr;
struct DVDInfo *prevPtr = NULL;
while (nextPtrPtr != NULL && curPtr->rating > (nextPtrPtr)->rating ) {
prevPtr = nextPtrPtr;
nextPtrPtr = prevPtr->next;
}
curPtr->prev = prevPtr; // link to previous struct
curPtr->next = nextPtrPtr; // link to next struct
if ( curPtr->next != NULL )
curPtr->next->prev = curPtr; // link prev of next struct to curPtr
else
gTailPtr = curPtr; // no next struct: curPtr is now the tail
nextPtrPtr = curPtr; // link next or previous struct (or head) to curPtr
}
so I'm having a crazy time right now reading characters off a stack. I'm storing the char as an int, so I can check for the EOF signal, but things aren't going so well. I'm new to the implementation of stacks, so things are probably just wrong somewhere. Here's my code.
I'm getting both the incorrect top character on the stack (it shows -1, which is EOF, instead of the last character entered), as well as some sort of memory error - "pointer being freed was not allocated", which references the destroyStack() function.
int main( void ) {
int *letter;
STACK *stack;
stack = createStack();
letter = (int *) malloc( sizeof( int ) );
printf("Please enter the letters, each on a new line, or to quit:\n");
while ( *letter != EOF || stackFull( stack ) ) {
*letter = getchar();
if ( *letter != '\n' && *letter != ' ' && *letter != EOF ) {
printf("Adding %c to the stack.\n", *letter);
pushStack( stack, letter );
}
}
free( letter );
printf("Stack count is %i\n", stackCount(stack));
letter = (int *) getStackTop( stack );
printf("The top char is %i\n", *letter);
destroyStack( stack );
return 0;
}
and my stack code:
typedef struct node {
void *dataPointer;
struct node *link;
} NODE;
typedef struct {
int count;
NODE *top;
} STACK;
STACK* createStack() {
STACK *stack;
stack = (STACK *) malloc( sizeof( STACK ) );
if ( stack ) {
stack->count = 0;
stack->top = NULL;
}
return stack;
}
bool pushStack( STACK *stack, void *pointerToData) {
NODE *newNode;
newNode = (NODE *) malloc( sizeof( NODE ) );
if ( !newNode ) {
return false;
}
newNode->dataPointer = pointerToData;
newNode->link = stack->top;
stack->top = newNode;
( stack->count )++;
return true;
}
void* popStack( STACK *stack ) {
void* topData;
NODE* temp;
if ( stack->count == 0 ) {
topData = NULL;
} else {
temp = stack->top;
topData = stack->top->dataPointer;
stack->top = stack->top->link;
free( temp );
( stack->count )--;
}
return topData;
}
void* getStackTop( STACK *stack ) {
if ( stack->count == 0 ) {
return NULL;
} else {
return stack->top->dataPointer;
}
}
bool stackEmpty( STACK *stack ) {
return ( stack->count == 0 );
}
bool stackFull( STACK *stack ) {
NODE *temp;
if ( ( temp = (NODE *) malloc( sizeof( *(stack->top) ) ) ) ) {
free( temp );
return false;
}
return true;
}
int stackCount( STACK *stack ) {
return ( stack->count );
}
STACK* destroyStack( STACK *stack ) {
NODE *temp;
if ( stack ) {
while ( stack->top != NULL ) {
free( stack->top->dataPointer );
temp = stack->top;
stack->top = stack->top->link;
free( temp );
}
free( stack );
}
return NULL;
}
Your problem is with letter. It's only allocated once and when you push it onto the stack, it doesn't make a copy. That's why your top data pointer is always the last thing you pushed. Then you free it and destroyStack frees it and you get another error. Since the stack functions were from your assignment, the fix is to allocate a new data pointer inside the loop every iteration and ensure that it's not freed outside of destroyStack.
Well . . . it looks like you're double-freeing the data pointer:
pushStack( stack, letter );
...
free( letter );
...
free( stack->top->dataPointer ); //(in destroyStack)
So, I would start by removing the free( letter ) line.
Look at how many int sized pieces of memory you've allocated. I think you'll need to allocate a new one for each entry you push onto the stack.