Searching, inserting, outputing from binary search tree. - c

How can i do above things in one single programme with multiple duplicates keys and csv. type input data file?

EDIT: assumed KEY "," DATA "\n" (no whitespace, for brevity) and appended a short sketch at the end such that the OP has a start.
I cannot repair it because I don't know the input but I can point out some of the errors you made. See comments in code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNAMELENTH 64
#define MAXDATALENTH 1465
typedef struct node {
char name[MAXNAMELENTH];
char data[MAXDATALENTH];
struct node *left;
struct node *right;
} node;
node *root;
node *search(node ** tree, char *key, int count, FILE * fp_out);
node *insertion(node * r, char *key, char *value);
void deltree(node * tree);
char *strtok_r(char *str, const char *delim, char **nextp);
int main(int argc, char *argv[])
{
node *root;
node *tmp;
FILE *fp;
FILE *outputfile;
FILE *keyfile;
FILE *fp_key;
int i;
int counter = 0;
int bufsize = MAXDATALENTH + MAXNAMELENTH;
int keyfilelen = MAXNAMELENTH;
char *keyread;
char *buffer, *saveptr;
char *line = NULL;
char *keyin = NULL;
char *valuein = NULL;
char inputkey[MAXNAMELENTH];
char *target_key = NULL;
char *keyline = NULL;
root = NULL;
/* Inserting nodes into tree */
buffer = (char *) malloc(bufsize * sizeof(char));
if (buffer == NULL) {
// use the proper macros, please
exit(EXIT_FAILURE);
}
// Check outputs! Always check outputs!
// I just assume that it has not been done here for simplicity
// and fear of posting-size limits (limit is 30k IIRC, that's a lot of code)
fp = fopen(argv[1], "r");
outputfile = fopen("outputfile.txt", "a");
// this is an infinite loop. How do you break out?
while (1) {
// fgets() returns NULL in case of EOF and error
// (yes, both, so check, e.g.: with ferror())
fgets(line, bufsize, fp);
buffer = line;
// I'm not fully sure, but I think you wanted a "=" instead of a ","
// Please switch on warnings for your compiler
keyin, strtok_r(buffer, ",", &saveptr);
// NUL delimited? Really? Are you sure strtok_r() can handle it?
valuein = strtok_r(NULL, "\0", &saveptr);
// insertion() returns a node
insertion(root, keyin, valuein);
}
/* Search node into tree */
// Wrong type: keyfile is a filepointer (FILE *), not a string (char *)
if (scanf("%s", keyfile) != EOF) {
// hu? Please switch on warnings for your compiler
keyfile = fopen(argv[4], "r");
// where's keyfile? Gone?
while ((fgets(keyline, keyfilelen, fp_key))) {
keyread = strtok_r(keyline, "\n", &saveptr);
search((&root), keyread, counter, outputfile);
}
// Please use braces, even here, thank you
if (keyline) {
free(keyline);
}
fclose(keyfile);
}
// This reads keys given as arguments at programstart,
// that's not what the teacher wanted
for (i = 3; argv[i] != NULL; i++) {
target_key = argv[i];
search((&root), target_key, counter, outputfile);
}
// This program does not read from stdin.
// Hint: stdin is also nothing more (although slightly less) than a file
// but it is already open and you don't close it
// (but it may not exist at all, so check first)
/* Deleting all nodes of tree */
deltree(root);
fclose(fp);
fclose(outputfile);
return 0;
}
node *insertion(node * r, char *key, char *value)
{
if (r == NULL) // BST is not created created
{
r = (node *) malloc(sizeof(node)); // create a new node
// insert data to new node
strcpy(r->name, key);
strcpy(r->data, value);
// make left and right childs empty
r->left = NULL;
r->right = NULL;
}
// if the data is less than node value then we must put this in left sub-tree
else if (strcmp(key, r->name) < 0) {
r->left = insertion(r->left, key, value);
}
// else this will be in the right subtree
else if (strcmp(key, r->name) > 0) {
r->right = insertion(r->right, key, value);
} else {
if (strcmp(value, r->data) > 0) {
r->left = insertion(r->left, key, value);
} else if (strcmp(value, r->data) < 0) {
r->right = insertion(r->right, key, value);
}
// what if both, name and data are equal?
}
// if you don't want to do anything with the returned
// node than don't return it. Just an int indicating error
// or something in the line
return r;
}
void deltree(node * tree)
{
if (tree) {
deltree(tree->left);
deltree(tree->right);
free(tree);
}
}
// searching does not compare the same way as inserting
node *search(node ** tree, char *key, int count, FILE * fp_out)
{
if (!(*tree)) {
return NULL;
}
if (strcmp(key, (*tree)->name) < 0) {
search(&((*tree)->left), key, count, fp_out);
count++;
} else if (strcmp(key, (*tree)->name) > 0) {
search(&((*tree)->right), key, count, fp_out);
count++;
} else if (strcmp(key, (*tree)->name) == 0) {
// won't print anything, because you return before the printing
return *tree;
fprintf(fp_out, "%s --> %s\n", key, (*tree)->data);
} else {
fprintf(fp_out, "%s --> NOTFOUND", key);
}
printf("%s --> %s\n", key, count);
// nothing to return here?
}
// Thank you for the proper reference!
// Seems to grow less and less usual these times.
/*
* public domain strtok_r() by Charlie Gordon
*
* from comp.lang.c 9/14/2007
*
* http://groups.google.com/group/comp.lang.c/msg/2ab1ecbb86646684
*
* (Declaration that it's public domain):
* http://groups.google.com/group/comp.lang.c/msg/7c7b39328fefab9c
*/
char *strtok_r(char *str, const char *delim, char **nextp)
{
char *ret;
if (str == NULL) {
str = *nextp;
}
str += strspn(str, delim);
if (*str == '\0') {
return NULL;
}
ret = str;
str += strcspn(str, delim);
if (*str) {
*str++ = '\0';
}
*nextp = str;
return ret;
}
EDIT: the sketch. Please be aware that I didn't do all of your homework, I left a bit "for the student", as the saying goes.
/*
*
* - Construct a binary search tree to store the information contained in the file specified
* in the command line argument. Each record should be stored in a separate Node.
*
* - Search the binary search tree for records, based on their keys. The keys are read in
* from stdin, i.e. from the screen.
*
* For testing, it is often convenient to create a file of keys to be searched, one per line, and redirect the input from this file.
*
* Use the UNIX operator < for redirecting input from a file.
*
* - Examples of use:
* ./yelp1 datafile outputfile then type in keys;
* or
* ./yelp1 datafile outputfile < keyfile
*
* - Your program will look up each key and output the information (the data found) to the output
* file specified by the second command line parameter.
*
* If the key is not found in the tree,you must output the word NOTFOUND.
*
* The number of key comparisons performed during both successful and unsuccessful lookups
* have to be written to stdout.
*
* - Remember that the entries in the file do not necessarily have unique keys.
* Your search must locate all keys matching the search key, and output all the data found.
*/
/*
* Tested with datafile produced by the following shellcode
*
* # KEY "," DATA
* counter=1;
* while [ $counter -le 100 ];
* do counter=$((counter + 1));
* echo $(pwgen 10 1)","$(pwgen 10 1) >> testtree.db
* done;
*
* # ten random KEY
* shuf -n10 testtree.db | sed -e 's/,[a-z]\+//g' > testtree10keys
*
* # ten random DATA
* shuf -n10 testtree.db | sed -e 's/[a-z]\+,//g' > testtree10datas
*
* Please insert doublettes manually
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// data produced has only 10 characters each (plus NUL)
#define MAXNAMELENTH 11
#define MAXDATALENTH 11
typedef struct node {
char name[MAXNAMELENTH];
char data[MAXDATALENTH];
struct node *left;
struct node *right;
} node;
node *root;
node *search(node ** tree, char *key, int *count, FILE * fp_out);
int insertion(node ** r, char *key, char *value);
void deltree(node * tree);
//char *strtok_r(char *str, const char *delim, char **nextp);
void bt_print(node * leaf);
int main(int argc, char *argv[])
{
node *root;
// node *tmp;
FILE *fp;
FILE *outputfile;
// FILE *keyfile;
// FILE *fp_key;
// int i;
int counter = 0;
int bufsize = MAXDATALENTH + MAXNAMELENTH + 2;
// int keyfilelen = MAXNAMELENTH;
// char *keyread;
char *buffer;
// char *saveptr;
// char *line = NULL;
char *keyin = NULL;
char *valuein = NULL;
// char inputkey[MAXNAMELENTH];
// char *target_key = NULL;
// char *keyline = NULL;
char *e;
int res;
char *comma;
root = NULL;
// must have at least one argument
if (argc < 2) {
fprintf(stderr, "Usage: %s datafile [< key-list]\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Inserting nodes into tree */
buffer = malloc(bufsize);
if (buffer == NULL) {
fprintf(stderr, "Malloc failed\n");
exit(EXIT_FAILURE);
}
fp = fopen(argv[1], "r");
if (fp == NULL) {
fprintf(stderr, "Opening \"%s\" for reading failed\n", argv[1]);
exit(EXIT_FAILURE);
}
outputfile = fopen("outputfile.txt", "a");
if (fp == NULL) {
fprintf(stderr, "Opening \"outputfile.txt\" for appending failed\n");
exit(EXIT_FAILURE);
}
while ((e = fgets(buffer, bufsize, fp))) {
if (e == NULL) {
if (ferror(fp)) {
// TODO: check errno for the exact kind of error
fprintf(stderr, "An eror occured during reading \"%s\"\n", argv[1]);
exit(EXIT_FAILURE);
} else if (feof(fp)) {
break;
}
}
// assuming strict KEY","DATA"\n" and without whitespace
// otherwise you need to check every step here!
// valuein points to the comma before DATA
valuein = strchr(buffer, ',');
// valuein points to DATA
valuein++;
// DATA is 10 characters large
valuein[10] = '\0';
// comma points to the comma before DATA
comma = strchr(buffer, ',');
// make *comma NUL
*comma = '\0';
keyin = buffer;
// ignoring return for now
//printf("%s,%s\n",keyin, valuein);
(void) insertion(&root, keyin, valuein);
}
bt_print(root);
// search-keys come from either stdin or get typed in.
// things typed in are also stdin
while ((res = scanf("%10s", buffer)) == 1) {
//printf("%s\n",buffer);
search(&root, buffer, &counter, outputfile);
printf("Misses for KEY \"%s\" = %d\n", buffer, counter);
counter = 0;
}
/* Deleting all nodes of tree */
deltree(root);
fclose(fp);
fclose(outputfile);
return 0;
}
void bt_print(node * leaf)
{
if (leaf) {
printf("%s,%s\n", leaf->name, leaf->data);
bt_print(leaf->left);
bt_print(leaf->right);
}
}
int insertion(node ** r, char *key, char *value)
{
if (*r == NULL) {
*r = malloc(sizeof(node));
if (r == NULL) {
return 0;
}
strcpy((*r)->name, key);
strcpy((*r)->data, value);
(*r)->left = NULL;
(*r)->right = NULL;
}
// Checks for returns omitted for clarity
else if (strcmp(key, (*r)->name) < 0) {
insertion(&(*r)->left, key, value);
}
// else this will be in the right subtree
else if (strcmp(key, (*r)->name) > 0) {
insertion(&(*r)->right, key, value);
} else {
if (strcmp(value, (*r)->data) > 0) {
insertion(&(*r)->left, key, value);
} else if (strcmp(value, (*r)->data) < 0) {
insertion(&(*r)->right, key, value);
}
// what if both, name *and* data are equal?
return 0;
}
return 1;
}
void deltree(node * tree)
{
if (tree) {
deltree(tree->left);
deltree(tree->right);
free(tree);
}
}
// search still cannot find multiple occurences of KEY
// Can you repair it?
node *search(node ** tree, char *key, int *count, FILE * fp_out)
{
node *tmp;
if (!(*tree)) {
printf("%s --> NOTFOUND\n", key);
fprintf(fp_out, "%s --> NOTFOUND", key);
return NULL;
} else {
if (strcmp(key, (*tree)->name) < 0) {
tmp = search(&((*tree)->left), key, count, fp_out);
(*count)++;
return tmp;
} else if (strcmp(key, (*tree)->name) > 0) {
tmp = search(&((*tree)->right), key, count, fp_out);
(*count)++;
return tmp;
} else {
// HINT 1: check (*tree)->left->name and (*tree)->right->name
// (recursively) and print it as long as key==name
// HINT 2: you don't need recursion, you can do it in a loop
printf("FOUND KEY %s --> DATA %s\n", key, (*tree)->data);
fprintf(fp_out, "%s --> %s\n", key, (*tree)->data);
return *tree;
}
}
}

