So everything in my program works except for the main itself. The program is supposed to take in a file provided through standard input and print out the descending order of words followed by the frequency that they occur. I can do this individually line for line but am having trouble putting it together as a whole to count all the lines and not just one specific line. Here is my code:

blade71(382)% cat test.c
#include <stdio.h>
#include <string.h>

#define MAX_WORD_LENGTH    31
#define MAX_TEXT_LENGTH 10000
#define TRUE                1
#define FALSE               0
#define BUFSIZE 100

/* Structure defining a count of the occurrences of a given word */
struct WordCounter
{
 char *word;
 int word_count;
 struct WordCounter *pNext;  /* Pointer to the next word counter in the list */
};

      /* Function prototypes */
void addWord(char *pWord);
/* Adds a word to the list or updates exisiting word */
int is_separator(char ch);
/* Tests for a separator character */
void show(struct WordCounter *pWordcounter);
/* Outputs a word and its count of occurrences */
struct WordCounter* createWordCounter(char *word);
/* Creates a new WordCounter structure */
int getword(char *, int);
/* Self explanitory */
int getch(void);
void ungetch(int);

      /* Global variables */
struct WordCounter *pStart = NULL;
/* Pointer to first word counter in the list */
char buf[BUFSIZE];
int bufp = 0;

main()
{
 char text[MAX_TEXT_LENGTH];    /* Stores input text */
 char buffer[MAX_WORD_LENGTH];  /* Buffer to hold a word */
 size_t i = 0;                  /* Index to text */
 int len = 0 ;                  /* Word length */
 struct WordCounter *pCounter = NULL;  /* Pointer to a word counter */
 printf("Calculating frequency of word occurances:\n");
gets(text); This line only gets the first line.  To get the next I thought I could do something like footnote 1.

/* Extract the words from the text  */
 while(text[i] != '\0')
 {
  /* Skip over separators */
  while(is_separator(text[i]))
  ++i;
  /* It is either the end of the string or the start of a word    */
  /* As long as it is not the string terminator copy the character */
  len = 0;              /* Reset character count    */
  while((!is_separator(text[i])) && (text[i] != '\0'))
  buffer[len++] = text[i++];
  if(len>0)               /* Check we have some characters in the word */
    {
     buffer[len] = '\0';   /* We reached the end of a word so add terminator */
     addWord(buffer);      /* Add the word to the list */
    }
  }
                                                                                 /* List the words and their counts */
 pCounter = pStart;
 while(pCounter != NULL)
  {
   show(pCounter);
   pCounter = pCounter->pNext;
  }
 printf("\n");
 /* Free the memory that we allocated */
 pCounter = pStart;
 while(pCounter != NULL)
  {
   free(pCounter->word);        /* Free space for the word */
   pStart = pCounter;           /* Save address of current */
   pCounter = pCounter->pNext;  /* Move to next counter    */
   free(pStart);                /* Free space for current  */
  }
}

/* Returns TRUE if the argument is a separator character and FALSE otherwise */
int is_separator(char ch)
{
 /* Separators are space, comma, colon, semicolon, double quote, question mark, exclamation, and period */
 static char separators[] = { ' ' , ',',':' , '\"', '?' , '!' , '.'};
 int i = 0;
 for(i = 0 ; i<sizeof separators ; i++)
  {
   if(ch == separators[i])
   return TRUE;
  }
 return FALSE;
}
                                                                                void show(struct WordCounter *pWordcounter)
{
 /* output the word left-justified in a fixed field width followed by the count */
 printf("\n%-30s   %5d", pWordcounter->word,pWordcounter->word_count);
}

void addWord(char *word)
{
 struct WordCounter *pCounter = NULL;
 struct WordCounter *pLast = NULL;
 if(pStart == NULL)
  {
   pStart = createWordCounter(word);
   return;
  }
                                                                                 /* If the word is in the list, increment its count */
 pCounter = pStart;
 while(pCounter != NULL)
  {
   if(strcmp(word, pCounter->word) == 0)
    {
     ++pCounter->word_count;
     return;
    }
   pLast = pCounter;            /* Save address of last in case we need it */
   pCounter = pCounter->pNext;  /* Move pointer to next in the list        */
  }

 /* If we get to here it's not in the list - so add it */
   pLast->pNext = createWordCounter(word);
}

