C Programming: A Modern Approach - Chapter 15 Exercise 5

Discussion in 'C Programming' started by Simon Morgan, Jul 22, 2005.

  1. Simon Morgan

    Simon Morgan Guest

    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_insert, i, j;

    extra_spaces = MAX_LINE_LEN - line_len;
    for (i = 0; i < line_len; i++) {
    if (line != ' ')
    putchar(line);
    else {
    spaces_to_insert = extra_spaces / (num_words - 1);
    for (j = 1; j <= spaces_to_insert + 1; j++)
    putchar(' ');
    extra_spaces -= spaces_to_insert;
    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_insert but this results in the extra spaces not being
    distributed evenly.

    Thanks.
     
    Simon Morgan, Jul 22, 2005
    #1
    1. Advertising

  2. Simon Morgan wrote:

    > 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_insert, i, j;
    >
    > extra_spaces = MAX_LINE_LEN - line_len;
    > for (i = 0; i < line_len; i++) {
    > if (line != ' ')
    > putchar(line);
    > else {
    > spaces_to_insert = extra_spaces / (num_words - 1);


    This is the troublemaker. Let's say you have 8 extra spaces and 4 words.
    Then spaces_to_insert 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_insert = 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.)

    > for (j = 1; j <= spaces_to_insert + 1; j++)
    > putchar(' ');
    > extra_spaces -= spaces_to_insert;
    > num_words--;
    > }
    > }
    > putchar('\n');
    > }


    Regards
    Steffen
     
    Steffen Buehler, Jul 22, 2005
    #2
    1. Advertising

  3. Simon Morgan

    Simon Morgan Guest

    On Fri, 22 Jul 2005 12:54:23 +0200, Steffen Buehler wrote:

    > spaces_to_insert = 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.)


    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.
     
    Simon Morgan, Jul 22, 2005
    #3
  4. Simon Morgan

    Suman Guest

    Simon Morgan wrote:
    > On Fri, 22 Jul 2005 12:54:23 +0200, Steffen Buehler wrote:
    >
    > > spaces_to_insert = 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.)

    >
    > 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?


    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.)

    >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.
     
    Suman, Jul 22, 2005
    #4
  5. Simon Morgan wrote:

    > On Fri, 22 Jul 2005 12:54:23 +0200, Steffen Buehler wrote:
    >
    >> spaces_to_insert = int(0.5 + extra_spaces / (num_words - 1.0);

    >
    > Is int a function or am I supposed to cast the
    > result of the expression to an int?


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

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

    (I forgot the last closing bracket as well...)

    > 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)


    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
     
    Steffen Buehler, Jul 22, 2005
    #5
  6. Simon Morgan

    Simon Morgan Guest

    On Fri, 22 Jul 2005 13:41:30 +0200, Steffen Buehler wrote:

    > It's a simple cast, sorry for the confusion. The line should read
    >
    > spaces_to_insert = (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?


    Mine looks the same as your corrected version.

    > What are your values for extra_spaces and num_words?


    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
     
    Simon Morgan, Jul 22, 2005
    #6
  7. Simon Morgan

    Simon Morgan Guest

    On Fri, 22 Jul 2005 11:47:53 +0000, Simon Morgan wrote:

    > extra_spaces = 9
    > num_words = 9
    > C is quirky, flawed, and an enormous success. While
    > extra_spaces = 0
    > num_words = 9


    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
     
    Simon Morgan, Jul 22, 2005
    #7
  8. Simon Morgan

    Simon Morgan Guest

    On Fri, 22 Jul 2005 11:52:59 +0000, Simon Morgan wrote:

    > C is quirky, flawed, and an enormous success. While extra_spaces
    > = 0


    *sigh*
     
    Simon Morgan, Jul 22, 2005
    #8
  9. Simon Morgan wrote:

    > extra_spaces = 9
    > num_words = 9
    > C is quirky, flawed, and an enormous success. While


    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
     
    Steffen Buehler, Jul 22, 2005
    #9
  10. Simon Morgan

    Simon Morgan Guest

    On Fri, 22 Jul 2005 14:10:47 +0200, Steffen Buehler wrote:

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


    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_insert, i, j;

    extra_spaces = MAX_LINE_LEN - line_len;
    printf("extra_spaces = %d\n", extra_spaces);
    printf("num_words = %d\n", num_words);
    for (i = 0; i < line_len; i++) {
    if (line != ' ')
    putchar(line);
    else {
    spaces_to_insert = (int)(0.5 + extra_spaces / (num_words - 1.0));
    for (j = 1; j <= spaces_to_insert + 1; j++)
    putchar(' ');
    extra_spaces -= spaces_to_insert;
    num_words--;
    }
    }
    putchar('\n');
    }
     
    Simon Morgan, Jul 22, 2005
    #10
  11. In article <>,
    Simon Morgan <> wrote:

    >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.


    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
     
    Richard Tobin, Jul 22, 2005
    #11
  12. Simon Morgan wrote:

    > Here is my current code:


    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_insert float. The
    code will remain the same, only the calculation of spaces_to_insert
    turns to

    spaces_to_insert = ceil(extra_spaces / (num_words - 1.0));

    or

    spaces_to_insert = floor(extra_spaces / (num_words - 1.0));

    whichever you prefer. Works fine here.

    Regards
    Steffen
     
    Steffen Buehler, Jul 22, 2005
    #12
  13. Simon Morgan

    Simon Morgan Guest

    On Fri, 22 Jul 2005 14:33:18 +0200, Steffen Buehler wrote:

    > Works fine here.


    And here, clever stuff. Thanks a lot for your help.
     
    Simon Morgan, Jul 22, 2005
    #13
  14. Simon Morgan

    CBFalconer Guest

    Simon Morgan wrote:
    >
    > 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.


    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:>
    */

    #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(fp)));
    } /* 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(stdin) || (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 = '\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_FAILURE);
    if (!(ln = malloc(rhcol+1))) exit(EXIT_FAILURE);

    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(argc, argv)) return EXIT_FAILURE;
    else {
    (void)filter(stdin, stdout);
    cleanup();
    }
    return 0;
    } /* main */

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
     
    CBFalconer, Jul 22, 2005
    #14
  15. Simon Morgan

    Tim Rentsch Guest

    Simon Morgan <> writes:

    > 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_insert, i, j;
    >
    > extra_spaces = MAX_LINE_LEN - line_len;
    > for (i = 0; i < line_len; i++) {
    > if (line != ' ')
    > putchar(line);
    > else {
    > spaces_to_insert = extra_spaces / (num_words - 1);
    > for (j = 1; j <= spaces_to_insert + 1; j++)
    > putchar(' ');
    > extra_spaces -= spaces_to_insert;
    > 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_insert but this results in the extra spaces not being
    > distributed evenly.


    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%(num_words-1)

    and

    g + extra_spaces%(num_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.
     
    Tim Rentsch, Jul 22, 2005
    #15
  16. Simon Morgan

    Tim Rentsch Guest

    (Richard Tobin) writes:

    > In article <>,
    > Simon Morgan <> wrote:
    >
    > >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.

    >
    > 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


    Right, except Bresenham's algorithm usually adds 2x number of spaces
    at each gap, and subtracts 2x number of gaps for each "increment"
    (which is printing a space in this case), so that the comparison value
    of 1x gaps can be used, which is "1/2" in the rationalized number
    system.
     
    Tim Rentsch, Jul 22, 2005
    #16
  17. Simon Morgan

    Simon Morgan Guest

    On Fri, 22 Jul 2005 10:51:01 -0700, Tim Rentsch wrote:

    > If the gap number is g, 0 <= g < num_words-1, then the expressions
    >
    > g < extra_spaces%(num_words-1)
    >
    > and
    >
    > g + extra_spaces%(num_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.


    Thanks for your help.

    Is this implementation correct? Because using it I just get seemingly
    random distribution of extra spaces.

    void write_line(void)
    {
    int extra_spaces, spaces_to_insert, i, j;
    int endianness = 0, gap = 0;

    extra_spaces = MAX_LINE_LEN - line_len;
    for (i = 0; i < line_len; i++) {
    if (line != ' ')
    putchar(line);
    else {
    gap++;
    spaces_to_insert = extra_spaces / (num_words - 1);
    if (0 <= gap && gap < num_words - 1) {
    if (endianness) {
    spaces_to_insert += gap < extra_spaces % (num_words-1);
    endianness = 0;
    } else {
    spaces_to_insert += gap + extra_spaces % (num_words-1) >= num_words-1;
    endianness = 1;
    }
    }
    for (j = 1; j <= spaces_to_insert + 1; j++)
    putchar(' ');
    extra_spaces -= spaces_to_insert;
    num_words--;
    }
    }
    putchar('\n');
    }
     
    Simon Morgan, Jul 22, 2005
    #17
  18. Simon Morgan

    Malcolm Guest

    "Simon Morgan" <> wrote
    > 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've got a hint. The solution is to use an old-fashioned approach.
     
    Malcolm, Jul 22, 2005
    #18
  19. Simon Morgan

    Tim Rentsch Guest

    Simon Morgan <> writes:

    > On Fri, 22 Jul 2005 10:51:01 -0700, Tim Rentsch wrote:
    >
    > > If the gap number is g, 0 <= g < num_words-1, then the expressions
    > >
    > > g < extra_spaces%(num_words-1)
    > >
    > > and
    > >
    > > g + extra_spaces%(num_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.

    >
    > Thanks for your help.


    You're most welcome.


    > Is this implementation correct? Because using it I just get seemingly
    > random distribution of extra spaces.
    >
    > void write_line(void)
    > {
    > int extra_spaces, spaces_to_insert, i, j;
    > int endianness = 0, gap = 0;
    >
    > extra_spaces = MAX_LINE_LEN - line_len;
    > for (i = 0; i < line_len; i++) {
    > if (line != ' ')
    > putchar(line);
    > else {
    > gap++;
    > spaces_to_insert = extra_spaces / (num_words - 1);
    > if (0 <= gap && gap < num_words - 1) {
    > if (endianness) {
    > spaces_to_insert += gap < extra_spaces % (num_words-1);
    > endianness = 0;
    > } else {
    > spaces_to_insert += gap + extra_spaces % (num_words-1) >= num_words-1;
    > endianness = 1;
    > }
    > }
    > for (j = 1; j <= spaces_to_insert + 1; j++)
    > putchar(' ');
    > extra_spaces -= spaces_to_insert;
    > num_words--;
    > }
    > }
    > putchar('\n');
    > }


    Two comments.

    One, the test of the condition '0 <= gap && gap < num_words - 1'
    should always return true, assuming things are working properly.
    Rather than test the expression with an 'if', you could (and
    I believe should) write it as an assert:

    assert( 0 <= gap && gap < num_words - 1 );

    There needs to be a '#include <assert.h>', of course.

    Two, I see where you went wrong but I'm not sure what led you to go
    wrong. Try a simple example: let's suppose the number of extra
    spaces is six, and the number of gaps (num_words-1) is three. That
    should be two spaces per gap (not counting the given one, and no
    variation between the gaps, since three divides six evenly). At the
    first gap the code would calculate

    spaces_to_insert = extra_spaces / (num_words-1); /* 6/3 == 2 */

    which is fine. At the second gap the code would calculate

    spaces_to_insert = extra_spaces / (num_words-1); /* 4/3 == 1 */

    because we did 'extra_spaces -= spaces_to_insert;' (or in other words
    subtracted 2, giving 4) after the first gap. At the third gap the
    code would calculate

    spaces_to_insert = extra_spaces / (num_words-1); /* 3/3 == 1 */

    because after the second gap 1 was subtracted from extra_spaces. You
    see the problem? Subtracting 'spaces_to_insert' from 'extra_spaces'
    at each gap makes the code do the wrong thing.


    Also, a suggestion. Use braces with if, for, etc, in all cases where
    the statement(s) in the body are on subsequent lines, even when there
    is only one controlled statement. The more consistent rule reduces
    cognitive load when reading code, and is less error prone when
    modifying code (as you will find out if you ever try adding a line to
    a single line code "block" that isn't surrounded by braces, as most of
    us have at one time or another).
     
    Tim Rentsch, Jul 24, 2005
    #19
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Scott W
    Replies:
    14
    Views:
    749
    I.M. !Knuth
    Jul 18, 2006
  2. arnuld
    Replies:
    0
    Views:
    413
    arnuld
    Mar 5, 2007
  3. arnuld
    Replies:
    0
    Views:
    517
    arnuld
    Mar 5, 2007
  4. arnuld
    Replies:
    4
    Views:
    526
    mlimber
    Mar 5, 2007
  5. woodyee
    Replies:
    1
    Views:
    192
    anne001
    May 2, 2006
Loading...

Share This Page