Related

when using fread() on a partial line, how do you move to the next line?

Im using fread() and fseek() togather to gather parts of a string. I'm not using fread() on the whole line though.
I'd take the whole line but to my knowledge you cannot use fseek() on a character array correct?
`int parse(const char *f, const struct stat *flightD, int type){
//file pointer
Airport_S *Air_Pts = (Airport_S *)malloc(sizeoftype(Airport_S));
FILE *fp;
//char need[10];
char airLineFile[2];
char chkAirPt[3];
fp = fopen(f, "r");
if(type == FTW_F){ // test for 'type' of FTW_F
//check to see if the file opened successfully
if(fp == NULL)
printf("Cannot open file %s", f)
return 1;
while (!(FEOF)){
//fgets(need,10,fp)
//must return zero to parent funtion to continue tree traversal
// ?? While current dir != originally called dir?
//open the file, read it's contents and assess them
fseek(fp, 5, SEEK_SET) //set FP to right before airport code
chkAirPt = fread(chkAirPt,sizeof(char),3, fp)
fseek(fp,0,SEEK_SET);
//combine the airline abbreviation with '.txt'
airLineFile = strcat(fread(airLineFile, sizeof(char), 2, fp),".txt");
//if the struct has no values in it, populate it with this first one.
if(Air_Pts->airport == NULL){
//Set info for very first node
Air_Pts->airPt=strcpy(Air_Pts->airport, chkAirPt);
fseek(fp,0,SEEK_SET);
Air_Pts->fltInfo->airLine=airLineFile;
Air_Pts->fltInfo->next = NULL;
Air_Pts->fltInfo->prev = NULL;
Air_Pts->next = NULL;
Air_Pts->prev = NULL;
//what is the file going to do after this?
}
else if(strcmp(Air_Pts->airport, chkAirPt) == 0){
if(strcmp(Air_Pts->fltInfo->airLine, airLineFile) == 0){
Air_Pts->fltInfo->occ++;
}
else
Air_Pts->fltInfo = addAirline(Air_Pts->fltInfo);
}
// some code
return 0;
else //anything other than a file -or- FTW_D
return 1;
}
}
}`
You are working too hard. Just read and discard the data you don't need. For example:
/* Sample input line: AA43 DTW2315 ... */
/* Read first two columns of each line of a text file into a struct */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data {
char airport[32];
char flight[32];
struct data *next;
};
FILE * Fopen(const char *path, const char *mode);
void * xmalloc(size_t);
void
push(struct data **head, struct data new)
{
struct data *t = xmalloc( sizeof *t);
t->next = *head;
strncpy(t->airport, new.airport, sizeof t->airport);
strncpy(t->flight, new.flight, sizeof t->flight);
*head = t;
}
int
main(int argc, char **argv)
{
FILE *ifp = argc > 1 ? Fopen(argv[1], "r") : stdin;
struct data *head = NULL;
struct data this;
int line = 1;
int c = 0;
while( (c = fscanf(ifp, "31%s %31s", this.airport, this.flight)) == 2) {
push(&head, this);
/* Discard until the end of line */
while( (c = fgetc(ifp)) != EOF ) {
if( c == '\n') {
line += 1;
break;
}
}
}
/* Print all the records in reverse order */
for( ; head; head = head->next ) {
printf(" %s: %s\n", head->airport, head->flight);
}
return 0;
}
FILE *
Fopen(const char *path, const char *mode)
{
FILE *rv = fopen(path, mode);
if( rv == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return rv;
}
void *
xmalloc(size_t s)
{
void *rv = malloc(s);
if( rv == NULL ) {
perror("malloc");
exit(EXIT_FAILURE);
}
return rv;
}

Incorrect code to check if a word can be made of smaller given words (word break)

Incorrect code to check if a word can be made of smaller given words (word break).This is the code I wrote for the above mentioned problem, however an online judge declares it as incorrect, what could be the possible reasons? And how should I modify my code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Node structure */
typedef struct node {
int letter[26];
struct node* next[26];
int is_word;
} node;
/* Create node */
node* getnode(void) {
node* p = malloc(sizeof(node));
int i;
for (i = 0; i < 1004; i++) {
p->letter[i] = 0;
p->next[i] = NULL;
}
p->is_word = 0;
return p;
}
/* make dictionary */
void fill_dictionary(char word[], node* start) {
int len = strlen(word), i;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[word[i] % 'a'] == 0) {
temp->letter[word[i] % 'a'] = 1;
temp->next[word[i] % 'a'] = getnode();
temp = temp->next[word[i] % 'a'];
} else {
temp = temp->next[word[i] % 'a'];
}
}
temp->is_word = 1;
return;
}
int spell_check(char line[100003], node* start) {
int len = strlen(line), i, flag = 0;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[line[i] % 'a'] == 0) {
return 1;
} else {
temp = temp->next[line[i] % 'a'];
flag = 0;
if (temp->is_word == 1) {
flag = 1;
temp = start;
}
}
}
if (flag == 1) {
return 0;
} else {
return 1;
}
}
int main(void) {
int n, i, ans, m;
scanf("%d %d", &n,&m); // no. of words in dictionary
node* start = getnode();
for (i = 0; i < n; i++) {
char word[11]; // max length of dictionary word
scanf("%s", word);
fill_dictionary(word, start);
}
scanf("%d", &n); // no. of lines to be checked
for (i = 0; i < n; i++) {
char line[100003]; // max length of a line
scanf("%s", line);
ans = spell_check(line, start);
if (ans == 0) {
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}
Here's one way to to it. This compiles and runs. It displays the parsed result. It tries to read the dictionary from a file called "dictionary.text" in the current directory. You can change it to put the dictionary wherever you want. I commented it heavily to help you understand it but it has some subtle C things you may need to really think about and figure out. One bit of advice: Name everything in a program as extremely accurately for what it is/does as possible (but reasonably succinct). That will help immensely when trying to debug or figure out what you did wrong. Careless names really make code confusing and hard to debug.
Good luck!
Example:
$ gcc -o wordsplitter wordsplitter.c
$ wordsplitter xyzhellogoodbyefoodogcatpigcarwhereareyouhorse
xyz "hello" "goodbye" foo "dog" "cat" pigcar "where" "are" "you" horse
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DICTIONARY_FILEPATH "dictionary.txt"
#define MAX_WORD_SIZE 100
/*
* Error codes (usually this is put in a header file and included)
*/
#define SUCCESS 0
#define FILE_NOT_FOUND -1
#define OUT_OF_MEMORY -2
typedef struct word {
struct word *next;
char *word;
} word_t;
word_t *dictionaryListhead = NULL;
typedef struct wordsubcomponent {
struct wordsubcomponent *next;
char *text;
int isDictionaryWord;
} wordsubcomponent_t;
int
loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}
wordsubcomponent_t
*newsubcomponent() {
wordsubcomponent_t *subcomp = NULL;
if ((subcomp = calloc(sizeof(wordsubcomponent_t), 1)) != NULL) {
subcomp->text = strdup(""); // seed with empty string (instead of NULL) so we can append
} else {
fprintf(stderr, "out of memory (fatal). program exiting\n");
exit(-1);
}
return subcomp;
}
/*
* Returns an linked list of word subcomponents for the given word, split up around dictionary words
*/
wordsubcomponent_t *getWordSubcomponents(char *wordToParse, word_t *listhead) {
wordsubcomponent_t *subcomponents, *currSubcomp;
subcomponents = currSubcomp = newsubcomponent();
for (char *cp = wordToParse; cp < wordToParse + strlen(wordToParse);) { // exit when cp gets to end of word to parse.
int matchFlag = 0;
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
if (strncasecmp(cp, wordNode->word, strlen(wordNode->word)) == 0) { // prefix of cur. ptr is dict word.
if (strlen(currSubcomp->text) != 0) // Detected non-dict text in subcomp.
currSubcomp = currSubcomp->next = newsubcomponent(); // leave in list & add new subcomp for dict word.
currSubcomp->text = wordNode->word; // save dict-word in subcomp
currSubcomp->isDictionaryWord = 1;
currSubcomp = currSubcomp->next = newsubcomponent(); // dict-word in list, so get new subcomp
cp += strlen(wordNode->word); // advance cp past extracted dict-word
matchFlag = 1;
break; // break out of inner-loop
}
}
if (!matchFlag) { // No dict-word found at cp
char oneNullTerminatedLetter[2] = { *cp++, '\0' }; // put 1st ltr into NULL-terminated string & adv cp.
strcat(currSubcomp->text, oneNullTerminatedLetter); // append letter-as-string to curr subcomp
}
}
return subcomponents;
}
void
dumpDictionary(word_t *listhead) {
printf("\nList of dictionary words:\n");
printf("----------------\n");
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
printf(" %s\n", wordNode->word);
}
printf("----------------\n\n");
}
int
main(int argc, char **argv)
{
int status;
if ((status = loadDictionaryFromFile(DICTIONARY_FILEPATH, &dictionaryListhead)) < 0) {
switch(status) {
case FILE_NOT_FOUND:
fprintf(stderr, "Error accessing dictionary: %s\n", argv[0]);
break;
case OUT_OF_MEMORY:
fprintf(stderr, "Out of memory");
break;
}
return EXIT_FAILURE;
}
/*
* Load dictionary first so we can show them the list of words if they didn't
* pass in a command line argument with the word to parse.
*/
if (argc < 2) {
fprintf(stderr, "Usage: %s <word_to_parse>\n\n", argv[0]);
dumpDictionary(dictionaryListhead);
return EXIT_FAILURE;
}
wordsubcomponent_t *subcomp = getWordSubcomponents(argv[1], dictionaryListhead);
while(subcomp != NULL && strlen(subcomp->text) > 0) {
if (subcomp->isDictionaryWord)
printf("\"%s\" ", subcomp->text);
else
printf("%s ", subcomp->text);
subcomp = subcomp->next;
}
printf("\n");
return EXIT_SUCCESS;
}
#nerdist colony:
There is a resource leak in loadDictionaryFromFile. This means a file pointer was not closed when returning from this function in case of an error.
Here is a corrected copy of this function
int loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
fclose(dictionaryFile); // <-- Close the file pointer
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}