/* Create and returns a new WordCounter object for the argument */
struct WordCounter* createWordCounter(char *word)
{
  struct WordCounter *pCounter = NULL;
  pCounter = (struct WordCounter*)malloc(sizeof(struct WordCounter));
  pCounter->word = (char*)malloc(strlen(word)+1);
  strcpy(pCounter->word, word);
  pCounter->word_count = 1;
  pCounter->pNext = NULL;
  return pCounter;
}

1.

while(scanf("%s",&text[x] != EOF))
{
gets(&text[x]);
x++;
}

However, C being the type dependent pain in the ass that it is...this doesn't work or I'm just unaware of how to cast it to work.

Recommended Answers

All 10 Replies

>>The program is supposed to take in a file provided through standard input
That means get the name of the file from standard input, not the lines of the file. You have to open the file and read each word, something like this:

int main(int argc, char* argv[])
{
   FILE* fp = fopen( argv[1], "r"); // open the text file
   char buf[255];
   while( fscanf(fp,"%s",buf) > 0) // get a word
   {
    // populate the linked list with this word
   }
}
fclose(fp);

took your advice and made a big mess...

blade71(38)% cat gb
File opened successfully.
Calculating frequency of word occurances:

FsasyaofbfotcannciLadttptamaceNwaeiagcwtwtnoanscasdcleWamoagbfotwWhctdapotfaafrpftwhgtlttnmlIiafaptwsdtBialswcndwcncwcnhtgTbmladwshhcifaopptaodTwwlnnlrwwshbicnfwtdhIifutlrtbdhttuwwtwfhhtfsnaIirfutbhdttgtrbutfthdwtidttcfwtgtlfmodtwhhrttdsnhdivttnuGshanbofatgotpbtpftpsnpftearth

As you can see it is now getting every first letter of the gettysburg address and more. It is not getting the whole string and fgets is acting as getchar for some strange reason. Here is the source:
i

int main(int argc, char* argv[])
{
 char text[MAX_TEXT_LENGTH];
 char buffer[MAX_WORD_LENGTH];
 size_t i = 0;
 int len = 0;
 struct WordCounter *pCounter = NULL;
 FILE* fp = fopen("gettysburg.txt", "rt"); /* Opens the text file */
 if(fp == NULL)
  {
   printf("Error: can't open file. \n");
   return 1;
  }
 else
  {
   printf("File opened successfully. \n");
   int z = 0;
   while(!feof(fp))
 {
     fscanf(fp, "%s", &text[z]);
     z++;
    }
   printf("Calculating frequency of word occurances:\n");
   fgets(&text[z],MAX_WORD_LENGTH,fp);
   /* Extract the words from the text */
   while(text[i] != '\0')
    {
     /* Skip over separators */
     while(is_separator(text[i]))
     ++i;
     /* It is either the end of the string or the start of a word    */
     /* As long as it is not the string terminator copy the character */
     len = 0;              /* Reset character count    */
     while((!is_separator(text[i])) && (text[i] != '\0'))
                                       buffer[len++] = text[i++];
     if(len>0)               /* Check we have some characters in the word */
      {
       buffer[len] = '\0';   /* We reached the end of a word so add terminator *
/
       addWord(buffer);      /* Add the word to the list */
      }
 }
  }
   /* List the words and their counts */
   pCounter = pStart;
   while(pCounter != NULL)
    {
     show(pCounter);
     pCounter = pCounter->pNext;
    }
  printf("\n");
  /* Free the memory that we allocated */
  pCounter = pStart;
  while(pCounter != NULL)
   {
    free(pCounter->word);        /* Free space for the word */
    pStart = pCounter;           /* Save address of current */
    pCounter = pCounter->pNext;  /* Move to next counter    */
    free(pStart);                /* Free space for current  */
   }
}

