Hi guys I am really having a hard time with C programming. Our lectures are very fast and not beneficial to those with non-C backgrounds. We were required to write a code for counting frequency of words from stdin and then listing them in descending order with those with equal length being alphabetized. Please help me because I am really lost with this program. I really need it.

Thanks for the links sir. Its just that I'm going nothing with my code. I posted what I have done below and its a wreck. I can't even convert uppercase input to lower case. How to count the occurrences of a word is a big puzzle also for me. I wish you could help me.

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

int main (void)
{
        char haystack[1028];
        char needle[] = " a";
        char c = 'a';
        char *ph;
        fgets(haystack,sizeof(haystack),stdin);
        while(c<='z'){
           ph = haystack;
           if(c==*ph) {
              putchar(*ph++);
              while(!isspace(*ph)){ 
              putchar(*ph++); 
              printf("\n");
           }
           while( ph=strstr(ph,needle) ){
              putchar(*ph++);
              while(!isspace(*ph)) { 
              putchar(*ph++); 
              printf("\n");             
              }
           }
        needle[1]=++c;
        }
puts("");
return(0);
}

Occurrences can be done with what's called a frequency table. It's a really cool thing, and it's really easy to implement. But, I'm not going to write your program for you, so I'll give you a frequency table that counts the occurrences of single characters and let you figure out how to do it with words using the excellent links you've already been given (otherwise I would hurt Dave's feelings):

#include <stdio.h>
#include <limits.h>
#include <ctype.h>

int main ( void )
{
  int freq[CHAR_MAX + 1] = {0};
  int i;
  char input;

  while ( ( input = getchar() ) != EOF )
    ++freq[input];

  for ( i = 0; i < CHAR_MAX + 1; i++ ) {
    if ( freq[i] != 0 ) {
      if ( isalpha ( i ) )
        printf ( "%c:\t%d\n", i, freq[i] );
      else
        printf ( "%#X:\t%d\n", i, freq[i] );
    }
  }

  getchar();

  return 0;
}

I talk about frequency tables a lot because they're so useful, you might even be able to find an exact solution to your problem by searching the forum. ;)

sir thanks for the things about frequency tables but we arent allowed to use them. here's what my prof wants.

Input. Hello world! Hello country. Hello world! Hello card. Hello apple.
Output:
hello 5
world 2
apple 1
card 1
country 1


I'm really having difficulty with this program. Hope anyone could help.

>madam thanks for the things
Fixed quote ;)

>but we arent allowed to use them.
How else does your professor expect you to keep track of the number of times a word is present in a sentance, then? I'll let Narue answer this one...

>thanks for the things about frequency tables but we arent allowed to use them.
What are you allowed to use if you can't cache the words and counts? I can think of one way (that could be considered a beginner solution) off the top of my head, and the logic is extremely painful even for experienced programmers.

> thanks for the things about frequency tables but we arent allowed to use them.
Which is why it is pointless to ask people to do your homework.

Not only would we have to vaguely guess at what you really wanted, we also have to guess at how much to dumb it down to the point where you might have plausibly written it. This just isn't going to happen.

> Our lectures are very fast and not beneficial to those with non-C backgrounds
Perhaps you're on the wrong course then. You (as a group of non-C people) need to go talk to the lecturers to voice your concerns.

If the course material said "assumes familiarity with C", then your bluff has been called. Quit now and get onto another course before it's too late to catch up with either of them.

This is going to get a lot harder very quickly, so you need to look at the long term problem as well. Us providing you with one ready made answer is not going to make you an instant C expert. All it will do is keep you on the course for another week until the next (and even more unobtainable) assignment is handed out.

um sorry for the confusion. What I meant with the things not being allowed is that the output wanted was to be straightforward. I am thinking with the frequency table is how I can account for a very long string. I'm really sorry if I offended anyone but I don't know where to start. Im puzzled with these.

Hello I was thinking about the sorting part. Like I said I don't have my compiler so this is what I rolled out from the top of my head, I'm not sure if it works?

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

#define NELEMS 5
//could be done dynamically with malloc perhaps?

struct crap
{
   char word[1024];
   int wordOccurrence;
};

static int wordOccurrenceSort(const void *, const void *);

int main()
{
   size_t i;
   static struct crap stuff[NELEMS] =
     
     {
      {"card",1},
      {"Hello",5},
      {"apple",1},
      {"country",1},
      {"world",2}
     };

   
   qsort(stuff, NELEMS, sizeof stuff[0],wordOccurrenceSort);

   puts("Sort by word occurence:\n");
   
   for (i = 0; i < NELEMS; ++i )
   {
      printf("\n%-20s %2d",stuff[i].word, stuff[i].wordOccurrence);
   }
        
   getchar();
      
   return 0;
}


static int wordOccurrenceSort(const void *p1, const void *p2)
{
   struct crap *sp1 = (struct crap *) p1;
   struct crap *sp2 = (struct crap *) p2;
   
   if (sp2->wordOccurrence > sp1->wordOccurrence )
   {
      return 1; //not sure what value to assign?
   }
   
   if (sp2->wordOccurrence < sp1->wordOccurrence )
   {
      return 0;//not sure what value to assign?
   }
   
   if ( sp2->wordOccurrence == sp1->wordOccurrence)
   {
      int order = strcmp(sp1->word,sp2->word);
      return order;
     //not sure what value to assign?
   }
}
static int wordOccurrenceSort(const void *p1, const void *p2)
{
   struct crap *sp1 = (struct crap *) p1;
   struct crap *sp2 = (struct crap *) p2;
   
   if (sp2->wordOccurrence > sp1->wordOccurrence )
   {
      return 1; //not sure what value to assign?
   }
   
   if (sp2->wordOccurrence < sp1->wordOccurrence )
   {
      return 0;//not sure what value to assign?
   }
   
   if ( sp2->wordOccurrence == sp1->wordOccurrence)
   {
      int order = strcmp(sp1->word,sp2->word);
      return order;
     //not sure what value to assign?
   }
}

You could simply have done something like this since this function is required to return how one element is placed wrt another and not any absolute value. Only the sign matters here (+ve, -ve, zero).

static int wordOccurrenceSort(const void *p1, const void *p2)
{
   struct crap *sp1 = (struct crap *) p1;
   struct crap *sp2 = (struct crap *) p2;
   
   return  (sp1->wordOccurrence - sp2->wordOccurrence) ;
}

You could simply have done something like this since this function is required to return how one element is placed wrt another and not any absolute value. Only the sign matters here (+ve, -ve, zero).

static int wordOccurrenceSort(const void *p1, const void *p2)
{
   struct crap *sp1 = (struct crap *) p1;
   struct crap *sp2 = (struct crap *) p2;
   
   return  (sp1->wordOccurrence - sp2->wordOccurrence) ;
}

Maybe, like I said I don't have my compiler to test it. I wrote that on the fly.

How does your version sort the words of same occurrence into alphabetical order though. I can't see it?

We were required to write a code for counting frequency of words from stdin and then listing them in descending order with those with equal length being alphabetized

How does your version sort the words of same occurrence into alphabetical order though. I can't see it?

Oh, I guess I overlooked that requirement. Here is the fix:

static int wordOccurrenceSort(const void *p1, const void *p2)
{
   struct crap *sp1 = (struct crap *) p1;
   struct crap *sp2 = (struct crap *) p2;

    if (sp1->wordOccurrence == sp2->wordOccurrence)
        return strcmp (sp1->word, sp2->word) ;
    else
        return  (sp1->wordOccurrence - sp2->wordOccurrence) ;
}

Well, doing that would be really simple. Posting the entire solution would be like wasting the efforts Narue and the others have put in solving the OP's problem.

I would leave the OP to figure out this one for himself.

>What I meant with the things not being allowed is that the output wanted was to be straightforward.
The output has no relationship to how you produce the answer. You can solve the problem a dozen wildly different ways and get exactly the same desired output that you posted.

>Only the sign matters here (+ve, -ve, zero).
>return (sp1->wordOccurrence - sp2->wordOccurrence) ;
Sure, only the sign matters, but it's also the sign that kills you with this code. You're a smart guy, so I'll give you three words of advice on why this is a poor solution: signed integer overflow.

Comments
*shoots himself in the head* I overlooked that possibility, thanks - ~s.o.s~

>You're a smart guy, so I'll give you three words of advice on why this is a poor solution: signed integer overflow.

He he, does that mean my code is safer? To be honest I don't know? This is just guess work - but it would be nice to know why. How long are you on maternity leave for?

>He he, does that mean my code is safer?
Yes. In these two comparison functions, the first is far safer:

int compare_exact ( const void *a, const void *b )
{
  const int *ia = a;
  const int *ib = b;

  if ( *ia < *ib )
    return -1;
  else if ( *ia > *ib )
    return +1;
  else
    return 0;
}

int compare_arithmetic ( const void *a, const void *b )
{
  const int *ia = a;
  const int *ib = b;

  return *ia - *ib;
}

The latter works great if the subtraction doesn't cause signed overflow, but when it does (and it will; probably at a client demo or press release) it'll cause undefined behavior.

>How long are you on maternity leave for?
Until the first of April, then I start officially telecommuting. But on my team it's implied that I'm out of commission indefinitely except for high priority issues that need the Narue touch. ;)

