The problem I am having with my program is that I create a linked list, but when I go to print out my linked list it just prints out the last person in the list. It is supposed to print out everyone in the list. This is the only problem that I have in my program and if someone could point me in the right direction it would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define MAX_PLAYERS 9
#define MAX_STR_LEN 25
typedef struct Player_ {
char name[MAX_STR_LEN];
int number_of_hits;
int number_of_strikes;
struct Player_ *next;
} Player;
int pitch_result(void);
Player *add_player(Player *first_player, const char *name);
void destroy_team(Player *first_player);
void display_line_up(Player* first);
void readFile(Player **lineup, const char* file);
int main(int argc, char *argv[]) {
if(argc < 2){
exit(1);
}
srand(time(NULL));
int strikes = 0;
int hits = 0;
Player *lineup = NULL;
readFile(&lineup, argv[1]);
printf("\nLine up for this team is: ");
display_line_up(lineup);
printf("\n\n%s is batting \n", lineup->name);
for ( ; strikes < 3; ) {
int result = pitch_result();
if (result) {
++hits;
}
else
++strikes;
}
printf("\nScore of game was: %d\n", hits/4);
return 0;
}
void readFile(Player **lineup, const char* file){
FILE *input;
input = fopen(file, "r");
if(input == NULL){
printf("Failed to open");
}
char player[MAX_STR_LEN];
while(fscanf(input, "%s", &player) != EOF){
// printf("\n%s", player);
*lineup = add_player(*lineup, player);
}
}
int pitch_result(void) {
int result;
result = rand() % 2;
return result;
}
void destroy_team(Player *first_player){
Player *temp = first_player->next;
Player *free_player;
while (temp) {
free_player = temp;
temp = temp->next;
free(free_player->name);
free(free_player);
}
}
Player *add_player(Player *first_player, const char *name) {
Player *new_player = (Player*)malloc(sizeof(Player));
int nameLength;
nameLength = strlen(name);
// new_player->name = malloc(nameLength * sizeof(char));
new_player->next = NULL;
strncpy(new_player->name, name, nameLength);
new_player->number_of_hits = 0;
new_player->number_of_strikes = 0;
return new_player;
}
void display_line_up(Player *first){
if(first == NULL)
printf("\nThe list is empty");
else {
while(first != NULL){
printf("\n%s", first->name);
first = first->next;
}
}
}
Here is the file that I read into the program when I run it (stats.txt)
Yadier_Molina
Allen_Craig
Daniel_Descalso
Rafael_Furcal
David_Freese
Matt_Holiday
Jon_Jay
Carlos_Beltran
Matt_Adams
This is the sample output that I was given for my program
Line up for this team is:
Yadier_Molina
Allen_Craig
Daniel_Descalso
Rafael_Furcal
David_Freese
Matt_Holliday
Jon_Jay
Carlos_Beltran
Matt_Adams
Yadier_Molina is batting
Strike!
hit!
Strike!
Strike!
Score of game was: 0
Your add_player function returns a pointer to a node that contains the new player-- and has no connection to the preexisting list (the variable first_player is never even used).
Your readFile function uses this, discarding the old list each time it reads the name of a new player:
*lineup = add_player(*lineup, player);
so the resultant list contains only the last player.
As Beta said, you are not concatenating the players to the list. You can keep a pointer to the last element, which you modify from readFile:
void readFile(Player **lineup, const char* file){
Player* last = NULL;
FILE *input;
input = fopen(file, "r");
if(input == NULL){
printf("Failed to open");
}
char player[MAX_STR_LEN];
while(fscanf(input, "%s", &player) != EOF){
// printf("\n%s", player);
Player* p = add_player(player);
if (!last)
*lineup = p;
else
last->next = p;
last = p;
}
}
And the function add_player just creates a new player so, I would rename it to: create_player(const char* name)
Related
I want to insert the data in ascending order based on the partNumber.
When the function is called in main, then the node is successfully added at the first position. But on calling the function second time, there is some problem in insertion and I am unable to figure it out. When I enter the values(in second call), I get the error
Process exited after 8.277 seconds with return value 3221225477
typedef struct part {
int partNumber;
char partName[200];
int partQuantity;
struct part *nextPart;
} Part;
Part *inventory = NULL;
void insertPart();
int
main(int argc, char *argv[])
{
insertPart();
insertPart();
insertPart();
insertPart();
return 0;
}
void
insertPart()
{
Part *tempPart,
*traversePart,
*swapPart;
int counter = 0;
traversePart = inventory;
tempPart = (Part *) malloc(sizeof(Part *));
printf("Enter the Part Number\n");
scanf("%d", &(tempPart->partNumber));
getchar();
printf("Enter the Part Name\n");
fgets(tempPart->partName, 200, stdin);
printf("Enter the Part Quantity\n");
scanf("%d", &(tempPart->partQuantity));
getchar();
if (inventory == NULL) {
inventory = tempPart;
printf("Part added at the first position.\n");
}
else {
while (traversePart->nextPart->partNumber < tempPart->partNumber) {
counter++;
traversePart = traversePart->nextPart;
if (traversePart->nextPart == NULL) {
break;
}
}
if (counter == 0) {
swapPart = inventory;
inventory = tempPart;
tempPart->nextPart = swapPart;
}
else if (traversePart->nextPart == NULL) {
traversePart->nextPart = tempPart;
}
else {
swapPart = traversePart->nextPart;
traversePart->nextPart = tempPart;
tempPart->nextPart = swapPart;
}
}
printf("Element added at position : %d", counter);
}
The problem is traversePart->nextPart->partNumber traversePart->nextPart is not referring to anything or it is not holding any of the address. When you insert first value if condition is true
if (inventory == NULL) {
inventory = tempPart;
printf("Part added at the first position.\n");
}
inventory now holding the address of tempPart but while assigning values of tempPart you never assign an address to its nextvalue and it's not there because you only inserted the first value. For the second position
else{
while(traversePart->nextPart!=NULL)
{
traversePart=traversePart->nextPart;
}
if(traversePart->partNumber < tempPart->partNumber){
//here you can verify conditions
traversePart->nextPart = tempPart
}
}
You're intermixing fgets and scanf [and getchar]. Better to use just fgets and then apply strtol for numbers [or sscanf].
You're linked list code is a bit convoluted. It can be simplified.
Here's the refactored code. I've pulled some helper functions that I had lying around to do the prompting.
And, I added list printing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct part {
int partNumber;
char partName[200];
int partQuantity;
struct part *nextPart;
} Part;
Part *inventory = NULL;
void insertPart();
int getstr(char *buf,int buflen,const char *prompt);
long getnum_strtol(const char *prompt);
int
main(int argc, char **argv)
{
insertPart();
insertPart();
insertPart();
insertPart();
for (Part *cur = inventory; cur != NULL; cur = cur->nextPart)
printf("partNumber=%d partQuantity=%d partName='%s'\n",
cur->partNumber,cur->partQuantity,cur->partName);
return 0;
}
void
insertPart(void)
{
Part *tempPart;
Part *cur;
Part *prev = NULL;
int counter = 0;
#if 0
tempPart = (Part *) malloc(sizeof(Part *));
#else
tempPart = malloc(sizeof(*tempPart));
#endif
tempPart->partNumber = getnum_strtol("Enter the Part Number");
getstr(tempPart->partName,sizeof(tempPart->partName),"Enter the Part Name");
tempPart->partQuantity = getnum_strtol("Enter the Part Quantity");
tempPart->nextPart = NULL;
// find the tail/end of the list
for (cur = inventory; cur != NULL; cur = cur->nextPart) {
++counter;
// insert in sorted part order
if (cur->partNumber > tempPart->partNumber)
break;
prev = cur;
}
do {
tempPart->nextPart = cur;
// insert in the middle or end of list
if (prev != NULL) {
prev->nextPart = tempPart;
break;
}
// insert in new list or before first element of existing list
tempPart->nextPart = inventory;
inventory = tempPart;
} while (0);
printf("\nElement added at position : %d\n", counter);
}
// getstr -- get a string with prompt
// RETURNS: length or (<0 -> error)
int
getstr(char *buf,int buflen,const char *prompt)
{
char *cp;
int ret = 0;
// NOTE: usage of the error codes in errno.h is arbitrary
while (ret <= 0) {
// ensure buffer has enough space
if (buflen < 2) {
ret = -ENOMEM;
break;
}
// output prompt
if (prompt != NULL) {
printf("%s: ",prompt);
fflush(stdout);
}
// get a line
cp = fgets(buf,buflen,stdin);
// EOF
if (cp == NULL) {
ret = -ENODATA;
break;
}
// get buffer length
ret = strlen(buf);
// empty string
if (ret <= 0)
continue;
// point to last char
cp = &buf[ret - 1];
// ensure we got a newline -- if not, fgets had to chop the line (i.e.)
// the line is too long to fit in the buffer
if (*cp != '\n') {
ret = -ENOSPC;
break;
}
// strip the newline -- we are done
*cp = 0;
--ret;
}
return ret;
}
// getnum_strtol -- get number using strtol
long
getnum_strtol(const char *prompt)
{
int len;
int readflg = 1;
char *cp;
char buf[100];
long num = 0;
while (readflg) {
len = getstr(buf,sizeof(buf),prompt);
if (len < 0)
exit(1);
num = strtol(buf,&cp,10);
// ensure we got a least one digit
if (cp <= buf)
continue;
switch (*cp) {
case ' ':
case '\t':
case 0:
readflg = 0;
break;
default:
printf("getnum_strtol: not a valid number -- buffer '%s', invalid '%s'\n",
buf,cp);
break;
}
}
return num;
}
Here's the input file I used to test:
37
Hex Bolt
12
28
Machine Screw
6
23
Brad Nail
1000
27
Lock Nut
300
Here's the program output:
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 0
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 1
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 1
Enter the Part Number: Enter the Part Name: Enter the Part Quantity:
Element added at position : 2
partNumber=23 partQuantity=1000 partName='Brad Nail'
partNumber=27 partQuantity=300 partName='Lock Nut'
partNumber=28 partQuantity=6 partName='Machine Screw'
partNumber=37 partQuantity=12 partName='Hex Bolt'
Let's call this file f1.txt and it has given attributes.
Student code
name
ID
and resident structure from another file let's call f2.txt will be read with the following attributes
ID
City
and residence will be asked from keyboard.
I tried to but gett stucked at some point
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student
{
int student_code;
char name[20];
char ID[20];
};
int main()
{
FILE *input_file;
struct student input;
input_file = fopen("f1.txt", "r");
if(input_file == NULL)
{
fprintf(stderr, "\nError!\n");
exit(1);
}
while(fread(&input, sizeof(struct student), 1, input_file))
printf("student code = %d name = %s ID = %s", input.student_code,
input.name, input.ID);
fclose(input_file);
return 0;
}
I'm new at C programming
for example f1.txt file will be in the following format
f1.txt
123456 yourname 987654
564566 test 454545
Use fscanf to read the lines because you know the format
Store the values into temporary variables
Copy them into a proper data structure: if you don't know the number of students use a dynamic array or a list.
EDIT:
Arrays allow random access, on the other hand lists only allow sequential access.
Here's my attempt using lists:
typedef struct student
{
int student_code;
char name[20];
char ID[20];
struct student* next;
}student_t;
typedef struct list_s
{
int size;
student_t* head;
student_t* tail;
} list_t;
void list_push_back(list_t* l, int code, char n[20], char id[20])
{
student_t* tmp = (student_t*)calloc(1,sizeof(*tmp));
tmp->student_code = code;
strncpy(tmp->name, n, 20);
strncpy(tmp->ID, id, 20);
if (l->head == NULL)
{
l->head = tmp;
l->tail = tmp;
l->size++;
return;
}
l->tail->next = tmp;
l->size++;
}
void list_print(list_t* l)
{
student_t* it = l->head;
while (it)
{
fprintf(stdout, "%d %s %s\n", it->student_code, it->name, it->ID);
it = it->next;
}
}
int main(int argc, char* argv[])
{
FILE *input_file;
struct student input;
input_file = fopen("f1.txt", "r");
if (input_file == NULL)
{
fprintf(stderr, "\nError!\n");
exit(1);
}
list_t* list = (list_t*)calloc(1,sizeof(*list));
char tmp_name[20];
char tmp_id[20];
int tmp_code = 0;
while (fscanf(input_file, "%d %s %s", &tmp_code, tmp_name, tmp_id) != EOF)
{
list_push_back(list, tmp_code, tmp_name, tmp_id);
}
fclose(input_file);
list_print(list);
return 0;
}
To read a single record into the structure input:
fscanf( input_file, "%d %s %s", &input.student_code, input.name, input.ID )
to read a integer and two strings into the relevant members.
fscanf() returns the number of formatted fields successfully assigned, so to display all records in the file in the manner your code attempts:
while( fscanf( input_file, "%d %s %s", &input.student_code,
input.name,
input.ID ) == 3 )
{
printf( "student code = %d, name = %s, ID = %s\n", input.student_code,
input.name,
input.ID ) ;
}
I am trying to read a file test.txt via fscanf and store it in a array of struct. This is what I tried. Problem here is that fscanf is not working as it is supposed to. After reading the file, I am also trying to print it on screen, but it won't work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Item {
double value;
int unit;
char name[50];
};
int load(struct Item* item, FILE* data);
void display(struct Item item, int variableA);
int main()
{
struct Item I;
int i;
char ck;
ck = fopen("test.txt", "r");
if (ck)
{
for (i = 0; i < 3; i++)
{
load(&I, ck);
display(I, 0); //DISPLAY FUNCTION THAT READS test.txt and DISPLAYS
}
fclose(ck);
}
return 0;
}
int load(struct Item* item, FILE* data)
{
fscanf(data, "%d,%.2lf,%s\n", &(*item).unit,&(*item).value,&(*item).name);
return 0;
}
void display(struct Item item, int variableA)
{
printf("|%3d |%12.2lf| %20s |***\n", item.unit, item.value, item.name);
return;
}
This is what I have in test.txt file:
205,11.20,John Snow
336,23.40,Winter is coming
220,34.20,You know nothing
Error: Program compiles with some warnings , but I get segmentation fault when I execute the code.
Any idea why?
Output Expectation: OUTPUT should be read from test.txt file and should be displayed on to the screen.
Multiple problems in the program:
1.
char ck;
ck = fopen("test.txt", "r");
fopen returns a FILE*, not a char, use
FILE* ck = fopen(...);
2.
fscanf(data, "%d,%.2lf,%s\n", &(*item).unit,&(*item).value,&(*item).name);
always check return value of fscanf, if it is smaller than the number of fields you requested, the following call to fscanf is unlikely to do what you expect. Also, *item.unit is the same as item->unit, use item->unit because it is shorter and cleaner:
int ret = fscanf(data, "%d,%lf,", &item->unit, &item->value);
if (ret != 3) { // error }
Third, %s matches a sequence of non-white-space characters, so when fscanf reads "John", it will stop, and the next fscanf call will get to read "Snow" while expecting an integer.
So to input a string with whitespace, use fgets instead, and remember to remove the newline character in the end.
Try following:
int main(void)
{
struct Item I;
int i;
FILE* ck;
int ret;
ck = fopen("test.txt", "r");
if (ck)
{
for (i = 0; i < 3; i++)
{
ret = load(&I, ck);
if (ret < 0)
break;
display(I, 0); //DISPLAY FUNCTION THAT READS test.txt and DISPLAYS
}
fclose(ck);
}
return 0;
}
int load(struct Item* item, FILE* data)
{
int ret = fscanf(data, "%d,%lf,", &item->unit, &item->value);
if (ret != 2) {
return -1;
}
fgets(item->name, sizeof item->name, data);
item->name[strlen(item->name)-1] = '\0';
return 0;
}
void display(struct Item item, int variableA)
{
printf("|%3d |%12.2lf| %20s |***\n", item.unit, item.value, item.name);
return;
}
It outputs:
$ ./a.out
|205 | 11.20| John Snow |***
|336 | 23.40| Winter is coming |***
|220 | 34.20| You know nothing |***
You can try this different approach.
It uses:
malloc,realloc to allocate and reallocate memory for array of structs. I assumed that much larger text files with more lines will be used and this allows the array to resize when needed to accommodate more information.
strtok to parse each peice of data between , delimeters, and then store them into the array of structures.
Checks return value of pointers to avoid segmentation faults.
Uses fgets to read each line of the file into a string, from which we can parse ourselves afterwards.
This is the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAMESTRLEN 50
#define INITSIZE 3
#define MAXSIZE 100
typedef struct {
int unit;
double value;
char name[NAMESTRLEN+1];
} item_t;
typedef struct {
item_t *items;
int numlines;
} allitems_t;
allitems_t *initialize_arraystructs(void);
void print_arraystructs(allitems_t *allitems);
void read_insert_items(FILE *filestream, allitems_t *allitems);
void check_ptr(void *ptr, const char *msg);
int
main(void) {
allitems_t *allitems;
FILE *fp;
fp = fopen("test.txt", "r");
if (fp == NULL) {
fprintf(stderr, "%s\n", "Error reading file!\n");
exit(EXIT_FAILURE);
}
allitems = initialize_arraystructs();
read_insert_items(fp, allitems);
print_arraystructs(allitems);
return 0;
}
void
read_insert_items(FILE *filestream, allitems_t *allitems) {
int count = 0;
char line[MAXSIZE];
char *unit, *value, *name;
size_t numitems = INITSIZE;
allitems->items = malloc(numitems * sizeof(item_t));
check_ptr(allitems->items, "Initial Allocation");
while (fgets(line, MAXSIZE, filestream) != NULL) {
unit = strtok(line, ",");
value = strtok(NULL, ",");
name = strtok(NULL, "\n");
if (count == numitems) {
numitems *= 2;
allitems->items = realloc(allitems->items, numitems * sizeof(item_t));
check_ptr(allitems->items, "Reallocation");
}
allitems->items[count].unit = atoi(unit);
allitems->items[count].value = atof(value);
strcpy(allitems->items[count].name, name);
count++;
allitems->numlines++;
}
}
allitems_t
*initialize_arraystructs(void) {
allitems_t *allitems;
allitems = malloc(sizeof(allitems_t));
check_ptr(allitems, "Initial Allocation");
allitems->items = NULL;
allitems->numlines = 0;
return allitems;
}
void
print_arraystructs(allitems_t *allitems) {
int i;
for (i = 0; i < allitems->numlines; i++) {
printf("%d,%.2f,%s\n",
allitems->items[i].unit,
allitems->items[i].value,
allitems->items[i].name);
}
}
void
check_ptr(void *ptr, const char *msg) {
if (!ptr) {
printf("Unexpected null pointer: %s\n", msg);
exit(EXIT_FAILURE);
}
}
I'm trying to retrieve informations by many plain-text files, which will be then stored in a proper struct. To do so, I'm using a function that takes member of the struct to populate and source of the plain-text file where the informations are stored.
Posting my "test" code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct _elem
{
const char *title;
int ok;
int almost;
int nope;
int hits;
float last_rank;
};
typedef struct _elem Chapter;
Chapter *generate_array(const char *source, int *elems);
int engine_start(Chapter *elem, char *source);
int main()
{
const char path_f[100];
int elements = 0;
int i = 0;
Chapter *dict;
printf("Insert the name of the source:\n");
scanf("%s", path_f);
printf("\nGenerating dictionary, please wait...\n");
dict = generate_array(path_f, &elements);
if (dict == NULL)
{
printf("Aborting.\n");
exit(1);
}
while (i < elements)
{
printf("Element %d:\n", (i + 1));
printf("\nTitle: %s\n", dict[i].title);
printf("Ok: %10d\n", dict[i].ok);
printf("Almost: %5d\n", dict[i].almost);
printf("Nope: %8d\n", dict[i].nope);
printf("Hits: %8d\n", dict[i].hits);
printf("Rank: %8.2f\n", dict[i].last_rank);
printf("\n");
i++;
}
return EXIT_SUCCESS;
}
Chapter *generate_array(const char *source, int *elems)
{
FILE *src;
int sources;
int i = 0;
char **srcs;
Chapter *generated;
src = fopen(source, "r");
if (src == NULL)
{
printf("[!!] Error while reading file!\n");
return NULL;
}
fscanf(src, "%d", &sources);
if (sources <= 0)
{
printf("[!!] Wrong number of sources, exiting.\n");
return NULL;
}
srcs = (char **) malloc(sizeof(char *) * sources);
while (i < sources && !feof(src))
{
srcs[i] = (char *) malloc(sizeof(char) * 100);
fscanf(src, "%s", srcs[i++]);
}
fclose(src);
generated = (Chapter *) malloc(sizeof(Chapter) * i);
*elems = i;
i = 0;
while (i < *elems)
{
if(engine_start( &generated[i], srcs[i] )) i++;
else
{
printf("[!!] Error in file %s, aborting.\n", srcs[i]);
return NULL;
}
}
return generated;
}
int engine_start(Chapter *elem, char *source)
{
FILE *parser;
int done = 0;
parser = fopen(source, "r");
if (parser == NULL) printf("[!!] Error while opening %s, aborting.\n", source);
else
{
fgets(elem->title, 100, parser);
fscanf(parser, "%d %d %d %d %f", &(elem->ok), &(elem->almost),
&(elem->nope), &(elem->hits),
&(elem->last_rank) );
fclose(parser);
done = 1;
}
return done;
}
Now this is the main file where are stored paths to the other plain-text files:
lol.dat
5
lold/lol1.dat
lold/lol2.dat
lold/lol3.dat
lold/lol4.dat
lold/lol5.dat
And one example of lolX.dat:
Qual'รจ la vittoria di cristo?
3 4 5 12 44.9
I'm getting SIGSEGV after the first iteration of "engine_start", probably due to FILE *parser (but I can be totally wrong, I don't know at this point).
Someone can guide me through this problem? Thank you.
Make the following changes and try-
struct _elem
{
char *title; // allocate the memory for this.
int ok;
int almost;
int nope;
int hits;
float last_rank;
};
You need to allocate memory for element title before assigning something to it.
int engine_start(Chapter *elem, char *source)
{
FILE *parser;
int done = 0;
parser = fopen(source, "r");
if (parser == NULL) printf("[!!] Error while opening %s, aborting.\n", source);
else
{
elem->title=(char *)malloc(100); // include this line.
fgets(elem->title, 100, parser);
fscanf(parser, "%d %d %d %d %f", &(elem->ok), &(elem->almost),
&(elem->nope), &(elem->hits),
&(elem->last_rank) );
fclose(parser);
done = 1;
}
return done;
}
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++;
}