K&R2, section1.6, exercise 1-13

A

arnuld

this programme runs without any error but it does not do what i want
it to do:

------------- PROGRAMME --------------
/* K&R2, section 1.6 Arrays; Exercise 1-13.

STATEMENT:
Write a program to print a histogram of the lengths of words in its
input.
It is easy to draw the histogram with the bars horizontal; a vertical
orientation is more challenging.


Method:

1.) we will store lenth of each wordn an array.
2.) for keeping simplicity, array size is 1000, i.e.
it can hold only 1000 words.
3.) after EOF is encountered then the "a Hostogram of starts ( * )
"will be
printed on the screen.

4.) each line of histogram will contain number of "stars" == length
of that word.

*/

#include <stdio.h>

#define IN 1
#define OUT 0
#define MAXWORDS 1000

int main()
{
int c;
int i = 0;
int aindex = 0;
int j = 0; /* "i,j,count" are general index counters */

int nc = 0; /* length of word or number of characters in a word */

int lwords[MAXWORDS + 1];

int nw = 0; /* number of words */

/* length of each word is stored in this array
and will be printed in the end */

int state = IN;

while( ((c = getchar()) != EOF) && (nw <= MAXWORDS) )
{
++nc;

if(c == ' ' || c == '\t' || c == '\n')
{
state = OUT;
--nc;
}

else if(state == OUT)
{
lwords[aindex++] = nc;
++nw;
state = IN;
}

}

printf("---------- printing HISTOGRAM -----------\n");

for(i = 0; i < aindex; ++i)
{
for(j = 0; j < lwords; ++j)
putchar('*');

putchar('\n');
}

return 0;
}
------------- OUTPUT ---------------
[arch@voodo kr2]$ gcc -std=c99 -pedantic -Wall -Wextra ex_1-13.c
[arch@voodo kr2]$ ./a.out
like
---------- printing HISTOGRAM -----------
[arch@voodo kr2]$
 
U

user923005

I don't recall if you are supposed to have access to ispunct() and
isspace() by that point in the book (K&R2 1.6) or not. Functions
isn't until 1.7 but we have been using some of the library functions
right from the get-go. But for a word counter, they (the is*()
functions and strtok()) seem like natural tools. Also, the evil and
cantankerous strtok() can be used.

A simple way to start might be to use the previous incarnation of the
word-count program on page 20.
 
A

arnuld

I don't recall if you are supposed to have access to ispunct() and
isspace() by that point in the book (K&R2 1.6) or not. Functions
isn't until 1.7 but we have been using some of the library functions
right from the get-go. But for a word counter, they (the is*()
functions and strtok()) seem like natural tools. Also, the evil and
cantankerous strtok() can be used.

you are using some really STRANGE words like "strtok".

A simple way to start might be to use the previous incarnation of the
word-count program on page 20.

my code *is* the modified-reincarnation of that programme. without
this modification, it does not work
 
G

Gawain

Change the code like this, maybe you can get you want.

if(c == ' ' || c == '\t' || c == '\n')
{
state = OUT;
--nc;
}


if(state == OUT)
{
lwords[aindex++] = nc;
++nw;
state = IN;
nc = 0;
}
 
A

arnuld

Change the code like this, maybe you can get you want.

if(c == ' ' || c == '\t' || c == '\n')
{
state = OUT;
--nc;
}

if(state == OUT)
{
lwords[aindex++] = nc;
++nw;
state = IN;
nc = 0;
}

actually i did that just 2 second before i saw your post :)

but it does not work :-(. i will try more after Lunch.

see you after Lunch....
 
P

p_cricket_guy

Change the code like this, maybe you can get you want.
if(c == ' ' || c == '\t' || c == '\n')
{
state = OUT;
--nc;
}
if(state == OUT)
{
lwords[aindex++] = nc;
++nw;
state = IN;
nc = 0;
}

actually i did that just 2 second before i saw your post :)

