K&R2 ex 1-8

M

Merrill & Michele

The following is my best attempt to solve the exercise in the subject line
whose simple request is to write a program that counts blanks, tabs and
newlines.

#include <stdio.h>
int main(int orange, char **apple)
{
int c,n1,n2,n3;
n1=n2=n3=0;
while((c=getchar()) != EOF)
{
if (c=='\n')
++n1;
else if (c=='\t')
++n2;
else if (c==' ')
++n3;
}
printf("%d %d %d\n",n1,n2,n3);
return (0);
}

This compiles, links and behaves on my windows platform except for the
newline character. If your response to me is that I'm an idiot, you are
probably correct, but I would prefer that you show such condition in light
of this code. ++Thanks. MPJ
 
M

Michael Mair

Hello MPJ,

The following is my best attempt to solve the exercise in the subject line
whose simple request is to write a program that counts blanks, tabs and
newlines.

Thank you :)

#include <stdio.h>
int main(int orange, char **apple)
The arguments orange and apple are not used.
{
int c,n1,n2,n3;
n1=n2=n3=0;
while((c=getchar()) != EOF)
{
if (c=='\n')
++n1;
else if (c=='\t')
++n2;
else if (c==' ')
++n3;
}
printf("%d %d %d\n",n1,n2,n3);
return (0);
It is open to debate but there are many people who think it is
safer to say
return 0;
as this does not mask an error when you are mistyping return and
do it so awkwardly that it becomes the name of a function, (say
void retrun (int);
)
}

This compiles, links and behaves on my windows platform except for the
newline character. If your response to me is that I'm an idiot, you are
probably correct, but I would prefer that you show such condition in light
of this code.

I took this as a request for code review.
As you see from my comments -- only nitpicky stuff -- I am quite happy
with your code.
Some notes:
- You can of course use a switch statement as character
constants are of integer type. I do not think worth it in this
case but wanted to mention it.
- You can name your variables in a way which tells more about them
(helps to avoid mistakes when you want to output their values).
- If you redirect a file to stdin, "int" variables might not be
enough as they only only are guaranteed to hold exp2(15)-1.
I would rather count using unsigned long, size_t or (if available)
uintmax_t.
- blank probably means ' ', but is not properly defined in the standard.
See also isblank(), isspace().


Cheers
Michael
 
M

Merrill & Michele

The arguments orange and apple are not used.

Fruits, nuts and Dutchmen hold places for me.
Michael Mair wrote:
It is open to debate but there are many people who think it is
safer to say
return 0;
as this does not mask an error when you are mistyping return and
do it so awkwardly that it becomes the name of a function, (say
void retrun (int);

Mistyping is a big issue with my lumberjack hands. That's one of the
reasons I lean towards an IDE.
Michael wrote:
I took this as a request for code review.
As you see from my comments -- only nitpicky stuff -- I am quite happy
with your code.
Some notes:
- You can of course use a switch statement as character
constants are of integer type. I do not think worth it in this
case but wanted to mention it.
- You can name your variables in a way which tells more about them
(helps to avoid mistakes when you want to output their values).
- If you redirect a file to stdin, "int" variables might not be
enough as they only only are guaranteed to hold exp2(15)-1.
I would rather count using unsigned long, size_t or (if available)
uintmax_t.
- blank probably means ' ', but is not properly defined in the standard.
See also isblank(), isspace().

Files will ultimately be the way I deal with data, because I loathe the
keyboard, but if this code is solid, then there's a fly in the ointment.
How does one enter an enter? Type really quickly? MPJ
 
K

Keith Thompson

Merrill & Michele said:
The following is my best attempt to solve the exercise in the subject line
whose simple request is to write a program that counts blanks, tabs and
newlines.

#include <stdio.h>
int main(int orange, char **apple)
{
int c,n1,n2,n3;
n1=n2=n3=0;
while((c=getchar()) != EOF)
{
if (c=='\n')
++n1;
else if (c=='\t')
++n2;
else if (c==' ')
++n3;
}
printf("%d %d %d\n",n1,n2,n3);
return (0);
}

This compiles, links and behaves on my windows platform except for the
newline character. If your response to me is that I'm an idiot, you are
probably correct, but I would prefer that you show such condition in light
of this code. ++Thanks. MPJ

I don't see any real problem with your program. I do have some
stylistic quibbles; I'll get to that later.

I compiled and ran the program myself, and it seems to work correctly.
Examining the code, I don't see any reason why it shouldn't. I
applaud you for showing us a complete compilable program that exhibits
the problem; far too many posters fail to do so, leaving us to guess
what the actual program looks like.

Unfortunately, you've left us to guess what the problem is. You say
that it behaves "except for the newline character". What exactly do
you mean by that? For a given input, what output are you actually
getting, and what output did you expect? (If I had to guess, I'd say
that the program is behaving correctly, and your expectation is
incorrect.)

As for style concerns, your indentation is too narrow and is not
consistent, and it's best to use more blanks (after commas and around
most operators). Here's a modified version of your program, changing
only indentation and spacing:

#include <stdio.h>
int main(int orange, char **apple)
{
int c, n1, n2, n3;
n1 = n2 = n3 = 0;
while ((c=getchar()) != EOF)
{
if (c == '\n')
++n1;
else if (c == '\t')
++n2;
else if (c == ' ')
++n3;
}
printf("%d %d %d\n", n1, n2, n3);
return (0);
}

I didn't add spacing around the "=" in "c=getchar()" so as to
emphasize the grouping.

Your use of "orange" and "apple" as the names of the arguments to main
is perfectly legal. It's also useless and annoying. The universal
convention is to use the names "argc" and "argv". By changing these
to "orange" and "apple", you make your code more difficult to read,
with no benefit whatsoever. For that matter, you don't use the
arguments, so you might as well use "int main(void)".

The parentheses around the argument to return are perfectly legal, but
unnecessary and potentially misleading. A return statement is not a
function call; your code is clearer if you don't make it look like
one. This isn't a big deal though; nobody reading your code is likely
to be confused.

I usually avoid declaring more than one variable on a line. If I'm
going to assign a value to the variable, I'd rather do it as an
initialization rather than as a separate assignment statement; it's
clearer and less error-prone.

If an "if" or other control statement controls only a single
statement, it doesn't have to be surrounded by curly braces. Strictly
speaking, since the "if ... else if ... else if" is a single
statement, the braces associated with the "while" are unnecessary.
Nevertheless, it's a very good idea to include them anyway. In fact,
I would go even farther; I *always* use braces in control statements,
even if they surround just a single simple statement (unless I put the
whole thing on one line, but that's rare). It gives the code a more
consistent look, and it avoids errors when I want to add another
statement. I suspect most C programmers would disagree with me on
this point. (It's a habit I picked up from Perl, which requires the
braces.)

(If I felt like being overly terse, I might write:

if (c == '\n') ++n1;
else if (c == '\t') ++n2;
else if (c == ' ') ++n3;

but that makes adding more statements even more difficult.)

The names n1, n2, and n3 are extremely unclear. It's not that
important for a tiny program like this, but for larger programs it
becomse extremely important to pick meaningful variable names.

Here's another version of your program, incorporating these points
(and using the brace style that I happen to prefer):

#include <stdio.h>
int main(void)
{
int c;
int newlines = 0;
int tabs = 0;
int blanks = 0;

while ((c=getchar()) != EOF) {
if (c == '\n') {
newlines ++;
}
else if (c == '\t') {
tabs ++;
}
else if (c == ' ') {
blanks ++;
}
}
printf("%d %d %d\n", newlines, tabs, blanks);
return 0;
}

Finally, I'd probably use a switch statement rather than a chain of if
statements.
 
K

Keith Thompson

Merrill & Michele said:
Files will ultimately be the way I deal with data, because I loathe the
keyboard, but if this code is solid, then there's a fly in the ointment.
How does one enter an enter? Type really quickly? MPJ

Um, there should be a key on your keyboard marked "Enter". It might
be marked "Return". Press it.

Was that really what you're asking?
 
M

Merrill & Michele

"Keith Thompson" <[email protected]>
I don't see any real problem with your program. I do have some
stylistic quibbles; I'll get to that later.

I compiled and ran the program myself, and it seems to work correctly.
Examining the code, I don't see any reason why it shouldn't. I
applaud you for showing us a complete compilable program that exhibits
the problem; far too many posters fail to do so, leaving us to guess
what the actual program looks like.

Unfortunately, you've left us to guess what the problem is. You say
that it behaves "except for the newline character". What exactly do
you mean by that? For a given input, what output are you actually
getting, and what output did you expect? (If I had to guess, I'd say
that the program is behaving correctly, and your expectation is
incorrect.)

As for style concerns, your indentation is too narrow and is not
consistent, and it's best to use more blanks (after commas and around
most operators). Here's a modified version of your program, changing
only indentation and spacing:

#include <stdio.h>
int main(int orange, char **apple)
{
int c, n1, n2, n3;
n1 = n2 = n3 = 0;
while ((c=getchar()) != EOF)
{
if (c == '\n')
++n1;
else if (c == '\t')
++n2;
else if (c == ' ')
++n3;
}
printf("%d %d %d\n", n1, n2, n3);
return (0);
}

