Alternate solution to krx113

P

Patrick M.

Hello. I just got the K&R 2nd Edition of "The C Programming Language". I
also just finished exercise 1-13, and I've coded a much shorter,
commented solution. I'm not sure if you're still updating the site
(http://users.powernet.co.uk/eton/kandr2/index.html), Richard, but if
you get the chance and feel like it, you can post the solution. I've
tested it and there seem to be no bugs from what I see...
 
O

Old Wolf

Patrick said:
Hello. I just got the K&R 2nd Edition of "The C Programming
Language". I also just finished exercise 1-13, and I've coded
a much shorter, commented solution.

I don't think yours is significantly shorter -- there seems to
be about the same amount of program logic, but Richard used
more whitespace and longer variable names than you did.

NB. I have removed some comments in the code below, because
of line-wrapping issues.
/* Print a histogram of the lengths of words in input. */
#include <stdio.h>

int main() {

long chars[12] = {0}, c = 0, wl = 0,
x = 0, n = 0, p = 0,
mwl = 0, q = 0;

I think I prefer the version with descriptive variable names :)
while ((c = getchar())) {

This will exit the loop if the input contains a zero-valued
character, did you intend this? (If you are going to follow
the philosophy Richard suggests, "be liberal in what you accept,
strict in what you produce"), you should probably allow a
zero character, and consider it to be whitespace.
++wl;
++p;
if (c == '\n' || c == '\t' || c == '\b' || c == ' ' || c == EOF) {
/* reset these variables because if you don't,
the app will think the words are much longer */
--wl;
--p;

AFAICS, you do not use 'p' anywhere in the program, except for
incrementing and decrementing it at this point. What is it for?
if (wl >= 11) {
++chars[11]; }
else {
++chars[wl]; }
wl = 0;

There are indenting problems here -- you've used spaces for the
"if" but tabs for the "++chars" line. In my text editor (4 space
tabs) it looks like the ++chars is out-dented 1 character (very
unreadable). When posting to Usenet it's a good idea to avoid tabs.
}

if (c == EOF) { /* EOF received... break */
break; }

Good (IMHO). In Richard's version, he introduces a new variable
"done", whose sole purpose is a long-winded version of "break".
I'd like to hear his rationale on that...
}
printf("\n");
/* We're going to want to find the max times a word length
appeared, and set mwl to that value */
for (x = 1; x <= 11; ++x) {

For maintainability, it would be a good idea to avoid the magic
number "11" here -- since it depends on the size of the chars[] array,
its derivation should reflect that. Same goes for the other
magic numbers in your code.
if (chars[x] > mwl) {
mwl = chars[x]; }
}

if (mwl >= 1)
for (x = mwl; x >= 1; --x) {
/* note to self: formatting printf("%d") with a
number before it, it will right justify it by
that number MINUS the amount of digits %d
contains. Remember this!!!*/
printf("%20d |", x);

This means that x will be right-justified in a field of width 20.
(Note that if x has more than 20 digits, then all of x's digits
will be printed -- it won't cut off at 20).
while (++n <= 11) {
if (chars[n] >= x) {

/* must be done for formatting purposes */
if (++q == 1) {
printf(" *"); }
else {
printf(" *"); }

}
else {
printf(" ");
}

}
printf("\n");
n = 0;
q = 0;
}

/* spaces in 1st printf must be 2 more than right-justified
value above, spaces in second must be one more than 1st
printf space count */
printf(" +-");
for (x = 0; x <= 31; ++x) {
printf("-");
}
printf("\n ");

Some more magic numbers / magic space counts.
for (x = 1; x <= 11; ++x) {
if (x == 11) {
printf(">10\n"); }
else {
printf("%2d ", x); }
}

That loop would be better written as (braces optional, of course):

for (x = 1; x < 11; ++x)
printf("%2d ", x);
printf(">10\n");
return 0;
}

Pretty good overall :)
 
P

Patrick M.

Old said:
I don't think yours is significantly shorter -- there seems to
be about the same amount of program logic, but Richard used
more whitespace and longer variable names than you did.

NB. I have removed some comments in the code below, because
of line-wrapping issues.

Well, the way mine is, it's 20 lines less than Richard's. True, it's not
significant, but I think it's sort of cool. ;)
/* Print a histogram of the lengths of words in input. */
#include <stdio.h>

int main() {

long chars[12] = {0}, c = 0, wl = 0,
x = 0, n = 0, p = 0,
mwl = 0, q = 0;

I think I prefer the version with descriptive variable names :)
while ((c = getchar())) {

This will exit the loop if the input contains a zero-valued
character, did you intend this? (If you are going to follow
the philosophy Richard suggests, "be liberal in what you accept,
strict in what you produce"), you should probably allow a
zero character, and consider it to be whitespace.

What do you mean, zero character? The only way it exits the loop is if
there is EOF.
AFAICS, you do not use 'p' anywhere in the program, except for
incrementing and decrementing it at this point. What is it for?

Ok, my bad, I forgot to get rid of those variables. I must've used them
when I was experiementing and creating the code, and never got rid of them.
if (wl >= 11) {
++chars[11]; }
else {
++chars[wl]; }
wl = 0;

There are indenting problems here -- you've used spaces for the
"if" but tabs for the "++chars" line. In my text editor (4 space
tabs) it looks like the ++chars is out-dented 1 character (very
unreadable). When posting to Usenet it's a good idea to avoid tabs.

Another "my bad". I believe it's because I was editing code, and emacs
never re-indented it.
Good (IMHO). In Richard's version, he introduces a new variable
"done", whose sole purpose is a long-winded version of "break".
I'd like to hear his rationale on that...

Thanks. Yes, another way is to use a variable, which I've done before,
but in this case I decided to use "break" so it didn't have to go
through the rest of the while loop before exiting.
}
printf("\n");
/* We're going to want to find the max times a word length
appeared, and set mwl to that value */
for (x = 1; x <= 11; ++x) {

For maintainability, it would be a good idea to avoid the magic
number "11" here -- since it depends on the size of the chars[] array,
its derivation should reflect that. Same goes for the other
magic numbers in your code.

That's true... I'll add a constant and fix that up :)
if (chars[x] > mwl) {
mwl = chars[x]; }
}

if (mwl >= 1)
for (x = mwl; x >= 1; --x) {
/* note to self: formatting printf("%d") with a
number before it, it will right justify it by
that number MINUS the amount of digits %d
contains. Remember this!!!*/
printf("%20d |", x);

This means that x will be right-justified in a field of width 20.
(Note that if x has more than 20 digits, then all of x's digits
will be printed -- it won't cut off at 20).
while (++n <= 11) {
if (chars[n] >= x) {

/* must be done for formatting purposes */
if (++q == 1) {
printf(" *"); }
else {
printf(" *"); }

}
else {
printf(" ");
}

}
printf("\n");
n = 0;
q = 0;
}

/* spaces in 1st printf must be 2 more than right-justified
value above, spaces in second must be one more than 1st
printf space count */
printf(" +-");
for (x = 0; x <= 31; ++x) {
printf("-");
}
printf("\n ");

Some more magic numbers / magic space counts.
for (x = 1; x <= 11; ++x) {
if (x == 11) {
printf(">10\n"); }
else {
printf("%2d ", x); }
}

That loop would be better written as (braces optional, of course):

for (x = 1; x < 11; ++x)
printf("%2d ", x);
printf(">10\n");

Yes, that is a better version...
Pretty good overall :)

Thanks for the useful critique... I'll keep those suggestions in mind
and edit the code accordingly. So far I really like C and I can't wait
till I gain a good knowledge of it... which comes with experience, of
course. I've got some really sweet projects in mind when I'm experienced
enough with C. :)

