K&R2 exercise 1.13

A

Army1987

Is this OK? If not, why?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 32767
#define DIGITS 5 /* number of decimal digits in MAXLEN */
int main(void)
{
size_t i;
int j;
char word[MAXLEN];
char format[DIGITS+3];
int counts[MAXLEN];
size_t len_curr, max_curr = 0;

memset(counts, 0, MAXLEN * sizeof(int));
word[MAXLEN - 1] = '\0';
sprintf(format, "%%%ds", MAXLEN);
while (scanf(format, word) > 0) {
if (word[MAXLEN-1] != '\0') {
word[MAXLEN-1] = '\0';
fprintf(stderr, "Truncating word longer than %d "
"characters to %s.\n", MAXLEN-1, word);
scanf("%*s");
}
len_curr = strlen(word);
counts[len_curr]++;
if (len_curr > max_curr)
max_curr = len_curr;
}
for (i=1; i<=max_curr; i++) {
printf("%*d|", DIGITS, (int)i);
for (j=0; j<counts; j++)
putchar('=');
putchar('\n');
}
return 0;
}
 
?

=?ISO-8859-1?Q?Bj=F8rn_Augestad?=

Army1987 said:
Is this OK? If not, why?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 32767
#define DIGITS 5 /* number of decimal digits in MAXLEN */
int main(void)
{
size_t i;
int j;
char word[MAXLEN];
char format[DIGITS+3];
int counts[MAXLEN];
size_t len_curr, max_curr = 0;

memset(counts, 0, MAXLEN * sizeof(int));

memset(counts, 0, sizeof counts);

word[MAXLEN - 1] = '\0';
sprintf(format, "%%%ds", MAXLEN);

This format string will cause scanf() to write in word[MAXLEN],
which is off by one.
while (scanf(format, word) > 0) {
if (word[MAXLEN-1] != '\0') {
word[MAXLEN-1] = '\0';
fprintf(stderr, "Truncating word longer than %d "
"characters to %s.\n", MAXLEN-1, word);
scanf("%*s");
}
len_curr = strlen(word);
counts[len_curr]++;
if (len_curr > max_curr)
max_curr = len_curr;
}
for (i=1; i<=max_curr; i++) {

Broken loop? Can max_curr ever equal MAXLEN? If so, you have an off by
one error a couple of lines down.
printf("%*d|", DIGITS, (int)i);
for (j=0; j<counts; j++)
putchar('=');
putchar('\n');
}
return 0;
}



HTH
Bjørn
 
A

Army1987

Bjørn Augestad said:
Army1987 said:
Is this OK? If not, why?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 32767
#define DIGITS 5 /* number of decimal digits in MAXLEN */
int main(void)
{
size_t i;
int j;
char word[MAXLEN];
char format[DIGITS+3];
int counts[MAXLEN];
size_t len_curr, max_curr = 0;

memset(counts, 0, MAXLEN * sizeof(int));

memset(counts, 0, sizeof counts);

word[MAXLEN - 1] = '\0';
sprintf(format, "%%%ds", MAXLEN);

This format string will cause scanf() to write in word[MAXLEN], which
is off by one.
I do check this in the following if, but I'd forgotten that scanf
doesn't know about sizeof word, so it'll try to zero word[MAXLEN]
anyway... Unluckily (or luckily, depending on the point of view)
when I tested the program (using 10 as MAXLEN) it didn't contain
sensible data, neither did any demon fly out of my nose.
Too tired to fix that right now...
while (scanf(format, word) > 0) {
if (word[MAXLEN-1] != '\0') {
word[MAXLEN-1] = '\0';
fprintf(stderr, "Truncating word longer than %d "
"characters to %s.\n", MAXLEN-1, word);
scanf("%*s");
}
len_curr = strlen(word);
counts[len_curr]++;
if (len_curr > max_curr)
max_curr = len_curr;
}
for (i=1; i<=max_curr; i++) {

Broken loop? Can max_curr ever equal MAXLEN? If so, you have an off by one
error a couple of lines down.
No, it can't, since word[MAXLEN-1] is zeroed above, so strlen(word)
can at most be MAXLEN-1.
printf("%*d|", DIGITS, (int)i);
for (j=0; j<counts; j++)
putchar('=');
putchar('\n');
}
return 0;
}
 