I didn't add spacing around the "=" in "c=getchar()" so as to
emphasize the grouping.

Your use of "orange" and "apple" as the names of the arguments to main
is perfectly legal. It's also useless and annoying. The universal
convention is to use the names "argc" and "argv". By changing these
to "orange" and "apple", you make your code more difficult to read,
with no benefit whatsoever. For that matter, you don't use the
arguments, so you might as well use "int main(void)".

The parentheses around the argument to return are perfectly legal, but
unnecessary and potentially misleading. A return statement is not a
function call; your code is clearer if you don't make it look like
one. This isn't a big deal though; nobody reading your code is likely
to be confused.

I usually avoid declaring more than one variable on a line. If I'm
going to assign a value to the variable, I'd rather do it as an
initialization rather than as a separate assignment statement; it's
clearer and less error-prone.

If an "if" or other control statement controls only a single
statement, it doesn't have to be surrounded by curly braces. Strictly
speaking, since the "if ... else if ... else if" is a single
statement, the braces associated with the "while" are unnecessary.
Nevertheless, it's a very good idea to include them anyway. In fact,
I would go even farther; I *always* use braces in control statements,
even if they surround just a single simple statement (unless I put the
whole thing on one line, but that's rare). It gives the code a more
consistent look, and it avoids errors when I want to add another
statement. I suspect most C programmers would disagree with me on
this point. (It's a habit I picked up from Perl, which requires the
braces.)

(If I felt like being overly terse, I might write:

if (c == '\n') ++n1;
else if (c == '\t') ++n2;
else if (c == ' ') ++n3;

but that makes adding more statements even more difficult.)

The names n1, n2, and n3 are extremely unclear. It's not that
important for a tiny program like this, but for larger programs it
becomse extremely important to pick meaningful variable names.

Here's another version of your program, incorporating these points
(and using the brace style that I happen to prefer):

#include <stdio.h>
int main(void)
{
int c;
int newlines = 0;
int tabs = 0;
int blanks = 0;

while ((c=getchar()) != EOF) {
if (c == '\n') {
newlines ++;
}
else if (c == '\t') {
tabs ++;
}
else if (c == ' ') {
blanks ++;
}
}
printf("%d %d %d\n", newlines, tabs, blanks);
return 0;
}

Finally, I'd probably use a switch statement rather than a chain of if
statements.

Thank you for your attention. The stylistic stuff I have to see as a hard
copy, but I wanted to get at the crux of what's not working for me. I
invoke the executable and am presented with a window. In order for any
keystroke to processed, I must hit 'enter.' Thus, I can hit tab enter tab
enter space enter, and my output is 0 enters 2 tabs 1 space. When I hit
enter enter enter enter, I get three zeroes. I swear I remember Heathfield
saying something about getchar.

That I need to wait to read something that comes off the net on ink and
paper in my study is as high a compliment as I give. MPJ
 
K

Keith Thompson

Merrill & Michele said:
Thank you for your attention. The stylistic stuff I have to see as a hard
copy, but I wanted to get at the crux of what's not working for me. I
invoke the executable and am presented with a window. In order for any
keystroke to processed, I must hit 'enter.' Thus, I can hit tab enter tab
enter space enter, and my output is 0 enters 2 tabs 1 space. When I hit
enter enter enter enter, I get three zeroes. I swear I remember Heathfield
saying something about getchar.

Then your question may be topical, but the answer almost certainly
isn't.

You're running the program under MS Windows, right? If you invoke an
executable other than from a command prompt, I don't know what that
does to the stdin, stdout, and stderr streams.

<OT>
You might try running the program from a command prompt; enter
control-Z on a line by itself to indicate the end of your input.
</OT>
 
M

Mike Wahler

I swear I remember Heathfield
saying something about getchar.

Check the archives.

BTW I really miss Richard around here, and hope he returns soon. :)

-Mike
 
C

CBFalconer

Merrill said:
The following is my best attempt to solve the exercise in the
subject line whose simple request is to write a program that
counts blanks, tabs and newlines.

Which you should specify in the body, since subject lines are not
always visible when reading.
#include <stdio.h>
int main(int orange, char **apple)
{
int c,n1,n2,n3;
n1=n2=n3=0;
while((c=getchar()) != EOF)
{
if (c=='\n')
++n1;
else if (c=='\t')
++n2;
else if (c==' ')
++n3;
}
printf("%d %d %d\n",n1,n2,n3);
return (0);
}