Thanks again!
 
P

Patrick M.

Patrick said:
What do you mean, zero character? The only way it exits the loop is if
there is EOF.

Nevermind, I see what you mean. C reads this as "while (c = getchar() !=
0)" since the truth value in most things in C is 1, and therefore while
it's 1 it will loop, and when it reads a zero value it stops looping.
The only way I see to fix this is to do what Richard did (By the way, I
didn't look at his code until after I created it my own way) and replace
that with "while (var == 1)". Any other suggestions?
 
E

Eric Sosman

Patrick M. wrote On 09/23/05 15:10,:
Nevermind, I see what you mean. C reads this as "while (c = getchar() !=
0)"

No; that's something else again.

while ((c = getchar())) /* 1 */
while (c = getchar() != 0) /* 2 */
while ((c = getchar()) != 0) /* 3 */

Lines 1 and 3 are equivalent; 2 is perfectly legal C but
has, er, "issues."
since the truth value in most things in C is 1, and therefore while
it's 1 it will loop, and when it reads a zero value it stops looping.

For testing purposes (if, while, for, ...), zero is
false and any non-zero value at all is true: 1, -2, 3.14,
stdin, &c, ...

Operators that produce truth values (==, >, !=, ...)
yield zero for false and one for true. Note that the
The only way I see to fix this is to do what Richard did (By the way, I
didn't look at his code until after I created it my own way) and replace
that with "while (var == 1)". Any other suggestions?

I don't know what Richard did, but the most obvious
pattern is

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

Patrick M.

Eric said:
I don't know what Richard did, but the most obvious
pattern is

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

Yes, I know that, but it creates problems in my application.
 
K

Keith Thompson

Eric Sosman said:
Patrick M. wrote On 09/23/05 15:10,:

No; that's something else again.

while ((c = getchar())) /* 1 */
while (c = getchar() != 0) /* 2 */
while ((c = getchar()) != 0) /* 3 */

Lines 1 and 3 are equivalent; 2 is perfectly legal C but
has, er, "issues."


For testing purposes (if, while, for, ...), zero is
false and any non-zero value at all is true: 1, -2, 3.14,
stdin, &c, ...

Operators that produce truth values (==, >, !=, ...)
yield zero for false and one for true. Note that the
<ctype.h> functions (isupper(), isdigit(), ...) are not
operators, and can yield "true" values other than one.

Yes. See also section 9 of the C FAQ.
I don't know what Richard did, but the most obvious
pattern is

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

But he does some processing inside the loop when getchar() returns EOF.

Probably the best approach is to use

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

and move that processing outside the loop.

Also, why is c of type long? It should be an int.
 
R

Richard Heathfield

Old Wolf said:
I don't think yours is significantly shorter -- there seems to
be about the same amount of program logic, but Richard used
more whitespace and longer variable names than you did.

Yep. I find that I can most easily maintain my own code if I can read and
understand it, and to that end I use whitespace and identifier names in
what I hope is a consistent and non-confusing way. If I were going for
brevity, I could obviously crunch everything up a lot more, but I prefer to
write in an exegetic style unless I'm deliberately going for obfuscation
(which is pretty rare, for me).
Good (IMHO). In Richard's version, he introduces a new variable
"done", whose sole purpose is a long-winded version of "break".
I'd like to hear his rationale on that...

I quite often get asked this. :)