Hm...just curious. Would the same expression cause signed overflow if we were assured that the "integer value" would always be greater than or equal to zero ?

I think no since no matter which combination we try the subtraction operator will not yeild an overflow when both the numbers are between 0 and MAX_INT.

And if both the numbers have already overflowed, which method we choose would become a moot point since any operation based on undefined value is undefined and so is the nature of the program from that point onwards.

Your views ?

>Your views ?
Let's add five years to the program. You've moved on to more interesting things and there's a change order. How is the maintenance programmer supposed to know that negative numbers are taboo? What if the change order requires them? By over-intellectualizing, you've introduced a bug and a fix that wouldn't be necessary if your code was written defensively from the start.

Let's add five years to the program. You've moved on to more interesting things and there's a change order. How is the maintenance programmer supposed to know that negative numbers are taboo? What if the change order requires them? By over-intellectualizing, you've introduced a bug and a fix that wouldn't be necessary if your code was written defensively from the start.

Makes sense...

Arigatougozaimasu.. ;)

Here's another approach that might work.

Use a list to hold the words and their frequency since you don't know how many words you will have and you are using C so STL vectors won't help. Each node in the list would have a char * for the word and an int to count frequency in addition to a pointer to the next node (unless you get "fancy" and add a second pointer to node to point to the prior node as well).