but it does not work :-(. i will try more after Lunch.

see you after Lunch....


That should work .. Gawain has suggested two changes:
1. "else if" changed to "if"
2. assign "nc = 0" under the above condition.

Did you try with both these changes ?

PS: My apologies if this post does not appear properly.
Right now, my google interface is not displaying the
cursor as I type :-(
 
A

arnuld

That should work .. Gawain has suggested two changes:
1. "else if" changed to "if"

SORRY, i overlooked "if". i thought it was same as my code "else if".

2. assign "nc = 0" under the above condition.

i did that with "else if" and it did not work.
Did you try with both these changes ?

with this code changed to "if" and "nc = 0". it works :) except of a
problem. here is the output:

[arch@voodo kr2]$ ./a.out
like---------- printing HISTOGRAM -----------
[arch@voodo kr2]$ ./a.out
like
---------- printing HISTOGRAM -----------
****
[arch@voodo kr2]$ ./a.out
like this about a
---------- printing HISTOGRAM -----------
****
****





*****


*
[arch@voodo kr2]$


it produces extra "newlines" for "tabs" entered.

how can i make it consistent ?

PS: My apologies if this post does not appear properly.
Right now, my google interface is not displaying the
cursor as I type :-(

i thought i was the only one who is facing this weired problem. i got
company now :)
 
A

arnuld

Which part don't you understand?

nearly, 90% of the solution. it is weired, something like a "syntax-
mess". i will ask in parts:

1.) what exactly these variables are doing:

long lengtharr[MAXWORDLEN + 1]; /* i know this is an array */
int firstletter = 1;
long thisval = 0;
long maxval = 0;
int thisidx = 0;
int done = 0;

2.) what is this code doing:

if(wordlen > 0) /* i know what this line is doing */
{
thisval = ++lengtharr[wordlen - 1];
if(thisval > maxval)
{
maxval = thisval;
 
R

Richard Heathfield

arnuld said:
Which part don't you understand?

nearly, 90% of the solution. it is weired, something like a "syntax-
mess". i will ask in parts:

1.) what exactly these variables are doing:

long lengtharr[MAXWORDLEN + 1]; /* i know this is an array */
int firstletter = 1;
long thisval = 0;
long maxval = 0;
int thisidx = 0;
int done = 0;

2.) what is this code doing:

if(wordlen > 0) /* i know what this line is doing */
{
thisval = ++lengtharr[wordlen - 1];

Here, we've counted the number of letters in the word. We've already
checked that it does not exceed the maximum length we're catering for,
so we want to record its length in the array of word length counts. For
example, let's say it's five letters long. Then we want to increase (by
one) the number of five-letter words we've counted so far. The right
place in the array is 'length of word, minus one' (because array
indices start at 0, not 1). That explains wordlen - 1. We use that as
an index into the array: lengtharr[wordlen - 1];

We want to add 1 to it: ++lengtharr[wordlen - 1];

and we want to know whether this new value has exceeded our currently
stored maximum count. Because we'll need to use the expression twice,
it's convenient to store it in an object:

thisval = ++lengtharr[wordlen - 1];

If it has exceeded the currently stored maximum, then obviously we have
a new maximum. (We need this value later, so that we know how to start
displaying our data.) The following code accomplishes this:
 
A

arnuld

Here, we've counted the number of letters in the word. We've already
checked that it does not exceed the maximum length we're catering for,
so we want to record its length in the array of word length counts.

this array stores length of all the words and in array, each element
corresponds to length of an input word.

right ?

For
example, let's say it's five letters long. Then we want to increase (by
one) the number of five-letter words we've counted so far.

why we want to increase the length of an input ?
 
R

Richard Heathfield

arnuld said:
this array stores length of all the words and in array, each element
corresponds to length of an input word.

right ?

lengtharr[0] counts all the words of length 1.
lengtharr[1] counts all the words of length 2.
lengtharr[2] counts all the words of length 3.
lengtharr[3] counts all the words of length 4.
lengtharr[4] counts all the words of length 5.

etc, except that

lengtharr[MAXWORDLEN] counts all the words of length *greater* than
MAXWORDLEN.

So if MAXWORDLEN is 10, as in the example, then an input like this:

Once upon a time there was a wonderfully obscure little programming
language called C which was so amazingly powerful that it could do six
impossible things before breakfast which is quite a stunning
achievement for such a tiny language and who knows what it might be
able to accomplish if thaumaturgically inclined philosophers were to
grant it mystical powers

would be processed like this:

'Once' has length 4, so wordlen - 1 is 3, so we increment lengtharr[3].
lengtharr now looks like this:

{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }
^
|
lengtharr[3] counts words of length 4


'upon' has length 4, so wordlen - 1 is 3, so we increment lengtharr[3].
lengtharr now looks like this:

{ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }
^
|
lengtharr[3] counts words of length 4

The '2' means "we have met 2 words of length 4"

'a' has length 1, so wordlen - 1 is 0, so we increment lengtharr[0].
lengtharr now looks like this:

{ 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }
^
|
lengtharr[0] counts words of length 1

The '1' means "we have met 1 word of length 1"

'time' has length 4, so wordlen - 1 is 3, so we increment lengtharr[3].
lengtharr now looks like this:

{ 1, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0 }
^
|
lengtharr[3] counts words of length 4

The '3' means "we have met 3 words of length 4"

Work the rest of the example yourself.
why we want to increase the length of an input ?

We're not. We're COUNTING the words that have that length. When we
encounter another word of that length, we add one to the count, not to
the length!
 
M

mark_bluemel

nearly, 90% of the solution. it is weired, something like a "syntax-
mess".

This is not a polite way to explain to the original coder what you
don't understand about their code.
i will ask in parts:

1.) what exactly these variables are doing:

long lengtharr[MAXWORDLEN + 1]; /* i know this is an array */
It's an array holding counts of words, by word length. C arrays start
at [0], but words are no less than one letter, so lengtharr[0] is the
count of words which are one letter long.

As words more than MAXWORDLEN (10 in the example) are not otherwise
handled, Richard added a spare element to the array for all over-sized
words.
int firstletter = 1;

This is a flag to handle the special case of the first character read
from the file.
long thisval = 0;
long maxval = 0;

These track the biggest word count we've found.
int thisidx = 0;

This is used basically as an index which varies between 0 and
MAXWORDLEN.
int done = 0;

As mentioned in the header, this is used for handling end of input.
2.) what is this code doing:

if(wordlen > 0) /* i know what this line is doing */
{
thisval = ++lengtharr[wordlen - 1];

increment the count of words of this length, and get the value of the
incremented count.
if(thisval > maxval)
{
maxval = thisval;

Adjust the maximum count if necessary.
 
A

arnuld

lengtharr[0] counts all the words of length 1.
lengtharr[1] counts all the words of length 2.
lengtharr[2] counts all the words of length 3.
lengtharr[3] counts all the words of length 4.
lengtharr[4] counts all the words of length 5.


this confused me even MORE :-(
So if MAXWORDLEN is 10, as in the example, then an input like this:

Once upon a time there was a wonderfully obscure little programming
language called C which was so amazingly powerful that it could do six
impossible things before breakfast which is quite a stunning
achievement for such a tiny language and who knows what it might be
able to accomplish if thaumaturgically inclined philosophers were to
grant it mystical powers

would be processed like this:

'Once' has length 4, so wordlen - 1 is 3, so we increment lengtharr[3].
lengtharr now looks like this:

{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }
^
|
lengtharr[3] counts words of length 4

'upon' has length 4, so wordlen - 1 is 3, so we increment lengtharr[3].
lengtharr now looks like this:

{ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }
^
|
lengtharr[3] counts words of length 4

The '2' means "we have met 2 words of length 4"

'a' has length 1, so wordlen - 1 is 0, so we increment lengtharr[0].
lengtharr now looks like this:

{ 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }
^
|
lengtharr[0] counts words of length 1

The '1' means "we have met 1 word of length 1"

'time' has length 4, so wordlen - 1 is 3, so we increment lengtharr[3].
lengtharr now looks like this:

{ 1, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0 }
^
|
lengtharr[3] counts words of length 4

The '3' means "we have met 3 words of length 4"

Work the rest of the example yourself.


thanks Richard, now i understood it.


i think you need to put it in your documentation at CLC Wiki, just
above your code. the code just uses a *method* which you have
described here. i don't think a newbie can get the "method-applied" by
just looking at the mysterious code.

it was 3rd most clear explanations i have ever seen: 1st one was in
"Practical Common Lisp", 2nd one was K&R2 section 1.8.

thanks a lot and i have more questions.
 
S

sololoquist

1. histogram isto be treated as matrix of stars and spaces.
2. where no. of columns is number of words and hieght is the word
length of longest word
3. then go on printing either space or star depending on index
 
G

Gregor H.

i checked the solution at this page:

http://clc-wiki.net/wiki/K&R2_solutions:Chapter_1:Exercise_13

it is way-way complicated for me to understand.
How about the following (simple) solution?


#include <stdio.h>

#define IN 1
#define OUT 0

#define MAXLEN 20 /* max. length of a word */

/* Lengths of words (histogram with the bars horizontal) */
int main(void)
{
int c, i, j, state, len, overflow, h[MAXLEN+1];

for (i = 1; i <= MAXLEN; ++i) /* h[0] is not used */
h = 0;

len = 0;
overflow = 0;
state = OUT;

while ((c = getchar()) != EOF)
{
if (c == ' ' || c == '\n' || c == '\t')
{
if (state == IN)
{
state = OUT;

if (len <= MAXLEN) /* max. index is MAXLEN */
++h[len];
else
++overflow;

len = 0;
}
}
else
{
if (state == OUT)
state = IN;

if (c != '.' && c != '!' && c != '?' && c != ':' && c != ',' && c != ';')
len++;
}
}

printf("\n");

for (i = 1; i <= MAXLEN; ++i)
{
printf("%2d : ", i);
for (j = 0; j < h; ++j)
printf("*");
printf("\n");
}

if (overflow > 0)
{
if (overflow == 1)
printf("\n1 word has more than %d characters.\n", MAXLEN);
else
printf("\n%d words have more than %d characters.\n", overflow, MAXLEN);
}

return 0;
}


G. H.
 
B

Barry Schwarz

this programme runs without any error but it does not do what i want
it to do:

What did you want? What did you get? What is the difference between
the two if it is not immediately obvious?
------------- PROGRAMME --------------
/* K&R2, section 1.6 Arrays; Exercise 1-13.

STATEMENT:
Write a program to print a histogram of the lengths of words in its
input.
It is easy to draw the histogram with the bars horizontal; a vertical
orientation is more challenging.


Method:

1.) we will store lenth of each wordn an array.
2.) for keeping simplicity, array size is 1000, i.e.
it can hold only 1000 words.
3.) after EOF is encountered then the "a Hostogram of starts ( * )
"will be
printed on the screen.

4.) each line of histogram will contain number of "stars" == length
of that word.

It may be a language issue but the usual interpretation of this
exercise is produce a histogram that shows how many 1 letter words,
how many two letter words, etc were in the input. What you are
producing is a histogram that shows the length of first word, length
of second word, etc.
snip code


Remove del for email
 
A

arnuld

What did you want? What did you get? What is the difference between
the two if it is not immediately obvious?

what i WANTED:

I want it to produce a "horizontal histogram" which tells how many
characters were in the 1st word, how many characters were in the
second word by writing equal number of stars at the output. i want to
discard ant newlines, extra spaces (more than 1 space between the
words), tabs an newlines.

what i GOT:

it prints histogram BUT it also prints each extra space & tab as a
"newline in output".

DIFFERENCE: each extra space, tab and newline appears in the output
which must not be there.

---------- PROGRAMME -------
/* K&R2, section 1.6 Arrays; Exercise 1-13.

STATEMENT:
Write a program to print a histogram of the lengths of words in its
input.
It is easy to draw the histogram with the bars horizontal; a vertical
orientation is more challenging.


Method:

1.) we will store lenth of each word in an array.
2.) for keeping simplicity, array size is 1000, i.e.
it can hold only 1000 words.
3.) after EOF is encountered then the Hostogram will be
printed
*/

#include <stdio.h>

#define IN 1
#define OUT 0
#define MAXWORDS 1000

int main()
{
int c;
int i = 0;
int arr_index = 0;
int j = 0; /* "i,j,count" are general index counters */

int nc = 0; /* length of word or number of characters in a word */

int lwords[MAXWORDS + 1];

int nw = 0; /* number of words */

/* length of each word is stored in this array
and will be printed in the end */

int state = IN;

while( ((c = getchar()) != EOF) && (nw <= MAXWORDS) )
{
++nc;

if(c == ' ' || c == '\t' || c == '\n')
{
state = OUT;
--nc;
}

if(state == OUT)
{
lwords[arr_index++] = nc;
++nw;
state = IN;
nc = 0;
}

}

printf("---------- printing HISTOGRAM -----------\n");

/* printf("arr_index: %d\n", arr_index); */
for(i = 0; i < arr_index; ++i)
{
for(j = 0; j < lwords; ++j)
putchar('*');

putchar('\n');
}

return 0;
}


-------- OUTPUT ----------
[arch@voodo kr2]$ gcc -std=c99 -pedantic -Wall -Wextra ex_1-13.c
[arch@voodo kr2]$ ./a.out
like this
---------- printing HISTOGRAM -----------
****
****
[arch@voodo kr2]$ ./a.out
like this
---------- printing HISTOGRAM -----------
****

****
[arch@voodo kr2]$ ./a.out
like this
---------- printing HISTOGRAM -----------
****


****
[arch@voodo kr2]$ ./a.out
like


---------- printing HISTOGRAM -----------
****


[arch@voodo kr2]$

It may be a language issue but the usual interpretation of this
exercise is produce a histogram that shows how many 1 letter words,
how many two letter words, etc were in the input.

that K&R2 did not tell. YES, it was a language issue. i interpreted it
differently.
What you are
producing is a histogram that shows the length of first word, length
of second word, etc.

that is what exactly i thought that statement of exercise means.

thanks for telling what K&R actually meant.
 
B

Barry Schwarz

what i WANTED:

I want it to produce a "horizontal histogram" which tells how many
characters were in the 1st word, how many characters were in the
second word by writing equal number of stars at the output. i want to
discard ant newlines, extra spaces (more than 1 space between the
words), tabs an newlines.

what i GOT:

it prints histogram BUT it also prints each extra space & tab as a
"newline in output".

You are not handling sequential spaces properly. Follow the comments
in numerical order.
DIFFERENCE: each extra space, tab and newline appears in the output
which must not be there.

---------- PROGRAMME -------
/* K&R2, section 1.6 Arrays; Exercise 1-13.

STATEMENT:
Write a program to print a histogram of the lengths of words in its
input.
It is easy to draw the histogram with the bars horizontal; a vertical
orientation is more challenging.


Method:

1.) we will store lenth of each word in an array.
2.) for keeping simplicity, array size is 1000, i.e.
it can hold only 1000 words.
3.) after EOF is encountered then the Hostogram will be
printed
*/

#include <stdio.h>

#define IN 1
#define OUT 0
#define MAXWORDS 1000

int main()
{
int c;
int i = 0;
int arr_index = 0;
int j = 0; /* "i,j,count" are general index counters */

int nc = 0; /* length of word or number of characters in a word */

int lwords[MAXWORDS + 1];

int nw = 0; /* number of words */

/* length of each word is stored in this array
and will be printed in the end */

int state = IN;

For your second set of input, you appear to have 'l', 'i', 'k', 'e'
followed by several spaces.
while( ((c = getchar()) != EOF) && (nw <= MAXWORDS) )
{
++nc;

if(c == ' ' || c == '\t' || c == '\n')

1 - When you process the first space after the e...

2 - When you process the second space after the e...
{
state = OUT;
--nc;

1 - you set nc to 4 ...

2 - you set nc to 0 ...
}

if(state == OUT)
{
lwords[arr_index++] = nc;

1 - and set lwords[0] to 4.

2 - and set lwords[1] to 0.

Side issue: are nw and arr_index ever different?
state = IN;
nc = 0;
}

}

printf("---------- printing HISTOGRAM -----------\n");

/* printf("arr_index: %d\n", arr_index); */
for(i = 0; i < arr_index; ++i)
{
for(j = 0; j < lwords; ++j)


3 - When i is 0...

4 - When i is 1, j is not less that [1] so the for loop exits and you
print no asterisks ...
putchar('*');

3 - you output 4 asterisks ...

4 - but you do print a '\n' resulting in a blank line.
putchar('\n');

3 - followed by a '\n'.
}

return 0;
}


-------- OUTPUT ----------
[arch@voodo kr2]$ gcc -std=c99 -pedantic -Wall -Wextra ex_1-13.c
[arch@voodo kr2]$ ./a.out
like this
---------- printing HISTOGRAM -----------
****
****
[arch@voodo kr2]$ ./a.out
like this
---------- printing HISTOGRAM -----------
****

****
[arch@voodo kr2]$ ./a.out
like this
---------- printing HISTOGRAM -----------
****


****
[arch@voodo kr2]$ ./a.out
like


---------- printing HISTOGRAM -----------
****


[arch@voodo kr2]$

It may be a language issue but the usual interpretation of this
exercise is produce a histogram that shows how many 1 letter words,
how many two letter words, etc were in the input.

that K&R2 did not tell. YES, it was a language issue. i interpreted it
differently.
What you are
producing is a histogram that shows the length of first word, length
of second word, etc.

that is what exactly i thought that statement of exercise means.

thanks for telling what K&R actually meant.


Remove del for email
 

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

Staff online

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,052
Latest member
LucyCarper

Latest Threads

Top