How would I read a text file in C?

I have file.txt with
123456 2,00 beer
234567 2,50 milk
345678 3,30 ice cream
I want to put this info in my dynamic two-dimensional array:
char **dataBase;
dataBase = (char**)malloc(NUM_OF_PROD * sizeof(char*));
for(i = 0; i < NUM_OF_PROD; i++){
dataBase[i] = (char*)malloc(MAX_BUFFER* sizeof(char));
}
But I don't know how. We have here 3 lines. If it was a C++, I would use getline() but in this situation I can't find a solution.
I usually use the fgets() function to a file on a line-per-line basis (provided it is a text file).
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define LINELEN 200
#define NAMELEN 40
struct PRICELIST
{
char item[NAMELEN];
float price;
unsigned int order_no;
struct PRICELIST *next;
struct PRICELIST *prev;
};
void list_print_node (struct PRICELIST *node)
{
printf ("%d %4.2f %s\n", node->order_no, node->price, node->item);
}
void list_print (struct PRICELIST *head)
{
printf ("Order # Price Item\n");
printf ("------------------------------\n");
while (head)
{
list_print_node (head);
head = head->next;
}
}
void list_delete (struct PRICELIST *head)
{
if (head)
{
/* recursive call */
list_delete (head->next);
free (head);
}
}
struct PRICELIST *list_read (char *filename)
{
FILE *file;
char line[LINELEN];
struct PRICELIST *pricelist, *node, *prev;
char *p;
size_t len;
file = fopen (filename, "r");
if (file == NULL)
{
perror (filename);
return NULL;
}
pricelist = NULL;
prev = NULL;
while (1)
{
if (fgets (line, sizeof(line), file) == NULL)
break;
/* eat the newline at the end of the buffer, be CR/CRLF agnostic .. */
len = strlen (line) - 1;
if (line[len] == '\r' || line[len] == '\n')
{
line[len] = '\0';
len --;
}
if (line[len] == '\r' || line[len] == '\n')
line[len] = '\0';
/* allocate a new node in the list */
node = malloc (sizeof (struct PRICELIST));
if (node)
{
/* now use sscanf() for getting single elements */
sscanf (line, "%d %f", &node->order_no, &node->price);
/* since the item name might contain spaces this is not so easy .. */
p = line;
while (isspace(*p)) p++;
while (isdigit(*p)) p++;
while (isspace(*p)) p++;
while (isdigit(*p)) p++;
while (ispunct(*p)) p++;
while (isdigit(*p)) p++;
while (isspace(*p)) p++;
strncpy (node->item, p, sizeof(node->item));
node->next = NULL;
/* if this is the first node of the list assign the head to it */
if (pricelist == NULL)
pricelist = node;
/* append the new node to the end of the linked list */
if (prev)
prev->next = node;
node->prev = prev;
/* save it for the next entry */
prev = node;
}
}
/* we are done with the file, close it */
fclose (file);
return pricelist;
}
/* let's test it */
int main (int argc, char *argv[])
{
struct PRICELIST *pricelist;
if (argc < 2)
{
printf ("Usage: %s filename\n", argv[0]);
return 0;
}
pricelist = list_read (argv[1]);
if (pricelist)
{
/* print the list */
printf ("This is the price list (filename '%s'):\n\n", argv[1]);
list_print (pricelist);
/* delete the list */
list_delete (pricelist);
}
return 0;
}
In the comments you mentioned you were only concerned about actually reading a file.
Here's how you'd go about reading a file (currently untested, binary mode):
#include <stdio.h>
int main()
{
FILE *file = fopen("path/to/your/file/yourfile.txt", "rb");
if(!file) return 1; //something went wrong!
long size = fseek(file, 0, SEEK_END);
char *buf = malloc(size);
fread(&buf, size, 1, file); //read all contents, once
fclose(file);
free(buf); //because this is just an example
return 0;
}
For more info on reading a file, just do a quick google search and you'll find almost everything you're looking for.
You can implement your own version of getline using fgetc and realloc.
#include <stdio.h>
#include <stdlib.h>
char *getline(FILE *file)
{
size_t size = 16; // Size of memory allocated for line
size_t len = 0; // Characters read
char *line = malloc(size);
// Return NULL if memory allocation fails
if (line == NULL)
return NULL;
for(;;) {
int c;
switch (c = fgetc(file)) {
// If End Of File is met, return the line up until this point
// if anything has been read
case EOF:
if (len == 0) {
free(line);
return NULL;
}
else {
line[len+1] = '\0';
return line;
}
case '\n':
line[len+1] = '\0'; // NUL terminate the string
return line;
default:
line[len++] = c;
}
// If the string plus NUL terminator is longer than size
// double the size of line
if (len + 1 >= size) {
size *= 2;
line = realloc(line, size);
// Return NULL if memory allocation fails
if (line == NULL)
return NULL;
}
}
}
There are also many free/open source implementations of the same function that can be found online. For instance this GPL 2 one. If you are on a POSIX system (e.g. OS X or Linux) there is already a version of getline found in stdio.h.

