I made this thread a few hours ago:
Tricky Segmentation faults with BST recursion in C
Managed to figure it out after hours of trying. I've run into another snag, however. It's a weird one. Relevant code for perspective:
extern char *optarg;
extern int optind;
int c, err = 0;
char currentLine[STRING_SIZE];
char fileDirectory[STRING_SIZE];
static char usage[] = "Usage: %s [-c] [-o output_file_name] [input_file_name]\n";
while ((c = getopt(argc, argv, "co:")) != -1)
switch (c)
{
case 'c':
cflag = 1;
break;
case 'o':
oflag = 1;
// If an output file name
// was entered, copy it
// to fileDirectory
if (optarg != NULL)
{
strcpy(fileDirectory, optarg);
}
break;
default:
err = 1;
break;
}
if (err)
{
fprintf(stderr, usage, argv[0]);
exit(1);
}
// --- BST SORT CODE STARTS HERE ---
// This is the BST. As the assignment instructions
// specify, it is initially set to NULL
BST *root = NULL;
// Pointer to the mode the files
// will be opened in. Starts as
// "w" since we're opening the output file
// first
char *mode = (char*)malloc(sizeof(char*));
strcpy(mode, "w");
FILE *outFile;
outFile = fopen(fileDirectory, mode);
// Now update mode and fileDirectory so
// we can open the INPUT file
strcpy(mode, "r");
// Check if we have an input file name
// If argv[optind] isn't NULL, that means we have
// an input file name, so copy it into fileDirectory
if (argv[optind] != NULL)
{
strcpy(fileDirectory, argv[optind]);
}
FILE *inFile;
// Attempt to open the input file
//inFile = fopen(fileDirectory, mode);
fopen(fileDirectory, mode);
if (inFile != NULL)
{
// Process the file while EOF isn't
// returned
while (!feof(inFile))
{
// Get a single line (one string)
fgets(currentLine, STRING_SIZE, inFile);
// Check whether the line is an empty line
if (*currentLine != '\n')
{
// If the string isn't an empty line, call
// the insert function
root = insert(root, currentLine);
}
}
// At this point, we're done processing
// the input file, so close it
fclose(inFile);
}
// Otherwise, process user input from standard input
else
{
do
{
printf("Please enter a string (or blank line to exit): ");
// Get a single line of input from the user
fgets(currentLine, STRING_SIZE, stdin);
// If this is our first call to the
// insert function, set root to point
// to the branch created (which is
// the actual "root" of the tree)
if (root == NULL)
{
root = insert(root, currentLine);
}
// Otherwise, simply call the insert
// function on the root of the tree
else
{
insert(root, currentLine);
}
} while (caseSenStrCmp(currentLine, "\n") != 0);
}
// At this point, we've read all the input, so
// perform in-order traversal and print all the
// strings as per assignment specification
inOrderPrint(root, oflag, outFile);
// We're done, so reclaim the tree
deallocateTree(root);
// Finally, if we have an outFile, close it
if (outFile)
{
fclose(outFile);
}
}
The above is an excerpt from my main file (you can see the entire thing in my other thread if you're curious). The assignment to inFile is commented out because I'm also having trouble with that - just ignore it (I don't THINK it has anything to do with this problem)
What follows is a function that performs an in-order traversal of a binary search tree and prints the strings stored in its branches to either stdout (if the oflag isn't set or there's no output file) or an output file (if the flag IS set and an output file exists):
void inOrderPrint(BST *root, int oflag, FILE *outFile)
{
// Check if the current branch is null
if (root == NULL)
{
return;
}
// Otherwise, perform the in-order traversal
else
{
// This counter will be used in a loop
// that will print the strings in the branches
int count;
if (root->left != NULL)
{
inOrderPrint(root->left, oflag, outFile);
}
// If the oflag is set and outFile
// isn't NULL, then we can print to
// the output file
if (oflag && (outFile != NULL))
{
// Print the string as many times
// as it occurs in the tree
for (count = 0; count < root->counter; count++)
{
//fprintf(outFile, "%s\n", root->key);
fputs(root->key, outFile);
// !!! Does the fflush go here? !!!
fflush(outFile);
}
}
// Otherwise, print to stdout
else
{
// Same idea as above: print
// as many times as there are
// instances of the string in the tree
for (count = 0; count < root->counter; count++)
{
printf("%s\n", root->key);
}
}
if (root->right != NULL)
{
inOrderPrint(root->right, oflag, outFile);
}
}
}
So the problem this time (there's actually two, but I'll take care of this one first) is that when the oflag ISN'T set (that is, when I don't specify an output file) and the strings in the nodes have to be printed to stdout (the console in this case), which happens through this block of code:
else
{
// Same idea as above: print
// as many times as there are
// instances of the string in the tree
for (count = 0; count < root->counter; count++)
{
printf("%s\n", root->key);
}
}
It works beautifully - the strings print perfectly in order just like they're supposed to. However, when I try to print to an output file, which happens based on this block:
if (oflag && (outFile != NULL))
{
// Print the string as many times
// as it occurs in the tree
for (count = 0; count < root->counter; count++)
{
//fprintf(outFile, "%s\n", root->key);
fputs(root->key, outFile);
}
}
It prints garbage (ignore the commented-out fprintf statement; that was just me trying to see if using fputs instead would make a difference - it didn't). Not a lot of it, mind you.
Just a single symbol, namely this one: ø
Interestingly enough, the output file changes in size in a manner consistent with the amount of strings that get "written" to the file - the more strings in the tree that have to be written, the greater the size (as in, the amount of memory it takes up) of the output file. No matter how big the file is, though, all that's ever actually written on the file is just a single ø
I don't understand why this is, or how to fix it. The fact that printing to the console using root->key works perfectly tells me that it's probably not because the strings being written are NULL or invalid.
My only other guess is that it has something to do with the way I'm passing the pointer to the string (i.e. root->key vs *(root->key))?
createBranch() and insert() functions that create new nodes and insert them into the BST, for reference
BST* createBranch(char *keyVal)
{
// Create the new branch
BST* newBranch = (BST*)malloc(sizeof(BST));
// Allocate memory for newBranch's C-string
newBranch->key = (char*)malloc(STRING_SIZE * sizeof(char));
// Copy the user-provided string into newBranch's
// key field
strcpy(newBranch->key, keyVal);
// Set newBranch's counter value to 1. This
// will be incremented if/when other instances
// of the key are inserted into the tree
newBranch->counter = 1;
newBranch->left = NULL;
newBranch->right = NULL;
return newBranch;
}
// Adds items to the BST. Includes functionality
// to verify whether an item already exists in the tree
BST* insert(BST* root, char *key)
{
// If branch is null, call createBranch
// to make one, then return it
if (root == NULL)
{
return createBranch(key);
}
// Otherwise, check whether the key
// already exists in the tree
if (!existsInTree(root, key, cflag))
{
// If it doesn't, check whether
// the case sensitivity flag is set
if (cflag)
{
// If it is, use the case-sensitive
// string comparison function
if (caseSenStrCmp(root->key, key))
{
// If the key provided is greater
// than the string stored at the
// current branch, insert into
// right child
root->right = insert(root->right, key);
}
else
{
// Otherwise, insert into left child
root->left = insert(root->left, key);
}
}
// If it isn't, use the case-INsensitive string
// comparison function to decide where to insert
else
{
// Same logic as before
if (caseInsenStrCmp(root->key, key))
{
root->right = insert(root->right, key);
}
else
{
root->left = insert(root ->left, key);
}
}
}
return root;
}
EDIT:
I've updated the first big code block to include the rest of the main function.
@dmuir:
I do close the outFile at the end of main (check end of first big block of code in my post), but I've never used fflush or even heard of it. I took a quick look at the documentation for it and it looks like it's meant to be used after every instance of printing something to an output file so the buffer is clear for the next value to be printed?
I've included a test usage of it in my printInOrder() function (second big block of code in this post, flanked by !!!). A test run of the code with this added didn't solve the problem, unfortunately, but I'm not even sure if I used it correctly?
@Iharob Al Asimi
Apologies about the excess whitespace. I mostly do that only while I'm still putting the program together - once everything works I usually go back and trim down the comments and spaces considerably so it looks a little more like it is now.
As far as how I insert values into the tree, I've added my createBranch() and insert() functions to the post (the big block of code right above the bolded "EDIT").
I'm not so sure it's a problem with how I inserted the values or with them not being NULL-character terminated, because as I said, printing the values to the CONSOLE works perfectly fine. It's only when I try to print to a FILE that I get the single garbage character ø
@William Pursell:
Apologies about the error statement. That was put in there as a test while I was writing the getopt code, I just forgot to erase it. I've removed it for now since it has nothing to do with the problem I'm having (I think).