2

As part of my course, I have to learn C using Turbo C (unfortunately).

Our teacher asked us to make a piece of code that counts the number of characters, words and sentences in a paragraph (only using printf, getch() and a while loop.. he doesn't want us to use any other commands yet). Here is the code I wrote:

#include <stdio.h>
#include <conio.h>

void main(void)  
{  
clrscr();  
int count = 0;  
int words = 0;  
int sentences = 0;  
char ch;

while ((ch = getch()) != '\n')
{
    printf("%c", ch);
    while ((ch = getch()) != '.')
    {
        printf("%c", ch);
        while ((ch = getch()) != ' ')
        {
            printf("%c", ch);
            count++;
        }
        printf("%c", ch);
        words++;
    }
    sentences++;
}

printf("The number of characters are %d", count);
printf("\nThe number of words are %d", words);
printf("\nThe number of sentences are %d", sentences);
getch();
   }

It does work (counts the number of characters and words at least). However when I compile the code and check it out on the console window I can't get the program to stop running. It is supposed to end as soon as I input the enter key. Why is that?

hippietrail
  • 15,848
  • 18
  • 99
  • 158
dnclem
  • 2,818
  • 15
  • 46
  • 64
  • Think about the nature of the problem. You have written a triple-nested loop where the problem would seem to require a single loop. Try it with just one loop and some if statements (or a switch) to do different things with the different types of characters. – ooga Feb 02 '14 at 16:40
  • That's the thing. I know (or at least think I know) how to do this using an if statement (or switch), but the teacher doesn't want us to use it. Only while.. – dnclem Feb 02 '14 at 16:42
  • 1
    As a side note: it should be `int main` and `return 0` at the end. –  Feb 02 '14 at 16:44
  • 1
    are you sure your teacher said not to use conditionals?, it appears from your post he doese'nt want you to use function. two different things, if else are not functions – tesseract Feb 02 '14 at 16:46
  • Uh, that was my mistake. Basically he said use things that he has only taught us yet, and he hasn't taught us if/switch/etc. He's just taught us loops, but he specifically said only use a while loop for this. I'll edit my post. – dnclem Feb 02 '14 at 16:47
  • 3
    It seems very strange that you would be taught while loops before if statements. – ooga Feb 02 '14 at 16:49
  • I agree. It's even sillier that he doesn't allow us to use them when we did in the previous semester. We were doing C++ back then, but they're (if statements) literally the same. Oh well. The fact we're using Turbo C is enough of a red flag that this course will be bad. I'm interested in knowing why this code doesn't work though. – dnclem Feb 02 '14 at 16:51
  • In the inner loops, it read the newline, which is not a space, the loop ends and then the middle loop reads the EOF, which does not compare to its condition, so it loops forever. Add `&& ch != EOF` to all your conditions. – ooga Feb 02 '14 at 16:56
  • probably, enter is `'\r'` – BLUEPIXY Feb 02 '14 at 17:09
  • I understand the problem now.. but adding the second condition didn't fix it. I tried && ch != '\n' either, but that didn't work.. – dnclem Feb 02 '14 at 17:10
  • Thinking again, maybe you should add all the outer conditions to the inner loops. So the innermost would test for space, period, and newline. The middle would test for period and newline. You could also add EOF to all of them. – ooga Feb 02 '14 at 17:10
  • Actually I just tested a separate code to check for enter and it was \r instead of \n, which is weird. I will test my code with \r and see how it goes.. – dnclem Feb 02 '14 at 17:22
  • @ooga Story after I confirm that it can exit by entering the very first to enter first. – BLUEPIXY Feb 02 '14 at 17:27

7 Answers7

4

Here you have the solution to your problem:

#include <stdio.h>
#include <conio.h>

void main(void)
{
    clrscr();  
    int count = 0;  
    int words = 0;  
    int sentences = 0;  
    char ch;

    ch = getch();
    while (ch != '\n')
    {
        while (ch != '.' && ch != '\n')
        {
            while (ch != ' ' && ch != '\n' && ch != '.')
            {
                count++;
                ch = getch();
                printf("%c", ch);
            }
            words++;
            while(ch == ' ') {
                ch = getch();
                printf("%c", ch);
            }
        }
        sentences++;
        while(ch == '.' && ch == ' ') {
           ch = getch();
           printf("%c", ch);
        }
    }

    printf("The number of characters are %d", count);
    printf("\nThe number of words are %d", words);
    printf("\nThe number of sentences are %d", sentences);
    getch();
}

The problem with your code is that the innermost while loop was consuming all the characters. Whenever you enter there and you type a dot or a newline it stays inside that loop because ch is different from a blank. However, when you exit from the innermost loop you risk to remain stuck at the second loop because ch will be a blank and so always different from '.' and '\n'. Since in my solution you only acquire a character in the innermost loop, in the other loops you need to "eat" the blank and the dot in order to go on with the other characters.

Checking these conditions in the two inner loops makes the code work. Notice that I removed some of your prints.

Hope it helps.

Edit: I added the instructions to print what you type and a last check in the while loop after sentences++ to check the blank, otherwise it will count one word more.

mike
  • 220
  • 1
  • 12
  • I think those prints were need since now it doesn't print any space. Also, it still doesn't "end" the code when I hit enter. – dnclem Feb 02 '14 at 17:47
  • and `'.'` doesn't print. and no count. – BLUEPIXY Feb 02 '14 at 17:50
  • For me it prints the results and at the end waits for a character before terminating the program, because of the final getch(). – mike Feb 02 '14 at 18:01
  • Are you sure? I tested your code in CodeBlocks and TurboC both, and none show spaces or print the output. – dnclem Feb 02 '14 at 18:13
  • By the way you can overcome the problem of printing what you write (i.e. do the echo) by putting a printf after each getch() (remember the parenthesis in the while loops of a single line) and you remove the one before count++. – mike Feb 02 '14 at 18:14
1

I think the problem is because of your outer while loop's condition. It checks for a newline character '\n', as soon as it finds one the loop terminates. You can try to include your code in a while loop with the following condition

while((c=getchar())!=EOF)

this will stop taking input when the user presses Ctrl+z

Hope this helps..

user3181652
  • 34
  • 1
  • 5
1

You can implement with ease an if statement using while statement:

bool flag = true;
while(IF_COND && flag)
{
    //DO SOMETHING
    flag = false;
}

just plug it in a simple solution that uses if statements.

For example:

#include <stdio.h>
#include <conio.h>

void main(void)  
{  
    int count = 0;  
    int words = 1;  
    int sentences = 1;  
    char ch;

    bool if_flag;

    while ((ch = getch()) != '\n')
    {
        count++;
        if_flag = true;
        while (ch==' ' && if_flag)
        {
            words++;
            if_flag = false;
        }
        if_flag = true;
        while (ch=='.' && if_flag)
        {
            sentences++;
            if_flag = false;
        }
    }

    printf("The number of characters are %d", count);
    printf("\nThe number of words are %d", words);
    printf("\nThe number of sentences are %d", sentences);
    getch();
}
zvisofer
  • 1,346
  • 18
  • 41
1
#include <stdio.h>
#include <ctype.h>

int main(void){

int sentence=0,characters =0,words =0,c=0,inside_word = 0,temp =0;
// while ((c = getchar()) != EOF) 
while ((c = getchar()) != '\n') {
   //a word is complete when we arrive at a space after we 
  // are inside a word or when we reach a  full stop

    while(c == '.'){
        sentence++;
        temp = c;
        c = 0;
    }
     while (isalnum(c)) {
        inside_word = 1;
        characters++;
        c =0;
    }
    while ((isspace(c) || temp == '.') && inside_word == 1){
        words++;
        inside_word = 0;
        temp = 0;
        c =0;
    }
}
printf(" %d   %d   %d",characters,words,sentence);
return 0;
}

this should do it,

isalnum checks if the letter is alphanumeric, if its an alphabetical letter or a number, I dont expect random ascii characters in my sentences in this program.

isspace as the name says check for space

you need the ctype.h header for this. or you could add in

   while(c == ' ') and whie((c>='a' && c<='z') || (c >= 'A' && c<='Z') 

if you don't want to use isalpace and isalnum, your choice, but it will be less elegant :)

tesseract
  • 891
  • 1
  • 7
  • 16
1
int ch;
int flag;
while ((ch = getch()) != '\r'){
    ++count;
    flag = 1;
    while(flag && (ch == ' ' || ch == '.')){
        ++words;//no good E.g Contiguous space, Space at the beginning of the sentence
        flag = 0;;
    }
    flag = 1;
    while(flag && ch == '.'){
        ++sentences;
        flag=0;
    }
    printf("%c", ch);
}
printf("\n");
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
  • Thank you. After hours of testing different things, yours is the only code that actually works. Is it possible to break the loop without using the break command though? Or would that mean changing the entire code? – dnclem Feb 02 '14 at 18:28
  • @david It can replace the break the method of zvisofer. – BLUEPIXY Feb 02 '14 at 18:30
0

The trouble with your code is that you consume the characters in each of your loops. a '\n' will be consumed either by the loop that scans for words of for sentences, so the outer loop will never see it.

Here is a possible solution to your problem:

int sentences = 0;
int words = 0;
int characters = 0;

int in_word = 0; // state of our parser

int ch;
do
{
    int end_word = 1; // consider a word wil end by default
    ch = getch();
    characters++; // count characters
    switch (ch)
    {
    case '.':
        sentences++; // any dot is considered end of a sentence and a word
        break;
    case ' ': // a space is the end of a word
        break;
    default:
       in_word = 1;  // any non-space non-dot char is considered part of a word
       end_word = 0; // cancel word ending
    }

    // handle word termination
    if (in_word and end_word) 
    {
        in_word = 0;
        words++;
    }

} while (ch != '\n');

A general approach to these parsing problems is to write a finite-state machine that will read one character at a time and react to all the possible transitions this character can trigger.

In this example, the machine has to remember if it is currently parsing a word, so that one new word is counted only the first time a terminating space or dot is encountered.

This piece of code uses a switch for concision. You can replace it with an if...else if sequence to please your teacher :).

If your teacher forced you to use only while loops, then your teacher has done a stupid thing. The equivalent code without other conditional expressions will be heavier, less understandable and redundant.

Since some people seem to think it's important, here is one possible solution:

int sentences = 0;
int words = 0;
int characters = 0;

int in_word = 0; // state of our parser
int ch;

// read initial character
ch = getch();

// do it with only while loops
while (ch != '\n')
{
    // count characters
    characters++;

    // count words
    while (in_word)
    {
        in_word = 0;
        words++;
    }

    // skip spaces
    while (ch == ' ')
    {
        ch = -1;
    }

    // detect sentences
    while (ch == '.')
    {
        sentences++;
        ch = -1;
    }

    // detect words
    while ((ch != '\n')
    {
        word_detected = 1;
        ch = -1;
    }

    // read next character
    ch = getch();
}

Basically you can replace if (c== xxx) ... with while (c== xxx) { c = -1; ... }, which is an artifical, contrieved way of programming.

An exercise should not promote stupid ways of doing things, IMHO.
That's why I suspect you misunderstood what the teacher asked.
Obviously if you can use while loops you can also use if statements.

Trying to do this exercise with only while loops is futile and results in something that as little or nothing to do with real parser code.

kuroi neko
  • 8,479
  • 1
  • 19
  • 43
  • It would be a lot easier if he was allowed to use if/else and switch but he said: *only using printf, getch() and a while loop* –  Feb 02 '14 at 16:59
  • `char ch;` should be `int ch;` And you should add a case for EOF to the switch. – wildplasser Feb 02 '14 at 17:02
  • @wildplasser OK for the int, as for EOF, bah, this is just for TurboC so EOF is unlikely to show up. The point was to illustrate how a parser generally works without wandering into minute details. – kuroi neko Feb 02 '14 at 17:05
  • Well even then I would have to use an if and switch statement, no? Which I can't. – dnclem Feb 02 '14 at 17:11
  • It is not that hard to rewite the switch(){} into a couple of if(){}s. BTW : `while (ch != '/n');` should be `while (ch != '\n');` – wildplasser Feb 02 '14 at 17:23
  • @wildplasser yep, another typo bites the dust. Thanks. Anyway, I feel like I'm wasting my time here. Either the OP musunderstood the conditions or the exercise is plain wrong, IMHO. – kuroi neko Feb 02 '14 at 17:47
  • I didn't. I know my teacher is asking a really dumb thing. I'm sorry if I'm wasting other people's time (and this is bugging me too - I've spent 3 hours on this dumb thing so far). It doesn't help that I'm using a really awful compiler too. – dnclem Feb 02 '14 at 17:51
  • 1
    In that case I can only sympathize. There are enough horrible programmers around, we don't need teachers to teach stupid ways of doing things :). When I was a project manager, had one of my team members produced a similar piece of code, I would have given him hell and asked ihm to rewrite it right away. – kuroi neko Feb 02 '14 at 17:54
  • Agreed. It's such a shame when you have an amazing programming teacher one semester, and then the next one you have one with horrible teaching methods. Instead of praising students for using functions which haven't even been taught he cancels the entire thing. – dnclem Feb 02 '14 at 17:59
0

All these solutions are incorrect. The only way you can solve this is by creating an AI program that uses Natural Language Processing which is not very easy to do.

Input:

"This is a paragraph about the Turing machine. Dr. Allan Turing invented the Turing Machine. It solved a problem that has a .1% change of being solved."

Checkout OpenNLP

https://sourceforge.net/projects/opennlp/

http://opennlp.apache.org/

KDG
  • 11
  • 4