A

Army1987

Army1987 said:
Bjørn Augestad said:
Army1987 said:
Is this OK? If not, why?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 32767
#define DIGITS 5 /* number of decimal digits in MAXLEN */
int main(void)
{
size_t i;
int j;
char word[MAXLEN]; char word[MAXLEN + 1];
char format[DIGITS+3];
int counts[MAXLEN];
size_t len_curr, max_curr = 0;

memset(counts, 0, MAXLEN * sizeof(int));

memset(counts, 0, sizeof counts);

word[MAXLEN - 1] = '\0';
sprintf(format, "%%%ds", MAXLEN);

This format string will cause scanf() to write in word[MAXLEN], which
is off by one.
I do check this in the following if, but I'd forgotten that scanf
doesn't know about sizeof word, so it'll try to zero word[MAXLEN]
anyway... Unluckily (or luckily, depending on the point of view)
when I tested the program (using 10 as MAXLEN) it didn't contain
sensible data, neither did any demon fly out of my nose.
Too tired to fix that right now...
I hadn't realized this was that trivial (see above)...
while (scanf(format, word) > 0) {
if (word[MAXLEN-1] != '\0') {
word[MAXLEN-1] = '\0';
fprintf(stderr, "Truncating word longer than %d "
"characters to %s.\n", MAXLEN-1, word);
scanf("%*s");
....but here's another problem. If a word is exactly MAXLEN
characters long, this scanf discards the following word. (I could
check this by setting word[MAXLEN] to some nonzero value and check
it before the second scanf.)
 
C

CBFalconer

Army1987 said:
Is this OK? If not, why?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 32767
#define DIGITS 5 /* number of decimal digits in MAXLEN */
int main(void)
{
size_t i;
int j;
char word[MAXLEN];
char format[DIGITS+3];
int counts[MAXLEN];

Right here you have allocated more than 65535 (unless sizeof(int)
== 1) bytes, which is not guaranteed (but may be possible). For
C90 that limit is 32767. You should malloc such beasts.
 
A

Army1987

CBFalconer said:
Army1987 said:
Is this OK? If not, why?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 32767
#define DIGITS 5 /* number of decimal digits in MAXLEN */
int main(void)
{
size_t i;
int j;
char word[MAXLEN];
char format[DIGITS+3];
int counts[MAXLEN];

Right here you have allocated more than 65535 (unless sizeof(int)
== 1) bytes, which is not guaranteed (but may be possible). For
C90 that limit is 32767. You should malloc such beasts.
Or reduce MAXLEN (I wanted a more realistic limit than 10, but now
I realize it is excessive...)
 
A

Army1987

Army1987 said:
Army1987 wrote:
while (scanf(format, word) > 0) {
if (word[MAXLEN-1] != '\0') {
word[MAXLEN-1] = '\0';
fprintf(stderr, "Truncating word longer than %d "
"characters to %s.\n", MAXLEN-1, word);
scanf("%*s");
...but here's another problem. If a word is exactly MAXLEN
characters long, this scanf discards the following word. (I could
check this by setting word[MAXLEN] to some nonzero value and check
it before the second scanf.)

Useless anyway. It'll be zeroed regardless of wheter the word is
exactly MAXLEN characters or longer.
#include <ctype.h>

if (word[MAXLEN-1] != '\0') {
word[MAXLEN-1] = '\0';
fprintf(stderr, "Truncating word longer than %d "
"characters to %s.\n", MAXLEN-1, word);
if (!isspace(getchar())
scanf("%*s");
}
should work, shouldn't it?
 
A

Army1987

Army1987 said:
#include <ctype.h>

if (word[MAXLEN-1] != '\0') {
word[MAXLEN-1] = '\0';
fprintf(stderr, "Truncating word longer than %d "
"characters to %s.\n", MAXLEN-1, word);
if (!isspace(getchar())
)
 

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

No members online now.

Forum statistics

Threads
474,146
Messages
2,570,832
Members
47,374
Latest member
EmeliaBryc

Latest Threads

Top