C Programming: A Modern Approach - Chapter 15 Exercise 5

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Simon Morgan

    #1

    C Programming: A Modern Approach - Chapter 15 Exercise 5

    Hi,

    Does anybody have a solution or a hint for Exercise 5 of Chapter 15 of
    K.N. King's book C Programming: A Modern Approach? I spent all of
    yesterday evening staring at it and drooling. The author sure does have a
    knack for making me feel like a dumbass, or maybe it's just that I am.

    The following code pads out sentences with extra spaces between words so
    that each line takes up the same amount of space on screen. As is, the
    code will favour the end of the line when distributing the extra spaces.
    The task is to modify it so that it alternates between distribution of the
    extra spaces favouring the end of the line and the beginning of the line.

    void write_line(void )
    {
    int extra_spaces, spaces_to_inser t, i, j;

    extra_spaces = MAX_LINE_LEN - line_len;
    for (i = 0; i < line_len; i++) {
    if (line[i] != ' ')
    putchar(line[i]);
    else {
    spaces_to_inser t = extra_spaces / (num_words - 1);
    for (j = 1; j <= spaces_to_inser t + 1; j++)
    putchar(' ');
    extra_spaces -= spaces_to_inser t;
    num_words--;
    }
    }
    putchar('\n');
    }

    I cannot for the life of me figure out a solution beyond parsing the
    sentence first and adding the number of spaces to an array to be used when
    printing the sentence to screen, but this feels like an awful kludge. The
    closest I've come to a decent solution is to add extra_spaces % (num_words
    - 1) to spaces_to_inser t but this results in the extra spaces not being
    distributed evenly.

    Thanks.

  • Steffen Buehler

    #2
    Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

    Simon Morgan wrote:
    [color=blue]
    > The following code pads out sentences with extra spaces between words
    > so that each line takes up the same amount of space on screen. As is,
    > the code will favour the end of the line when distributing the extra
    > spaces. The task is to modify it so that it alternates between
    > distribution of the extra spaces favouring the end of the line and
    > the beginning of the line.
    >
    > void write_line(void )
    > {
    > int extra_spaces, spaces_to_inser t, i, j;
    >
    > extra_spaces = MAX_LINE_LEN - line_len;
    > for (i = 0; i < line_len; i++) {
    > if (line[i] != ' ')
    > putchar(line[i]);
    > else {
    > spaces_to_inser t = extra_spaces / (num_words - 1);[/color]

    This is the troublemaker. Let's say you have 8 extra spaces and 4 words.
    Then spaces_to_inser t will be 8/3 = 2.666 and be _cut_ _off_ to 2. So
    "too few" spaces will be inserted first.

    If you want to have "too much" spaces first, change this line to

    spaces_to_inser t = int(0.5 + extra_spaces / (num_words - 1.0);

    (Beware to make the division floating-point by using 1.0 instead of 1 or
    casting extra_spaces to float, otherwise the rounding will not work.)
    [color=blue]
    > for (j = 1; j <= spaces_to_inser t + 1; j++)
    > putchar(' ');
    > extra_spaces -= spaces_to_inser t;
    > num_words--;
    > }
    > }
    > putchar('\n');
    > }[/color]

    Regards
    Steffen

    Comment

    • Simon Morgan

      #3
      Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

      On Fri, 22 Jul 2005 12:54:23 +0200, Steffen Buehler wrote:
      [color=blue]
      > spaces_to_inser t = int(0.5 + extra_spaces / (num_words - 1.0);
      >
      > (Beware to make the division floating-point by using 1.0 instead of 1 or
      > casting extra_spaces to float, otherwise the rounding will not work.)[/color]

      Thanks for the quick reply Steffen.

      Just one question. Is int a function or am I supposed to cast the result
      of the expression to an int? If I cast it the output isn't how I would
      expect it to be or how I think the book expects it to be (the spaces seem
      to be randomly distributed throughout the line) so I assume it's a
      function but I can't seem to find any mention of it in the book or in the
      man pages installed on my system.

      Comment

      • Steffen Buehler

        #4
        Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

        Simon Morgan wrote:
        [color=blue]
        > On Fri, 22 Jul 2005 12:54:23 +0200, Steffen Buehler wrote:
        >[color=green]
        >> spaces_to_inser t = int(0.5 + extra_spaces / (num_words - 1.0);[/color]
        >
        > Is int a function or am I supposed to cast the
        > result of the expression to an int?[/color]

        It's a simple cast, sorry for the confusion. The line should read

        spaces_to_inser t = (int)(0.5 + extra_spaces / (num_words - 1.0));

        (I forgot the last closing bracket as well...)
        [color=blue]
        > If I cast it the output isn't how
        > I would expect it to be or how I think the book expects it to be (the
        > spaces seem to be randomly distributed throughout the line)[/color]

        Strange. It works fine here. What did you do with the missing bracket?
        What are your values for extra_spaces and num_words?

        Regards
        Steffen

        Comment

        • Suman

          #5
          Re: C Programming: A Modern Approach - Chapter 15 Exercise 5



          Simon Morgan wrote:[color=blue]
          > On Fri, 22 Jul 2005 12:54:23 +0200, Steffen Buehler wrote:
          >[color=green]
          > > spaces_to_inser t = int(0.5 + extra_spaces / (num_words - 1.0);
          > >
          > > (Beware to make the division floating-point by using 1.0 instead of 1 or
          > > casting extra_spaces to float, otherwise the rounding will not work.)[/color]
          >
          > Thanks for the quick reply Steffen.
          >
          > Just one question. Is int a function or am I supposed to cast the result
          > of the expression to an int?[/color]

          May I suggest you get a book? Or, the standard. Or, atleast the draft.
          `int' is one of the standard signed integer types(6.2.5.)
          And a keyword (6.4.1.)
          [color=blue]
          >If I cast it the output isn't how I would
          > expect it to be or how I think the book expects it to be (the spaces seem
          > to be randomly distributed throughout the line) so I assume it's a
          > function but I can't seem to find any mention of it in the book or in the
          > man pages installed on my system.[/color]

          Comment

          • Simon Morgan

            #6
            Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

            On Fri, 22 Jul 2005 13:41:30 +0200, Steffen Buehler wrote:
            [color=blue]
            > It's a simple cast, sorry for the confusion. The line should read
            >
            > spaces_to_inser t = (int)(0.5 + extra_spaces / (num_words - 1.0));
            >
            > (I forgot the last closing bracket as well...)
            >
            > Strange. It works fine here. What did you do with the missing bracket?[/color]

            Mine looks the same as your corrected version.
            [color=blue]
            > What are your values for extra_spaces and num_words?[/color]

            extra_spaces = 9
            num_words = 9
            C is quirky, flawed, and an enormous success. While
            extra_spaces = 0
            num_words = 9
            accidents of history surely helped, it evidently satisfied a
            extra_spaces = 2
            num_words = 8
            need for a system implementation language efficient enough
            extra_spaces = 0
            num_words = 8
            to displace assembly language, yet sufficiently abstract and
            extra_spaces = 4
            num_words = 9
            fluent to describe algorithms and interactions in a wide
            variety of environments. -- Dennis M. Ritchie

            Comment

            • Simon Morgan

              #7
              Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

              On Fri, 22 Jul 2005 11:47:53 +0000, Simon Morgan wrote:
              [color=blue]
              > extra_spaces = 9
              > num_words = 9
              > C is quirky, flawed, and an enormous success. While
              > extra_spaces = 0
              > num_words = 9[/color]

              Apologies for the crappy formatting. I don't know whether It's my news
              server or client but it certainly didn't look like that before I posted
              it.

              extra_spaces = 9
              num_words = 9
              C is quirky, flawed, and an enormous success. While
              extra_spaces = 0
              num_words = 9
              accidents of history surely helped, it evidently satisfied a
              extra_spaces = 2
              num_words = 8
              need for a system implementation language efficient enough
              extra_spaces = 0
              num_words = 8
              to displace assembly language, yet sufficiently abstract and
              extra_spaces = 4
              num_words = 9
              fluent to describe algorithms and interactions in a wide
              variety of environments. -- Dennis M. Ritchie

              Comment

              • Simon Morgan

                #8
                Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

                On Fri, 22 Jul 2005 11:52:59 +0000, Simon Morgan wrote:
                [color=blue]
                > C is quirky, flawed, and an enormous success. While extra_spaces
                > = 0[/color]

                *sigh*

                Comment

                • Steffen Buehler

                  #9
                  Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

                  Simon Morgan wrote:
                  [color=blue]
                  > extra_spaces = 9
                  > num_words = 9
                  > C is quirky, flawed, and an enormous success. While[/color]

                  Let's stick to this. Here's what I get:

                  | C is quirky, flawed, and an enormous success. While

                  How come you insert most spaces at the last position but one? Your
                  remaining code must somewhere differ from the one you posted here.

                  Regards
                  Steffen

                  Comment

                  • Simon Morgan

                    #10
                    Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

                    On Fri, 22 Jul 2005 14:10:47 +0200, Steffen Buehler wrote:
                    [color=blue]
                    > How come you insert most spaces at the last position but one? Your
                    > remaining code must somewhere differ from the one you posted here.[/color]

                    Do you have code for alternating between endianness? I haven't bothered
                    with that because it should be trivial to add. Right now all I'm trying to
                    do is get space distribution to favour the beginning of the line (the
                    non-floating point algorithm but in reverse if you see what I mean).

                    Here is my current code:

                    void write_line(void )
                    {
                    int extra_spaces, spaces_to_inser t, i, j;

                    extra_spaces = MAX_LINE_LEN - line_len;
                    printf("extra_s paces = %d\n", extra_spaces);
                    printf("num_wor ds = %d\n", num_words);
                    for (i = 0; i < line_len; i++) {
                    if (line[i] != ' ')
                    putchar(line[i]);
                    else {
                    spaces_to_inser t = (int)(0.5 + extra_spaces / (num_words - 1.0));
                    for (j = 1; j <= spaces_to_inser t + 1; j++)
                    putchar(' ');
                    extra_spaces -= spaces_to_inser t;
                    num_words--;
                    }
                    }
                    putchar('\n');
                    }

                    Comment

                    • Richard Tobin

                      #11
                      Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

                      In article <pan.2005.07.22 .09.48.30.18462 7@privacy.net>,
                      Simon Morgan <me@privacy.net > wrote:
                      [color=blue]
                      >The task is to modify it so that it alternates between distribution of the
                      >extra spaces favouring the end of the line and the beginning of the line.[/color]

                      It's not really answering your question, but this is an example of the
                      large class of problems that can be solved with something equivalent
                      to Bressenham's algorithm. That algorithm is traditionally used for
                      drawing straight lines on a pixel display, but can be used for all
                      kinds of problems where you want to approximate division using integer
                      increments.

                      In this case, suppose you want to divide 8 spaces among 5 gaps. Start
                      with zero. At each gap, then add 8 and subtract off as many 5s as you
                      can, and for each one add a space to that gap. Then proceed to the
                      next gap using the remainder as the starting value.

                      So we have

                      0+8 = 8 = 1*5 + 3 => 1 space
                      3+8 = 11 = 2*5 + 1 => 2 spaces
                      1+8 = 9 = 1*5 + 4 => 1 space
                      4+8 = 12 = 2*5 + 2 => 2 spaces
                      2+8 = 10 = 2*5 => 2 spaces

                      -- Richard

                      Comment

                      • Steffen Buehler

                        #12
                        Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

                        Simon Morgan wrote:
                        [color=blue]
                        > Here is my current code:[/color]

                        I see. I found that my first solution doesn't always work since the
                        rounding/casting produces errors that sooner or later lead to the
                        effects you (and in the meantime I) experienced.

                        To overcome this I now made extra_spaces and spaces_to_inser t float. The
                        code will remain the same, only the calculation of spaces_to_inser t
                        turns to

                        spaces_to_inser t = ceil(extra_spac es / (num_words - 1.0));

                        or

                        spaces_to_inser t = floor(extra_spa ces / (num_words - 1.0));

                        whichever you prefer. Works fine here.

                        Regards
                        Steffen

                        Comment

                        • Simon Morgan

                          #13
                          Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

                          On Fri, 22 Jul 2005 14:33:18 +0200, Steffen Buehler wrote:
                          [color=blue]
                          > Works fine here.[/color]

                          And here, clever stuff. Thanks a lot for your help.

                          Comment

                          • CBFalconer

                            #14
                            Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

                            Simon Morgan wrote:[color=blue]
                            >
                            > Does anybody have a solution or a hint for Exercise 5 of Chapter
                            > 15 of K.N. King's book C Programming: A Modern Approach? I spent
                            > all of yesterday evening staring at it and drooling. The author
                            > sure does have a knack for making me feel like a dumbass, or maybe
                            > it's just that I am.
                            >
                            > The following code pads out sentences with extra spaces between
                            > words so that each line takes up the same amount of space on
                            > screen. As is, the code will favour the end of the line when
                            > distributing the extra spaces. The task is to modify it so that
                            > it alternates between distribution of the extra spaces favouring
                            > the end of the line and the beginning of the line.[/color]

                            Here is something I threw together some time ago. I never did the
                            alternation part, but I did arrange to keep track of when needed.
                            Doing that will basically require a suitable buffer, rather than
                            simple stream output with putc.

                            /* ----- justify.c -----
                            Filter text file, right justifying by inserting
                            spaces between words. Words are anything separated
                            by blanks, tabs, newlines, formfeeds, bell, etc.

                            The single (optional) parameter is the output line
                            length, and defaults to 65. Execution without any
                            input redirections causes a help message.

                            This is a quick and dirty utility. 2003-01-28.
                            Released to public domain by:
                            <mailto:cbfalco ner@worldnet.at t.net>
                            */

                            #include <stdio.h>
                            #include <stdlib.h>
                            #include <ctype.h>
                            #include <string.h>

                            #define RHDEFAULT 65
                            #define RHMIN 20

                            static int rhcol; /* right hand column limit */
                            static int ragged; /* No rh justification, 0 init */

                            /* ------------------- */

                            /* This is very likely to be non-portable */
                            /* DOES NOT check fp open for reading */
                            /* NULL fp is considered a keyboard here! */
                            static int akeyboard(FILE *fp)
                            {
                            #ifndef __TURBOC__
                            # ifdef __STDC__
                            /* This dirty operation allows gcc -ansi -pedantic */
                            extern int fileno(FILE *fp);
                            extern int isatty(int fn);
                            # endif
                            #endif
                            return ((fp != NULL) && isatty(fileno(f p)));
                            } /* akeyboard */

                            /* ------------------- */

                            static void help(char *phrase1, char *phrase2)
                            {
                            if (phrase1) fprintf(stderr, "%s", phrase1);
                            if (phrase2) fprintf(stderr, "%s", phrase2);
                            fprintf(stderr, "\n"
                            "Usage: justify [rightmargin] <infile >outfile\n"
                            " The default rightmargin is 65\n"
                            " and values less than 20 are rejected\n"
                            "\n"
                            "A large value of rightmargin will effectively\n"
                            "convert all paragraphs into single lines\n"
                            "\n"
                            "A negative rightmargin causes ragged right\n"
                            "\n"
                            "A blank line delimits paragraphs\n");
                            } /* help */

                            /* ------------------- */

                            static int initialize(int argc, char *argv[])
                            {
                            long rightcol;
                            char *err;

                            if (akeyboard(stdi n) || (argc > 2)) {
                            help(NULL, NULL);
                            return 0;
                            }
                            rhcol = RHDEFAULT;
                            if (2 == argc) {
                            rightcol = strtol(argv[1], &err, 10);
                            if (rightcol < 0) {
                            rightcol = -rightcol;
                            ragged = 1;
                            }
                            if ((err == argv[1]) || (rightcol < RHMIN)) {
                            help("Bad argument: ", argv[1]);
                            return 0;
                            }
                            else rhcol = rightcol;
                            }
                            return 1;
                            } /* initialize */

                            /* ------------------- */

                            static void cleanup(void)
                            {
                            } /* cleanup */

                            /* ------------------- */

                            /* =============== =============== ==== */
                            /* Routines for text input and output */
                            /* =============== =============== ==== */

                            static void skipblanks(FILE *f)
                            {
                            int ch;

                            while ( (' ' == (ch = getc(f))) || ('\t' == ch) ||
                            ('\v' == ch) || ('\f' == ch) || ('\a' == ch) )
                            continue;
                            ungetc(ch, f);
                            } /* skipblanks */

                            /* ------------------- */

                            /* The file is assumed to hold no control chars */
                            /* other than \n \t \v \a and \f. A blank line */
                            /* marks a paragraph ending word */
                            static int nextword(FILE *f, char *buffer, int max)
                            {
                            int i, ch;

                            skipblanks(f);
                            if (EOF == (ch = getc(f))) return 0;

                            /* Detect paragraph endings as \n\n */
                            if ('\n' == ch) {
                            skipblanks(f); ch = getc(f);
                            if ('\n' == ch) { /* paragraph ending */
                            buffer[0] = buffer[1] = ch; /* wd = "\n\n" */
                            buffer[2] = '\0';
                            /* now we have to absorb any more blank lines */
                            do {
                            skipblanks(f); ch = getc(f);
                            } while ('\n' == ch);
                            ungetc(ch, f);
                            return 1;
                            }
                            }
                            /* now ch holds the first non-blank. Use all printable */
                            if (EOF == ch) return 0;
                            if (!isgraph(ch)) {
                            fprintf(stderr, "'%c', 0x%x WARN: Invalid character\n",
                            ch, (unsigned)ch);
                            }

                            i = 0;
                            do {
                            buffer[i++] = ch;
                            if (i >= max) { /* truncate over long words */
                            i--;
                            break; /* leaving ch for next word */
                            }
                            ch = getc(f);
                            } while (isgraph(ch));

                            ungetc(ch, f); /* save for next word, may be \n */
                            buffer[i] = '\0'; /* terminate string */
                            return 1;
                            } /* nextword */

                            /* ------------------- */

                            static void justify(char *ln, int wdgaps, int xtra, FILE *out)
                            {
                            int insert, i;
                            static int oddln = 0; /* for rt left blank insertion */
                            char ch;

                            #ifdef DEBUG
                            fprintf(out, "%2d %2d ", wdgaps, xtra);
                            #endif
                            insert = 0; oddln = !oddln;
                            if (wdgaps)
                            while (xtra > wdgaps) {
                            insert++; xtra -= wdgaps;
                            }
                            while ((ch = *ln++)) {
                            putc(ch, out);
                            if (' ' == ch) {
                            if (xtra) {
                            xtra--;
                            putc(' ', out);
                            }
                            for (i = insert; i; i--) putc(' ', out);
                            }
                            }
                            putc('\n', out);
                            } /* justify */

                            /* ------------------- */

                            static int filter(FILE *in, FILE *out)
                            {
                            char *buf;
                            char *ln;
                            int wdcount, lnlgh, wdlgh;
                            char *eop = "\n\n"; /* end of paragraph */
                            int done, endpar;

                            if (!(buf = malloc(rhcol+1) )) exit(EXIT_FAILU RE);
                            if (!(ln = malloc(rhcol+1) )) exit(EXIT_FAILU RE);

                            done = !nextword(in, buf, rhcol + 1);
                            endpar = !strcmp(buf, eop);

                            while (!endpar && !done) {
                            /* form paragraph */
                            wdlgh = strlen(buf);
                            wdcount = 0;
                            *ln = '\0'; lnlgh = 0;

                            while ((((lnlgh + wdlgh) < rhcol) || !lnlgh)
                            && !done && !endpar) {
                            /* form a line */
                            if (lnlgh) ln[lnlgh++] = ' ';
                            strcpy(ln + lnlgh, buf);
                            lnlgh += wdlgh;
                            wdcount++;

                            done = !nextword(in, buf, rhcol + 1);
                            endpar = !strcmp(buf, eop);
                            wdlgh = strlen(buf);
                            }

                            /* dump the line, wdcount words */
                            if (endpar || done) lnlgh = rhcol;
                            if (ragged) fprintf(out, "%s\n", ln);
                            else justify(ln, wdcount-1, rhcol-lnlgh, out);

                            if (endpar) {
                            fputc('\n', out);
                            done = !nextword(in, buf, rhcol + 1);
                            endpar = !strcmp(buf, eop);
                            }
                            }
                            return 0;
                            } /* filter */

                            /* ------------------- */

                            int main(int argc, char *argv[])
                            {
                            if (!initialize(ar gc, argv)) return EXIT_FAILURE;
                            else {
                            (void)filter(st din, stdout);
                            cleanup();
                            }
                            return 0;
                            } /* main */

                            --
                            Chuck F (cbfalconer@yah oo.com) (cbfalconer@wor ldnet.att.net)
                            Available for consulting/temporary embedded and systems.
                            <http://cbfalconer.home .att.net> USE worldnet address!


                            Comment

                            • Tim Rentsch

                              #15
                              Re: C Programming: A Modern Approach - Chapter 15 Exercise 5

                              Simon Morgan <me@privacy.net > writes:
                              [color=blue]
                              > Hi,
                              >
                              > Does anybody have a solution or a hint for Exercise 5 of Chapter 15 of
                              > K.N. King's book C Programming: A Modern Approach? I spent all of
                              > yesterday evening staring at it and drooling. The author sure does have a
                              > knack for making me feel like a dumbass, or maybe it's just that I am.
                              >
                              > The following code pads out sentences with extra spaces between words so
                              > that each line takes up the same amount of space on screen. As is, the
                              > code will favour the end of the line when distributing the extra spaces.
                              > The task is to modify it so that it alternates between distribution of the
                              > extra spaces favouring the end of the line and the beginning of the line.
                              >
                              > void write_line(void )
                              > {
                              > int extra_spaces, spaces_to_inser t, i, j;
                              >
                              > extra_spaces = MAX_LINE_LEN - line_len;
                              > for (i = 0; i < line_len; i++) {
                              > if (line[i] != ' ')
                              > putchar(line[i]);
                              > else {
                              > spaces_to_inser t = extra_spaces / (num_words - 1);
                              > for (j = 1; j <= spaces_to_inser t + 1; j++)
                              > putchar(' ');
                              > extra_spaces -= spaces_to_inser t;
                              > num_words--;
                              > }
                              > }
                              > putchar('\n');
                              > }
                              >
                              > I cannot for the life of me figure out a solution beyond parsing the
                              > sentence first and adding the number of spaces to an array to be used when
                              > printing the sentence to screen, but this feels like an awful kludge. The
                              > closest I've come to a decent solution is to add extra_spaces % (num_words
                              > - 1) to spaces_to_inser t but this results in the extra spaces not being
                              > distributed evenly.[/color]

                              What I think you want is, if the number of extra spaces is N, and the
                              number of separations (ie, 'num_words-1') is S, then there should be

                              N/S spaces between every word, and also
                              1 extra space at each of the N%S gaps at the
                              {beginning,end} of the line.

                              If the gap number is g, 0 <= g < num_words-1, then the expressions

                              g < extra_spaces%(n um_words-1)

                              and

                              g + extra_spaces%(n um_words-1) >= num_words-1

                              should, when added to extra_spaces/(num_words-1), give the number of
                              spaces that should be printed at each gap, for favoring the beginning
                              of the line and the end of the line respectively.

                              Comment

                              Working...