however the last word earth is fully displayed which gives me some hope in properly storing the values I am extracting and not just their first letter haha

Why did you use fgets() instead of fscanf()? fgets() gets the entire line without regard to spaces, which is not what you want. Look at the simple code I posted, it does what you need. All you have to do in that loop is add the word to the linked list or increment the word's counter if its already in the list. There is no need for that is_separator function because fscanf() will take care of that for you.

Final working result:

#include <stdio.h>
#include <string.h>

#define MAX_WORD_LENGTH    31
#define MAX_TEXT_LENGTH 10000
#define TRUE                1
#define FALSE               0
#define BUFSIZE 100

/* Structure defining a count of the occurrences of a given word */
struct WordCounter
{
 char *word;
 int word_count;
 struct WordCounter *pNext;  /* Pointer to the next word counter in the list */
};

/* Function prototypes */
void addWord(char *pWord);
/* Adds a word to the list or updates exisiting word */
int is_separator(char ch);
/* Tests for a separator character */
void show(struct WordCounter *pWordcounter);
/* Outputs a word and its count of occurrences */
struct WordCounter* createWordCounter(char *word);
/* Creates a new WordCounter structure */
int getword(char *, int);
/* Self explanitory */

/* Global variables */
struct WordCounter *pStart = NULL;
/* Pointer to first word counter in the list */

int main(int argc, char* argv[])
{
 char text[MAX_TEXT_LENGTH];
 char buffer[MAX_WORD_LENGTH];
 size_t i = 0;
 int len = 0;
 struct WordCounter *pCounter = NULL;
 FILE* fp = fopen("gettysburg.txt", "rt"); /* Opens the text file */
 if(fp == NULL)
  {
   printf("Error: can't open file. \n");
   return 1;
 }
 else
  {
   printf("File opened successfully. \n");

   printf("Calculating frequency of word occurances:\n");
   /* Extract the words from the text */
   while(fscanf(fp, "%s", buffer) > 0)
   {
       addWord(buffer);      /* Add the word to the list */
       buffer[len++];

   }
   /* List the words and their counts */
   pCounter = pStart;
   while(pCounter != NULL)
    {
     show(pCounter);
     pCounter = pCounter->pNext;
    }
  printf("\n");
  /* Free the memory that we allocated */
  pCounter = pStart;
 while(pCounter != NULL)
   {
    free(pCounter->word);        /* Free space for the word */
    pStart = pCounter;           /* Save address of current */
    pCounter = pCounter->pNext;  /* Move to next counter    */
    free(pStart);                /* Free space for current  */
   }
 }
}

You were so obviously right it hurt after I did that. You completely answered my original question of trying to use scanf and provided me with the proper use of fscanf. I don't know how much easier you could have made it for me to understand. Now when I look back I feel like I wasted a lot of time. But actually, I was learning so it wasn't a waste and you sir Ancient Dragon are one hell of a teacher. Thank you so much for your help. fscanf and fgets are really cool and I learned about them through you!

delete line 56 -- it does nothing.

delete line 56 -- it does nothing.

deleted....one addition question. Suppose I wanted to print my results in descending order of frequency. I should modify my while loop that prints the results however I'm not too sure how. Should I write a function that utilizes a sort algorithm and sorts the list, or is there an easier way to just modify something in this while to get the same desired results. Or should I make my list a double linked list so I can navigate through it and recursively print the descending values?

while(pCounter != NULL)
    {
     show(pCounter);
     pCounter = pCounter->pNext;
    }

Change AddWord() to add the new node in ascending or descending order. Then you won't have to bother about sorting later.

why would I change AddWord()? I could understand if I was trying to alphabetize the list but I'm not. I am trying to print it out in order of frequency... Ex suppose there are 5 "A" and 2 "The" it would print A 5 before The 2. The only way I can think to achieve this is to make my list a double linked list and begin swapping elements or copy it into an array and use a temporary array to swap elements...essentially the same thing

Oh I see -- I guess I misunderstood. You would have to sort the list after it was finished. When sorting linked lists just exchange the actual data, not the entire nodes, to preserve the link pointers.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.