Again, this is to do with my own imperfection. I'm actually pretty lousy at
figuring out what code is supposed to be doing, and since I have to
maintain my own code - often after months or even several years of not
having so much as glanced at it - I like to write it in such a way that I
can pick it up again easily later on. Since the biggest problem I have in
reading code is that of following "jump all over the shop" control flow, I
endeavoured to devise a programming style that minimised the jumpy aroundy
problems that so confuse me. To that end, I decided some years ago to try
to keep to a regimen of "one entry, one exit" for all functions and all
loops. On some (fairly rare) occasions I have departed from that, when I
think it's necessary to do so. On somewhat more frequent occasions I have
departed from it not because it's necessary but because it makes the code
slightly quicker to type - and on such occasions I invariably find myself
going back to that code to "do it properly", so to speak. I guess that's my
conscience speaking. :)

A word about the answers site may be in order. I started that off back in
January 2000 (I think), and kept it going for a couple of years, but I
found it harder and harder to keep apace of contributions, notably from one
Gregory Pietsch (whom I seem to recall I treated most abominably, for he
sent me loads of solutions which I never quite got around to posting - I
hope he's forgiven me by now). Eventually I simply gave up altogether.

I cannot in all conscience commit myself to resurrecting the answers site,
for I simply don't have the time. In any case, I no longer own that account
- it's only still up either out of the kindness of Powernet's heart or
because it's been overlooked somehow - so I couldn't update it if I wanted
to.

If someone with more time to spare than me wants to grab all the solutions
from that site while it's still up, and use it as the basis for a
rejuvenated answers site, I have no problem with that personally. I don't
know what copyright law says about the matter, so whoever takes up the
baton may need to contact the authors of the individual solutions to ask
their permission to reproduce those solutions.
 
G

Gregory Pietsch

Richard said:
A word about the answers site may be in order. I started that off back in
January 2000 (I think), and kept it going for a couple of years, but I
found it harder and harder to keep apace of contributions, notably from one
Gregory Pietsch (whom I seem to recall I treated most abominably, for he
sent me loads of solutions which I never quite got around to posting - I
hope he's forgiven me by now). Eventually I simply gave up altogether.

I forgive you, Richard. Are we still friends?

I believe that there was only one or two that I sent you that never
showed up on the site. By now, I've lost them, so I can't post them
here.

I know it's sometimes difficult for one person to maintain a giant
monstrosity of code. It's tough for me with FreeDOS Edlin if many
people send in patch after patch after patch because I'm the only guy
checking them in and I have to read them all first. Sometimes the
additional code looks like a bag on the side of the main code, and I
know that if the glue were better I could chuck most of it retaining
the same functionality, which is what I did with the Japanese code in
Edlin.
I cannot in all conscience commit myself to resurrecting the answers site,
for I simply don't have the time. In any case, I no longer own that account
- it's only still up either out of the kindness of Powernet's heart or
because it's been overlooked somehow - so I couldn't update it if I wanted
to.

That, and it still gets hits from those curious about K&R2 and the
comp.lang.c gurus who wrote such wondrous melodies. I found four
mirrors of it by searching on my name (in Brazil, Turkey, South Korea,
and Russia) at various times.
If someone with more time to spare than me wants to grab all the solutions
from that site while it's still up, and use it as the basis for a
rejuvenated answers site, I have no problem with that personally. I don't
know what copyright law says about the matter, so whoever takes up the
baton may need to contact the authors of the individual solutions to ask
their permission to reproduce those solutions.

I think Kamilche already did. I sent her some answers to look at and
post, such as 5-6 which I did for Richard Heathfield's site. I also
sent her my 1-23 answer that is on RH's site, and she publicly freaked
at how clever it was.

I personally don't have a problem with reproducing my code. In fact,
it's fun to find out where the code goes and find out where my
programming fame has led.

Gregory Pietsch (the above e-mail address doesn't work anymore, use
gpietsch at comcast dot net)
 
B

Ben Pfaff

Richard Heathfield said:
A word about the answers site may be in order. I started that off back in
January 2000 (I think), and kept it going for a couple of years, but I
found it harder and harder to keep apace of contributions, notably from one
Gregory Pietsch (whom I seem to recall I treated most abominably, for he
sent me loads of solutions which I never quite got around to posting - I
hope he's forgiven me by now). Eventually I simply gave up altogether.

A collection of K&R answers would be worthy of inclusion in the
proposed clc wiki, in my opinion.
 
F

Flash Gordon

Ben said:
A collection of K&R answers would be worthy of inclusion in the
proposed clc wiki, in my opinion.

Yes, I agree.

I also note that Gregory Pietsch gave his permission for his answers to
be reproduced in another post.
 
B

Ben Pfaff

Flash Gordon said:
Yes, I agree.

I also note that Gregory Pietsch gave his permission for his answers to
be reproduced in another post.

I think I contributed some answers to Richard Heathfield's
collection. If so, I hereby grant permission to include them in
any forthcoming clc wiki.
 
R

Richard Heathfield

Gregory Pietsch said:
I forgive you, Richard. Are we still friends?

Whew! I feel much better now. :)
I believe that there was only one or two that I sent you that never
showed up on the site. By now, I've lost them, so I can't post them
here.

If I ever come across them... (it's not impossible that they're lurking on a
laptop somewhere).
I think Kamilche already did. I sent her some answers to look at and
post, such as 5-6 which I did for Richard Heathfield's site. I also
sent her my 1-23 answer that is on RH's site, and she publicly freaked
at how clever it was.

Got a URL? I'd be delighted to link to her site from my own C Resources
page.
 
G

Gregory Pietsch

Richard said:
Gregory Pietsch said:


Whew! I feel much better now. :)


If I ever come across them... (it's not impossible that they're lurking on a
laptop somewhere).


Got a URL? I'd be delighted to link to her site from my own C Resources
page.

http://www.kamilche.com/c is where her K&R2 answers are. -- Gregory
Pietsch
 

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

Members online

Forum statistics

Threads
474,169
Messages
2,570,920
Members
47,462
Latest member
ChanaLipsc

Latest Threads

Top