1) input word
2) transform word to all lower case (or all upper case letters if you prefer)
3) determine the length of the word
4) search the list for the current word or the first word longer/shorter than the current word
5) If current word not found, insert the current word into the list just before the first word of longer/shorter length. If current word found increase frequency counter in the appropriate node of the list.
6) Once all words entered the frequency of each word is all done and you have a list of unique words.
7) To sort the words of equal length alphabetically determine the first and last node of equal length. Then sort the interval using whatever sort you want. I'd probably create a swap() function utilizing using the two nodes to swap and the node prior to each node to swap and then use it as part of a bubble sort, but that's just me.
8) Once each length() has been alphabetized I'd print out the list using desired format showing name and counter enclosed in each node.

I'm out of commission indefinitely except for high priority issues that need the Narue touch

Erm you mean like naming all the variables after yourself, e.g. int _jsw = 0 . Go team Narue! :cheesy:

Are you gonna post any pics of your sprog at daniweb so we can all say, "Awww, look she's even got red hair and big teeth too. ;)

hi sir. I have done something but am stuck with whats next. Our program was to have input via a file. I have stored the input and I have managed list words in descending order of frequency. My problem now is that I need to input those words that have same frequency accdg. to the ASCII table with those being same letter/no. put in order. I dont know how to do that.
My code is like this now. Pls. help me. I know structures could be used here but I dont have enough knowledge to use them. Any kind of help would be appreciated.

Desired output:
sentence - 4
sack - 3
sacks - 3
9 - 2
9001 - 2
99999 - 2
den - 2
dig - 2
disk - 2
0 - 1
00 - 1
01 - 1
zoo - 1

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

char Words[5000][500]; 
int wcntr[5000]; 
int Wnum; 
int Wtotal; 

void Nword(char *Word){ 

int i;

if (strlen(Word)==0){
return; 
}

if ((Word[0]=='-')&&(Word[1]=0)){
return; 
}
Wtotal++; 

for (i=0;i<Wnum;i++){ 

if (strcmp(Words[i],Word)==0){ 

Wcntr[i]++; 
return; 
}

} 

strcpy(Words[Wnum],Word); 

Wcntr[Wnum]=1; 

Wnum++;
} 

int main() 
{

char Character; 

char CurrentWord[500]; 

int index; 

int i,j,Max;

Wnum=0;
Wtotal=0; 
index=0;


while ((Character=getchar())!=EOF){

Character=tolower(Character);

if (((Character>='0')&&(Character<='9'))|| 
((Character>='a')&&(Character<='z'))||
((Character>='A')&&(Character<='Z'))|| 
(Character=='-')||(Character=='\'')||(Character=='&'))
{

CurrentWord[index++]=Character;
}
else 
{
CurrentWord[index]=0; 
Nword(CurrentWord); 
index=0; 
}
}

for (j=0;j<Wnum;j++){ 

Max=0; 

for (i=1;i<Wnum;i++){

if (Wcntr[i]>Wcntr[Max])
{
Max=i;
} 
}

printf("%s - %d \n",Words[Max],Wcntr[Max]);
Wcntr[Max]=-1; 

} 

 return 0;
}

To do this without tables or lists you could maintain two different arrays: allWords to hold all the words read in from file in sequential order, and uniqueWords to hold all unique words found in the file. Read each word from the file one at a time. As you're reading in each word place it in allWords. Then search uniqueWords to see if it's there. If it isn't, then add it.

Once you've read in the file sort uniqueWords however you wish. Once the words in uniqueWords are sorted then search allWords for each word in uniqueWords incrementing a counter each time the current word in uniqueWords matches the current word in allWords. Once you've searced allWords for the current word in uniqueWords print the current word in uniqueWords to the screen together with the value of the counter, clear the counter and start all over again.

Um sir with the AllWords and UniqWords arrays. I do not get how to show in ASCII order the words with equal frequency. I'm thinking of holding all words in array with them in ascii order already but I don't know how to get the words from highest to lowest frequency. Hope you can give me any hints.

This article has been dead for over six months. Start a new discussion instead.