It appears perfectly satisfactory, except it will needlessly
complain about unused parameters. In place of the obfuscated
parameter names, simply specify they are not supplied by using
void, and you can make the flow clearer by different formatting
(there are no prizes for paucity of blanks):

#include <stdio.h>
int main(void)
{
int c, n1, n2, n3;

n1 = n2 = n3 = 0;
while (EOF != (c = getchar())) {
if ('\n' == c) ++n1;
else if ('\t' == c) ++n2;
else if (' ' == c) ++n3;
}
printf("%d %d %d\n", n1, n2, n3);
return (0);
}

The formatting is purely a matter of style. The practice of
putting the constant first in equality tests makes it easier for
the compiler to pick up errors, because it can now detect the use
of '=' in place of '=='.
 
M

Mark McIntyre

The following is my best attempt to solve the exercise in the subject line
whose simple request is to write a program that counts blanks, tabs and
newlines.

#include <stdio.h>
int main(int orange, char **apple)

I realise you're doing this because you realised the param names are
irrelevant, but really, don't do it. Its pointless and just annoys &
confuses people. If you did this in a commercial environment you might get
a warning for fooling about, and if you did it in interview you might be
considererd too foolish to employ.
This compiles, links and behaves on my windows platform except for the
newline character.

In what way doesn't it work for the newline character? Please explain more
clearly.
 
S

Simon Richard Clarkstone

Merrill said:
The following is my best attempt to solve the exercise in the subject line
whose simple request is to write a program that counts blanks, tabs and
newlines.

#include <stdio.h>
int main(int orange, char **apple)
{
int c,n1,n2,n3;
n1=n2=n3=0;
while((c=getchar()) != EOF)
{
if (c=='\n')
++n1;
else if (c=='\t')
++n2;
else if (c==' ')
++n3;
}
printf("%d %d %d\n",n1,n2,n3);
return (0);
}

