Character, Line and Word Counter in C [closed] - c

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I am sorry to ask so many questions but I am clueless what to do when my Program gives me errors which I don't understand how to fix. I use Code Blocks. The book name is The C Programming Language 2nd Edition.
The Code:
#include <stdio.h>
#include <stdlib.h>
#define IN 1
#define OUT 0
int main()
{
int c, nl, nw, nc, state;
state = OUT;
while((c = getchar()) != EOF)
{
++nc;
if (c == '\n')
if (c == '' || c == '\n' || c = '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d \n", nl, nw, nc);
}
So when I build it it gives me error on line 14 saying:
||=== Build: Debug in Line Counter v2 (compiler: GNU GCC Compiler) ===|
C:\Users\Uddhava\Desktop\Uddhava\Learning\Programming\C C+\Line Counter v2\
main.c|14|error: empty character constant|
C:\Users\Uddhava\Desktop\Uddhava\Learning\Programming\C C+\Line Counter v2\
main.c|14|error: lvalue required as left operand of assignment|
||=== Build failed: 2 error(s), 2 warning(s) (0 minute(s), 0 second(s)) ===|

if (c == '' || c == '\n' || c = '\t')
The first thing wrong with this line is that it should be:
if (c == ' ' || c == '\n' || c == '\t')

if (c == '' || c == '\n' || c = '\t')
should be
if (c == ' ' || c == '\n' || c == '\t')
if (c == '\n')
if (c == '' || c == '\n' || c = '\t')
In your code, the first if statement makes the second meaningless.

You are testing the value of c against an empty character constant '', which is not allowed. I think you want to test it against a space ' '.

If you want to test the value of your variable c with an empty space, you should compare it with ' ' instead of ''. Furthermore, comparison operator is ==, not = (assignment), which you used to compare the tab character '\t' in the last condition of your if statement, thus your if statement should be:
if (c == ' ' || c == '\n' || c == '\t')

this code block:
while((c = getchar()) != EOF)
{
++nc;
if (c == '\n')
if (c == '' || c == '\n' || c = '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
does not indicate (via the indentation) exactly which 'if' clause
is related to the 'else clause.
this is a VERY good reason to include ALL the '{' and '}' braces
this is what is actually written in the code:
while((c = getchar()) != EOF)
{
++nc;
if (c == '\n')
{
if (c == '' || c == '\n' || c = '\t') // two errors on this line
{
state = OUT;
}
else if (state == OUT)
{
state = IN;
++nw;
}
}
}
the question becomes: is this what you really wanted?
we already know that the code is not correct
because the second 'if' will ALWAYS fail due to 'c' being
already confirmed as containing a '\n'
and the comparison of 'c' to ''
and the assignment of '\t' to 'c'
therefore, I suspect it should be:
while((c = getchar()) != EOF)
{
++nc;
if (('\n' == c) || (' ' == c) || ('\n' == c) || ('\t' == c) )
{
state = OUT;
}
else if (state == OUT)
{
state = IN;
++nw;
}
}
which would have also caught the assignment of '\t' to c at compile time
rather than you having to spend many an hour debugging the code.
I.E. put the literal on the left side of the comparison operator '=='

Well this worked, I used ideas from Amadeus, user3629249 and Min Fu. Thanks everyone for your help.
Working Code:
#include <stdio.h>
#include <stdlib.h>
#define IN 1
#define OUT 0
int main()
{
int c, nl, nw, nc, state;
state = OUT;
nc = 0;
nl = 0;
nw = 0;
while((c = getchar()) != EOF)
{
++nc;
if (('\n' == c) || (' ' == c) || ('\n' == c) || ('\t' == c) )
{
state = OUT;
++nl;
}
else if (state == OUT)
{
state = IN;
++nw;
}
}
printf("%d %d %d \n", nl, nw, nc);
return 0;
}

Related

Visual Studio (C) ignoring escape sequences

Going through Kernighan, and I am coding on visual studio with windows. Why doesn't the following program doesn't pick up tab characters, new lines, or spaces? I have to manually type its associated integer. Here's the word count program:
#define IN 1 /*State of being inside word*/
#define OUT 0 /*State of being outside word*/
countWords() {
int c, nl, nw, nc, state;
state = OUT;
nl = (nw = (nc = 0));
while ((c = getchar() != EOF)) {
nc++;
if (c == '\n') {
nl++;
}
if (c == ' ' || c == '\n' || c == '\t') {
state = OUT;
}
else if (state == OUT) {
state = IN;
nw++;
}
printf("%d %d %d\n", nl, nw, nc);
}
}
My test input was 'one two three' and the output was '0 1 14'. Indicating that it didn't recognise space character ' '. Is there a setting on VS that needs to be changed to get this working?
Be careful with operator precedence.
while ((c = getchar() != EOF)) {
The c variable gets the boolean value of the expression getchar() != EOF. It doesn't hold the character that was read in like you are probably expecting.
You probably meant to write it as:
while ((c = getchar()) != EOF) {

program to count commented characters and words in a C file

I have to count characters and word in comment of a C file, for both single line comments and blocked comment. Here's what I have:
#include <stdio.h>
#define IN = 1
#define OUT = 0
main() {
int c, nc;
nc = 0;
while ((c = getchar()) != EOF) {
if (c == '/') {
if (getchar() == '/')
while (getchar() != '\n')
++nc;
}
}
if (c == '/') {
if (getchar() == '*')
while (getchar() != '/')
++nc;
}
printf("Character Counts: %d\n", nc);
}
It works for every single line comment (//), but it skips the blocked comments (/*...*/). I feel like it never enter the if block for the blocked comment. Much appreciate!
There are multiple problems in your code:
You must specify int as the return type of the main function. The syntax in the question is obsolete.
The definitions of IN and OUT are incorrect. You should either use
#define IN 1
#define OUT 0
or
enum { IN = 1, OUT = 0 };
The first loop consumes all the bytes in standard input, you are at the end of file, so the tests for /*...*/ comments never produce anything.
loops such as while (getchar() != '\n') can run forever if the byte tested is not found before the end of file.
You cannot test // and /*...*/ comments separately as one can hide the other:
//* this is a line comment that does not start a C style one
/* this comment contains a // but stops here */ return 0;
Note also that you should parse C strings and character constants as they may contain // and or /* sequences that do not start a comment.
For a complete solution, you should also handle escaped newlines. Here are some pathological examples:
// this is a line comment that extends \
on multiple \
lines (and tricks the colorizer)
/\
* this is a C comment, but the colorizer missed it *\
/
This problem is non-trivial to solve in the general case, but you can start with simple cases.
Here is a modified version:
#include <stdio.h>
int main() {
int c, cc, nc = 0;
while ((c = getchar()) != EOF) {
if (c == '/') {
if ((cc = getchar()) == '/') {
while ((c = getchar()) != '\n')
nc++;
} else
if (cc == '*') {
while ((cc = getchar()) != EOF) {
if (cc == '*') {
if ((cc = getchar()) == '/')
break;
ungetc(cc, stdin);
}
nc++;
}
}
}
}
printf("Character Counts: %d\n", nc);
return 0;
}
I added code to count the words. It works on few occasions, but it behaves weird when I have space after the slash. For example, // comment... Most of the time, the word count is off by 1.
#include<stdio.h>
#define IN 1
#define OUT 0
int main() {
int c, cc, nc = 0;
int state;
int nw = 0;
state = OUT;
while ((c = getchar()) != EOF) {
if (c == '/') {
if ((cc = getchar()) == '/') {
while ((c = getchar()) != '\n'){
nc++;
if (c == ' ' || c == '\t')
state = OUT;
else if (state == OUT){
state = IN;
nw++;
}
}
}
else if (cc == '*') {
while ((cc = getchar()) != EOF) {
if (cc == ' ' || cc == '\t')
state = OUT;
else if (state == OUT){
state = IN;
nw++;
}
if (cc == '*') {
if ((cc = getchar()) == '/')
break;
ungetc(cc, stdin);
}
nc++;
}
}
}
}
printf("Character Counts: %d\n", nc);
printf("Word Counts: %d\n", nw);
return 0;
}
program to count commented characters and words in a C file
it skips the blocked comments (/.../)
I recommend, at a minimum, to parse code and look for 5 states: normal, in a // comment, in a /* comment, in a "" string literal, in a '' character constant.
// pseudo code
while ((ch = getchar()) != EOF) {
if ch == '/' and next == '/', process `//` comment until end-of-line
elseif ch '/' and next == '*', process `/*` comment until `*/`
elseif ch '"', process string until " (but not \")
elseif ch ''', process constant until ' (but not \')
else process normally
}
To look at the next character, call getchar() and then ungetc() if not as expected.

K&R C Histogram

I'm currently doing exercise 1-13 in K&R's C the Programming Language 2nd edition. I decided to start with a simple histogram that just replaces each letter in a word with '*'.
#include <stdio.h>
// histogram
#define IN 1
#define OUT 0
main() {
int c, state;
state = OUT;
while ((c = getchar()) != EOF) {
if (c == '\n' || c == '\t' || c == ' ') {
state = OUT;
putchar('\n');
}
else {
if (c != '\n' || c != ' ' || c != '\t') {
state = IN;
putchar('*');
}
}
}
}
However, take a look at this snippet of code:
else {
if (c != '\n' || c != ' ' || c != '\t') {
state = IN;
putchar('*');
}
}
How come this works, but if I enter if (state != OUT) , it doesn't work? I end up getting a completely different output. Aren't those two statements essentially the same thing?
c being equal to three terms "or" each other is not equivalent c not being equal to the negations of the same three terms "or" each other.
See De Morgan's laws.

Count lines , words, characters in C

This code is taken from C Programming by K & R. I am newbie to C programming and i need little help in understanding this code. This code gives me error please help me how to fix it
#include <stdio.h>
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
/* count lines, words, and characters in input */
main()
{
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n') ++nl;
if (c == ' ' || c == '\n' || c = '\t') state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
Error :
E:\Files\C\main.c:5:1: warning: return type defaults to 'int' [-Wreturn-type]
E:\Files\C\main.c: In function 'main':
E:\Files\C\main.c:14:40: error: lvalue required as left operand of assignment
E:\Files\C\main.c:21:1: warning: control reaches end of non-void function [-Wreturn-type]
You are assigning the value for c instead of comparing.
if (c == ' ' || c == '\n' || c = '\t') state = OUT;
should be
if (c == ' ' || c == '\n' || c == '\t') state = OUT;
And your main function should be like int main(void) and put a return 0 at the end
you are assigning value rather than comparing it:if (c == ' ' || c == '\n' || c = '\t'), == is used for comparison and = is used for assignment.
first of all change main function to int main() at line 5.
Also at line 13 try to use == for making it equal in the way shown below.
if (c == ' ' || c == '\n' || c == '\t') state = out;
//you assign a value instead
Also to terminate a program, at the end write return 0;

Exersice 1-13 from K&R

I am doing the K&R book.
If i check a == then everything works but if I check !=, then no histogram is printed.
This works
while( (c = getchar()) != EOF )
{
if(c == ' ' || c == '\t' || c =='\n')
{
state = OUT;
if(wc>0)
++numOfWords[wc];
wc = 0;
}
else
if(state == OUT)
state = IN;
if(state = IN)
++wc;
}
but changing the if section to this does not:
if(c != ' ' || c != '\t' || c !='\n'){
if(state == OUT){
state = IN;
++wc;}
else
++wc;
}
else
{
state = OUT;
if(wc>0)
++numOfWords[wc];
wc = 0;
}
}
I want every character that is not a tab or a space or a newline. So i wrote c != '\t' || c!= ' ' || c!= '\n'. which i take to mean as
If c is not (!=) space(' ') then its 1(true) OR(||) if c is not (!=) tab('\t') then its 1 OR(||) ...so on.
And if any one of the OR statement is true then the whole statement is true and body should execute, so why isn't it executing?
Thanks for noticing the typo in first snippet, I corrected it, but I want to ask is why doesn't the second snippet work?
Answer:
This works perfectly:
if(c != ' ' && c != '\t' && c !='\n' && c != '"' && c!= '.' && c != ','){
if(state == OUT){
state = IN;
++wc;}
else
++wc;
}
else
{
state = OUT;
if(wc>0)
++numOfWords[wc];
wc = 0;
}
In the first snippet
if(state = OUT)
...
if(state = IN)
is wrong. Change this to
if(state == OUT)
...
if(state = IN)
After that if your first snippet of code works well then change
if(c != ' ' || c != '\t' || c !='\n')
in your second snippet to
if(c != ' ' && c != '\t' && c !='\n')
if you with to negate the whole if stament try if(!(c == ' ' || c == '\t' || c =='\n')) or its logical equivalent if( c != ' ' && c != '\t' && c == '\n')). Negating the individuals elements is not enough. You have to change the or's to and's.
Every character is either "not a space", "not a tab", or "not a newline". A tab, for instance, is "not a space" and "not a newline". So that if-condition will never be false. It sounds like you want to look for characters which are "not a space" AND "not a tab" AND "not a newline".

Resources