Printing to a file in C

How do I print to an empty .txt file I already have created?
I already print the results to the console, and now I want to print to a file named "Output.txt". I've tried a couple of things that haven't worked, but I think it was easier to create a duplicate printDictionary() specifically for printing to a file called printDictionaryToFile(). I'm a little lost on how to do it though. Can anyone correct me on where I went wrong? I already added an extra FILE type called *out for my output to a file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stddef.h>
#define PUNC " \t\n\r,;.:!()[]{}?'\""
typedef struct node node;
typedef struct node {
char *word;
int count;
node *left;
node *right;
} node;
void insert(node ** dictionary, char * word) {
int result;
node * entry;
if (word == NULL || dictionary == NULL)
return;
if (*dictionary == NULL) {
entry= (node *) malloc(sizeof(node));
strcpy( entry->word= (char *) malloc(strlen(word) + 1), word);
entry->left= entry->right= NULL;
entry->count= 1;
*dictionary= entry;
return;
}
result = strcmp(word, (*dictionary)->word);
if ( result < 0 )
insert(&(*dictionary)->left, word);
else if (result > 0)
insert(&(*dictionary)->right, word);
else
++(*dictionary)->count;
return;
}
void printDictionary(node * dictionary) {
if (dictionary == NULL)
return;
printDictionary(dictionary->left);
printf( "%s = %d\n", dictionary->word, dictionary->count);
printDictionary(dictionary->right);
return;
}
void printDictionaryToFile( node * dictionary ) {
if (dictionary == NULL)
return;
printDictionaryToFile(dictionary->left);
fprintf(out, "%s = %d\n", dictionary->word, dictionary->count);
printDictionaryToFile(dictionary->right);
return;
}
void freeDictionary( node ** dictionary ) {
if (dictionary == NULL || *dictionary == NULL)
return;
freeDictionary(&(*dictionary)->left);
freeDictionary(&(*dictionary)->right);
free((*dictionary)->word);
free(*dictionary);
*dictionary= NULL;
return;
}
int main( int argc, char *argv[] ) {
FILE *fp, *out;
out = fopen("Output.txt", "w");
char b[1000], *s;
node *dictionary= NULL;
int i;
for (i= 1; i < argc; ++i) {
if ((fp = fopen(argv[i], "r")) == NULL) {
fprintf(stderr, "File %s can not be opened.\n", argv[i]);
continue;
}
for (s = fgets(b, sizeof(b), fp); s != NULL; s = fgets(b, sizeof(b), fp)) {
char *word;
for (word= strtok(b, PUNC); word != NULL; word = strtok(NULL, PUNC))
insert(&dictionary, strlwr(word));
}
fclose(fp);
}
printDictionaryToFile(dictionary);
printDictionary(dictionary);
freeDictionary(&dictionary);
return 0;
}
You can use the fprintf() function, which is quite similar to printf() in the way it works.
Here is an example:
FILE *fp;
int myInt = 5;
fp = fopen("Output.txt", "w");// "w" means that we are going to write on this file
fprintf(fp, "This is being written in the file. This is an int variable: %d", myInt);
fclose(fp); //Don't forget to close the file when finished
The output on your file would be this:
This is being written in the file. This is an int variable: 5
Worth to mention that opening the file using w as parameter will destroy the file's content every time you open it.