This compiles, links and behaves on my windows platform except for the
newline character.
It's partially Windows/DOS's fault.
* Under UN*X and similar (where C is popular), the newline character is
a single character: '\n' == 10.
* Under DOS, and Windows (sometimes) the newline character is actually
two characters: '\r' == 13 followed by '\n' == 10.
* Under the Mac, they use '\r' == 13.
(I am not an expert, correct me if I'm wrong.)
Possibly you can solve this by re-opening the sdin stream in text mode,
so that character translations will occur. I think that this is
guaranteed to convert whatever the local newline is into a single '\n',
thus solving your problem.
(Yes, this _does_ change the number of characters, which is why the C
language seems to discourage you from using a text-mode file for random
access; you can never be sure that you aren't going to fseek() into the
middle of an multibyte character, except by using the returned value
from ftell() or similar.)
 
K

Keith Thompson

Simon Richard Clarkstone said:
Merrill & Michele wrote: [...]
This compiles, links and behaves on my windows platform except for
the
newline character.
It's partially Windows/DOS's fault.
* Under UN*X and similar (where C is popular), the newline character
is a single character: '\n' == 10.
* Under DOS, and Windows (sometimes) the newline character is actually
two characters: '\r' == 13 followed by '\n' == 10.
* Under the Mac, they use '\r' == 13.
(I am not an expert, correct me if I'm wrong.)

That shouldn't be relevant; the standard input, output, and error
streams are text streams.
 
M

Merrill & Michele

Keith Thompson said:
Simon Richard Clarkstone said:
Merrill & Michele wrote: [...]
This compiles, links and behaves on my windows platform except for
the
newline character.
It's partially Windows/DOS's fault.
* Under UN*X and similar (where C is popular), the newline character
is a single character: '\n' == 10.
* Under DOS, and Windows (sometimes) the newline character is actually
two characters: '\r' == 13 followed by '\n' == 10.
* Under the Mac, they use '\r' == 13.
(I am not an expert, correct me if I'm wrong.)

That shouldn't be relevant; the standard input, output, and error
streams are text streams.

Thanks again for replies. I've got my theories on this misbehavior that I
will revisit at the appropriate time. Strictly speaking, I think they may
be OT. At any rate, I'm moving on. Exercise 1-9, here I come. MPJ
 
M

Merrill & Michele

:
Check the archives.

BTW I really miss Richard around here, and hope he returns soon. :)

As persons who have followed my posts know, I am new to usenet. One of the
first things I established was how to check the archives. I did so under
the mistaken assumption that once a reply was on my pc, it was there until I
dispensed with it, like, say the files that accumulates in your browser's
temp folder. That information is now lost. I have since learned to make
hard copies of stuff that I won't remember, and to place it in a notebook.
Could someone hit me again with the way to search usenet but with the
restriction to clc? ++thanks MPJ

P.S. C_Dreamer claimed that his next project was to be to write his own
language or compiler, can't remember which. I believe he needs to see the
words: pecCa fortiter.
 
M

Mike Wahler

Merrill & Michele said:
As persons who have followed my posts know, I am new to usenet. One of the
first things I established was how to check the archives. I did so under
the mistaken assumption that once a reply was on my pc, it was there until I
dispensed with it, like, say the files that accumulates in your browser's
temp folder.

In theory, yes, everything stored on your PC remains until
you remove it (but often a piece of software -- such as
a newsreader -- can be and/or is configured to automatically
remove data, e.g. after a given period of time).
That information is now lost. I have since learned to make
hard copies of stuff that I won't remember, and to place it in a notebook.
Could someone hit me again with the way to search usenet but with the
restriction to clc? ++thanks MPJ

However, when I wrote "check the archives" I didn't mean your
local files, but archives stored on a server(s) on the Internet.
google (and possibly/probably other firms) provides a central
repository of Usenet data. Visit www.groups.google.com and
use their search/filter features to find what you're looking for.

-Mike
 
C

CBFalconer

Merrill said:
As persons who have followed my posts know, I am new to usenet.
One of the first things I established was how to check the
archives. I did so under the mistaken assumption that once a
reply was on my pc, it was there until I dispensed with it, like,
say the files that accumulates in your browser's temp folder.
That information is now lost. I have since learned to make hard
copies of stuff that I won't remember, and to place it in a
notebook. Could someone hit me again with the way to search usenet
but with the restriction to clc? ++thanks MPJ

Use google. Anything posted with the anti-social X-NoArchive flag
is just plain lost. Also the threading is atrocious.

However you are better off dispensing with that buggy Outhouse
software and getting a real newsreader. XNews is good, but complex
to learn. Netscape (and Mozilla) is good. With these I can simply
copy anything I wish to retain to a special subdirectory.
 
M

Merrill & Michele

CBFalconer wrote:
Use google. Anything posted with the anti-social X-NoArchive flag
is just plain lost. Also the threading is atrocious.

However you are better off dispensing with that buggy Outhouse
software and getting a real newsreader. XNews is good, but complex
to learn. Netscape (and Mozilla) is good. With these I can simply
copy anything I wish to retain to a special subdirectory.

Thank you, Chuck, but no thanks. When you learn to program in the shadow of
Mount Rainier, you are formed from a different crucible than most.
"I support the Red Sox and any team that beats the Yankees"

"Any baby snookums can be a Yankee fan, it takes real moral
fiber to be a Red Sox fan"

I'd send you a broom and a six-pack if I knew where you lived and if it
could reach you by the time they got squished, as were my Twins. That's
ball. With computer projects, I'm not at all tolerant of losing. MPJ
 
M

Mike Wahler

Merrill & Michele said:
Thank you, Chuck, but no thanks. When you learn to program in the shadow of
Mount Rainier, you are formed from a different crucible than most.

I also live in that same 'shadow'[1] (and have actually done some
contract work for a certain local corporation, as well as being
a satisfied consumer of many of their products[2]), but I've never
limited my software (or hardware) purchases to a particular vendor.
Open your mind. Form yourself, don't let others do it. :)

[1] But learned to program in another state during a time when
computer ownership was still the domain of millionaires
and large businesses, and software prices averaged in the
thousands of dollars.

[2] OE isn't my favorite newsreader either, but I use it for
other (more pragmatic) reasons.



-Mike
 
M

Mark McIntyre

CBF wrote, but his attribution was snipped...

Thank you, Chuck, but no thanks.

Then try Agent. I have to tell you, OE is a pile of ....
When you learn to program in the shadow of
Mount Rainier, you are formed from a different crucible than most.

What? Can you keep the psychobabble to a min?
 
C

Chris Barts

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Merrill & Michele wrote:
[snip]
| Could someone hit me again with the way to search usenet but with the
| restriction to clc? ++thanks MPJ

Go to http://groups.google.com (which has searchable Usenet archives
back to 1981) and add the term 'group:comp.lang.c' before your search
terms, which can include words found in the body or the title of the post.

If you want to limit your search to one author, add the term
'author:[email protected]' (where (e-mail address removed) is the email address as it
appears in the From: field of the person's posts) to your terms.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFBcz4VBsEyCHtFPhsRAiKFAJ9pG4JicFmm6Fndq2lt+03OfCAbGgCePbVn
SNgh4pX67E0e1EHglwO0C0k=
=UiOD
-----END PGP SIGNATURE-----
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top