I'm trying to implement a stack that is read from a data file, without using arrays. I have all the file codes, I'm just modifying the main tester code.
This was given as a step.. but I'm not sure what he's asking, besides removing all of the array codes:
"4. Edit the tester code to read in the data from the file you create. You must remove all code dealing with an array and update the code to read in the data and place it directly in the stack using only stack functions. You cannot hardcode the number of lines you read in from the file nor can you change any code in the stack. How you do this is the challenge. "
The text file (StackData.txt) will have the following data (both the number and taskname):
1 task1
2 task2A
7 task3A
9 task2B
3 task4A
2 task4B
6 task3B
This is what I have so far:
// printf support
#include <stdio.h>
// stack callable routines
#include "Stack.h"
// UserData definition for making and getting stack data
#include "UserData.h"
// local functions
// PrintStackItem is a local function that we can call to print out a message (msg) and
// a UserData item. So we can see how many things are allocated as we proceed,
// it will also print out the number of things allocated
static void PrintStackItem (char msg[], UserData D);
// PrintAllocations is a local function that will print out a message (msg) and the
// current global AllocationCount
static void PrintAllocations (char msg[]);
int main(int argc, const char * argv[]) {
FILE* in = fopen("StackData.txt", "r");
int fscanf(FILE *in, char txt[50]);
if (in == NULL) {
printf("File not found.");
return 1;
}
// Show the allocation count when we start
PrintAllocations ("On startup");
// create a stack ans see the effect of on the number of allocations
Stack S = initStack();
PrintAllocations ("After initStack called");
// push the data on the stack, showing the data and allocations
for (int loop = 0; loop < in; loop++)
{
UserData D = FILE *in[loop];
push (S, D);
PrintStackItem("push called, data is", D);
}
// pop and print the stack content
// peek at the data before popping it so we can see what peek yields
while (!empty(S))
{
PrintStackItem ("peek called, data is", peek(S));
PrintStackItem ("pop called, data is", pop(S));
}
// delete the stack and see the effect on the allocations
PrintAllocations ("Before deleteStack called");
S = deleteStack(S);
PrintAllocations ("After deleteStack called");
return 0;
}
/*
PrintStackData prints out the received message and the data in UserData
*/
void PrintStackItem (char msg[], UserData D)
{
printf ("%s %d, #allocations is %d\n", msg, D.num, AllocationCount);
}
/*
PrintAllocations prints out the received message and the current allocation count
The allocation count is global AllocationCount
*/
void PrintAllocations (char msg[])
{
printf ("%s, #allocations is %d\n", msg, AllocationCount);
return;
}
This is the code for Stack:
#ifndef Stack_h
#define Stack_h
// The calls on a stack need to pass or return UserData
#include "UserData.h"
// Our stack will use a linked list, so we need to resolve LLInfoPtr
#include "LinkedList.h"
// The stack empty() call returns a boolean
#include <stdbool.h>
// This is the layout of a stack. Notice that it contains
// a pointer to our underlying linked list and a simple boolean
// to indicate if our stack is empty (true) or not empty (false)
typedef struct {
LLInfoPtr LL;
bool empty;
} StackInfo, *Stack;
// initStack() allocates a stack and initializes it
Stack initStack();
// empty() returns the boolean for the Stack S (true is empty, false
is not empty)
bool empty(Stack S);
// push() places the UserData on the top of the stack
void push (Stack S, UserData D);
// pop() returns the UserData on the top of the stack and deletes
// the data from the stack
UserData pop (Stack S);
// peep() returns the UserData on the top of the stack but will not
// delete it from the stack
UserData peek (Stack S);
// deleteStack() deletes the frees the storage that was allocated by
the call
// to initStack()
Stack deleteStack(Stack S);
#endif /* Stack_h */
This is the code for UserData:
#ifndef USERDATA_H_INCLUDED
#define USERDATA_H_INCLUDED
// The UserData struct defines what each node in the LL
// contains.
// User data in each node contains an integer
typedef struct {
int num;
} UserData, *UserDataPtr;
#endif // USERDATA_H_INCLUDED
This is the code for Linkedlist:
#ifndef LINKEDLIST_H_INCLUDED
#define LINKEDLIST_H_INCLUDED
// The LL functions use UserData
#include "UserData.h"
// The Linked List needs the definition of what a Node is. A Node has
// UserData and linkage information for both "next and "prev"
// for a doubly linked list).
typedef struct node
{
UserData Data;
struct node *next;
struct node *prev;
} Node, *NodePtr;
// A LL Information block contains Head and Tail pointers to a LL
// For speed, it also contains a running count of the number of nodes
// currently in the LL started at Head and finishing at Tail.
// Head is used when adding or removing from the LL front,
// Tail is needed only when adding to the end of the LL
typedef struct {
NodePtr Head;
NodePtr Tail;
int NumNodesInList;
} LLInfo, *LLInfoPtr;
// Verifying allocation / deallocation of dynamic memory is done through
// AllocationCount. The variable is declared in LinkedList.c and is linked to
// through the extern
extern int AllocationCount;
// ShouldDelete is an enum that has two valid values called DELETE_NODE
// and RETAIN_NODE that are used in calling to get user data from the front
// of the LL
typedef int ShouldDelete;
enum ShouldDelete {DELETE_NODE=1, RETAIN_NODE=2};
// declarations for LL callable functions follow
// LL_Init allocates a LL Information structure, initializing Head, Tail and NumNodesInList
// and returning the address of the structure
LLInfoPtr LL_Init ();
// LL_Delete frees up the LL Information structure
LLInfoPtr LL_Delete (LLInfoPtr LLI_Ptr);
// LL_AddAtFront adds user data to the front of the underlying LL accessed through
// the LL Information struct
void LL_AddAtFront (LLInfoPtr LLI_Ptr, UserData theData);
// LL_AddAtEnd adds user data to the Tail of the underlying LL accessed through the
// LL information struct
void LL_AddAtEnd (LLInfoPtr LLI_Ptr, UserData theData);
// LL_GetFront returns the user data currently at the Head of the underlying LL and
//, optionally removes the user data from the LL
UserData LL_GetFront (LLInfoPtr LLI_Ptr, ShouldDelete Choice);
// LL_Length returns the number of nodes in the underlying LL
int LL_Length (LLInfoPtr LLI_Ptr);
// LL_GetAtIndex returns the node at the specified index starting at 0
UserData LL_GetAtIndex (LLInfoPtr, int FetchIndex);
// LL_SetAtIndex updates the node at the specified index starting at 0
void LL_SetAtIndex (LLInfoPtr LLI_Ptr, UserData D, int UpdateIndex);
// LL_Swap swaps the nodes in the underlying LL specified by indices starting at 0
void LL_Swap (LLInfoPtr LLI_Ptr, int Index1, int Index2);
#endif // LINKEDLIST_H_INCLUDED
I didn't get an output..but here are the errors:
The original snippet of code that you shared was missing definitions of UserData and Stack, all the functions (initStack()
, deleteStack()
, push()
, peek()
, pop()
, empty()
) so this is probably the best we can do to help you:
for (int loop = 0; loop < in; loop++)
{
UserData D = FILE *in[loop];
push (S, D);
PrintStackItem("push called, data is", D);
}
should probably be something like:
for(;;) {
UserData D;
int rv = fscanf(in, "%d%*s", &D.num); // %*s will discard the string as you you don't seem to have a place to store it in your UserData.
if(rv != 1)
break;
push (S, D);
PrintStackItem("push called, data is", D);
}
PrintStackItem()
and PrintAllocations()
declarations and instead moved main()
the bottom of your file.Here's the minimal required for your original code to compile:
#include <stdio.h>
int AllocationCount = 0;
typedef struct {
} Stack;
typedef struct {
int num;
} UserData;
Stack initStack() {
return (Stack) {};
}
Stack deleteStack(Stack S) {
return (Stack) {};
}
void push(Stack S, UserData D) {
}
UserData peek(Stack S) {
return (UserData) { 0 };
}
UserData pop(Stack S) {
return (UserData) { 0 };
}
int empty(Stack S) {
return 1;
}
void PrintStackItem (char msg[], UserData D) {
printf ("%s %d, #allocations is %d\n", msg, D.num, AllocationCount);
}
void PrintAllocations (char msg[]) {
printf ("%s, #allocations is %d\n", msg, AllocationCount);
return;
}
int main(int argc, const char * argv[]) {
FILE* in = fopen("StackData.txt", "r");
if (!in) {
printf("File not found.");
return 1;
}
PrintAllocations ("On startup");
Stack S = initStack();
PrintAllocations ("After initStack called");
for (;;) {
UserData D;
int rv = fscanf(in, "%d%*s", &D.num);
if(rv != 2)
break;
push (S, D);
PrintStackItem("push called, data is", D);
}
while (!empty(S)) {
PrintStackItem ("peek called, data is", peek(S));
PrintStackItem ("pop called, data is", pop(S));
}
PrintAllocations ("Before deleteStack called");
deleteStack(S);
PrintAllocations ("After deleteStack called");
}
and here is resulting output:
On startup, #allocations is 0
After initStack called, #allocations is 0
push called, data is 1, #allocations is 0
push called, data is 2, #allocations is 0
push called, data is 7, #allocations is 0
push called, data is 9, #allocations is 0
push called, data is 3, #allocations is 0
push called, data is 2, #allocations is 0
push called, data is 6, #allocations is 0
Before deleteStack called, #allocations is 0
After deleteStack called, #allocations is 0
Once you remove those dummy functions it should work more or less.