Why is my dictionary not counting occurrences correctly?

I'm entering words into a binary tree and also counting the number of times they appear.
This is the text file: http://pastebin.com/FY9ZTQX6
Here is my code so far. It all happens in the insert() function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/*
Name: Marcus Lorenzana
Assignment: Final
*/
/*binary tree struct to hold left and right node
as well as the word and number of occurrences*/
typedef struct node
{
char *word;
int count;
struct node *left;
struct node *right;
}
node;
//,.:;-
int punctuation[4] = {0};
/*Function Prototypes*/
void insert(node ** dictionary, node * entry);
char* readFile(char* filename);
void printDictionary(node * tree);
void printPunctuation();
void toLower(char** word);
char *replace(char *st, char *orig, char *repl);;
int main()
{
char *word;
char* filecontents = readFile("data.txt");
FILE *fp = fopen("data.txt","r");
//create dictionary node
node *dictionary;
node *entry;
//read words and punctuation in from the text file
word = strtok (filecontents, " \n");
dictionary = NULL;
//create and add lowercase entries into the dictionary
//by calling insert function
while (word != NULL)
{
//store punctuation in it's own array of occurrences
//since there are only 4 to watch out for
if (word[0]==',') {
punctuation[0]++;
word = strtok (NULL, " \n");
} else if (word[0]=='.') {
punctuation[1]++;
word = strtok (NULL, " \n");
}
else if (word[0]==';') {
punctuation[2]++;
word = strtok (NULL, " \n");
}
else if (word[0]=='-') {
punctuation[3]++;
word = strtok (NULL, " \n");
}
else if (word[0]=='$') {
break;
}
//use binary tree to store unique words
else {
//convert word to lowercase first, so capital words
//won't have precedence
word = strlwr(word);
//create entry node and call insert with dictionary being call by reference
//so that is is mutable
entry = (node *) malloc(sizeof(node));
entry->left = entry->right = NULL;
entry->word = malloc(sizeof(char)*(strlen(word)+1));
entry->word = word;
insert(&dictionary,entry);
word = strtok (NULL, " \n");
}
}
//print the dictionary of words and their number of occurrences
printDictionary(dictionary);
//print the punctuation and their number of occurrences
printPunctuation();
//find word to be replaced
int found = 0;
char buffer[250];
char src[50] , dest[50];
while(fgets(buffer , sizeof(buffer) , fp) != NULL)
{
if(strchr(buffer , '<'))
{
found++;
break;
}
}
if(found)
{
fscanf(fp , "%s < %s" , src , dest);
}
//example of replace()
FILE *fout = fopen("newdata.txt","w");
filecontents = readFile("data.txt");
fprintf(fout,"%s",replace(filecontents,src,dest));
fclose(fout);
fclose(fp);
return 0;
}
/*inserts an entry into the dictionary in lexicographical order*/
void insert(node ** dictionary, node * entry)
{
//if there are no entries, set dictionary point
//to new one and set count to 1
if(!(*dictionary))
{
*dictionary = entry;
(*dictionary)->count=1;
return;
}
//compare word to see if it of higher
//or lower alphabetical order
int result = strcmp(entry->word,(*dictionary)->word);
//if it is lower, place on the left
if(result<0)
{
insert(&(*dictionary)->left, entry);
(*dictionary)->count=1;
}
//if it is higher, place on the right
if(result>0)
{
insert(&(*dictionary)->right, entry);
(*dictionary)->count=1;
}
//if it is equal, don't create a new entry but update the count
if(result == 0)
{
(*dictionary)->count++;
}
}
/*put file contents in string for strtok*/
char* readFile(char* filename)
{
FILE* file = fopen(filename,"r");
if(file == NULL)
{
return NULL;
}
fseek(file, 0, SEEK_END);
long int size = ftell(file);
rewind(file);
char* content = calloc(size + 1, 1);
fread(content,1,size,file);
return content;
}
/*prints the dictionary in lexicographical order
and number of occurrences for each word*/
void printDictionary(node * dictionary)
{
//traverse dictionary in lexicographical order
if(dictionary->left)
{
printDictionary(dictionary->left);
}
//print word and number of occurrences
printf("%s\n",dictionary->word);
printf("=%d\n",dictionary->count);
if(dictionary->right)
{
printDictionary(dictionary->right);
}
}
/*prints the punctuation and number of occurrences*/
void printPunctuation(){
//,.:;-
printf("\n, = %d",punctuation[0]);
printf("\n. = %d",punctuation[1]);
printf("\n; = %d",punctuation[2]);
printf("\n- = %d",punctuation[3]);
}
/*replace word*/
char *replace(char *st, char *orig, char *repl)
{
static char buffer[2000];
char *ch;
if (!(ch = strstr(st, orig)))
return st;
strncpy(buffer, st, ch-st);
buffer[ch-st] = 0;
sprintf(buffer+(ch-st), "%s%s", repl, ch+strlen(orig));
return buffer;
}
This is the output I'm getting: http://pastebin.com/8qSPQkiM
I'd start by changing this:
entry->word = malloc(sizeof(char)*(strlen(word)+1));
entry->word = word;
to this:
entry->word = malloc(sizeof(char)*(strlen(word)+1));
strcpy(entry->word, word);
As it is now, you're leaking memory and storing a stack-var pointer, which eventually is invalid. You're code has other problems, but this is likely the most immediate problem you're facing.
Next, in insert(), you're incorrectly resetting counters on intermediate nodes. This:
//if it is lower, place on the left
if(result<0)
{
insert(&(*dictionary)->left, entry);
(*dictionary)->count=1; // <=== SHOULD NOT BE HERE
}
//if it is higher, place on the right
if(result>0)
{
insert(&(*dictionary)->right, entry);
(*dictionary)->count=1; // <=== SHOULD NOT BE HERE
}
//if it is equal, don't create a new entry but update the count
if(result == 0)
{
(*dictionary)->count++;
}
should be this:
if(result<0)
{
insert(&(*dictionary)->left, entry);
}
else if (result>0)
{
insert(&(*dictionary)->right, entry);
}
else
{ // found it. update the count
(*dictionary)->count++;
}

Resources