Multiple indirection mess-up...

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

    #1

    Multiple indirection mess-up...

    Hi all,

    In the following program I allocate a block of pointers to type char,
    initialised to zero. I then point each of those pointers to a block of
    allocated memory of fixed size (33 bytes). A unique 'string' is then
    generated using itoa() and rand() for each block of memory.

    Finally using pointer-to-pointer of type char, I print the contents of
    the blocks of memory, i.e. the strings, using both printf() and
    manually, character by character.

    When trying to print character by character, the program is terminated
    for a GPF. I suspect the fault is in the pointer manipulations between
    lines 61 and 74.

    Can anyone find the exact mistake?

    The code follows:
    1: /* File: 006.c */
    2: #include <stdio.h>
    3: #include <stdlib.h>
    4: #include <time.h>
    5:
    6: #define DEF_ALLOC_ITEMS 32
    7: #define DEF_STR_SIZE 33 /* Because itoa() can return upto 33 bytes
    */
    8:
    9: int main( void )
    10: {
    11: char **mptr = NULL;
    12: char **ptr = NULL;
    13: char **sptr = NULL;
    14: int rnd;
    15: size_t nitems = DEF_ALLOC_ITEMS ;
    16: size_t ctr;
    17:
    18: /* Allocate an array of pointers to type char, set to NULL */
    19: mptr = calloc(nitems, sizeof (char *));
    20: if(mptr == NULL)
    21: exit(EXIT_FAILU RE);
    22: else
    23: ptr = mptr;
    24:
    25: /* Seed the pseudo-random number generator */
    26: srand((unsigned ) time(NULL));
    27:
    28: /* Use itoa() with rand() as parameter to get a character string.
    29: * Initialise each of the allocated pointers to a block of
    30: * allocated, zero'ed out memory, and pass it to itoa().
    31: * Thus we get a block of pointers to type char, each pointing to
    32: * a block of memory of size DEF_STR_SIZE, containing the character
    33: * string representation of a pseudo-random number.
    34: */
    35: nitems = DEF_STR_SIZE;
    36: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
    37: {
    38: *ptr = calloc(nitems, sizeof (char));
    39: if(*ptr == NULL)
    40: exit(EXIT_FAILU RE);
    41: else
    42: {
    43: rnd = rand();
    44: printf("\nGener ated random number for string %u is: %d",
    45: ctr+1, rnd);
    46: itoa(rnd, *ptr, 10);
    47: }
    48: ptr++;
    49: }
    50:
    51: /* Now print the strings */
    52: ptr = mptr;
    53: puts("\nPrintin g strings via printf():");
    54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
    55: {
    56: printf("\nStrin g %u is: %s", ctr+1, *ptr);
    57: ptr++;
    58: }
    59:
    60: /* Now print the strings manually using multiple-indirection... */
    61: ptr = mptr;
    62: sptr = ptr;
    63: puts("\n\nPrint ing strings manually using multiple-indirection:");
    64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
    65: {
    66: printf("\nStrin g %u is: ", ctr+1);
    67: sptr = ptr;
    68: while(**sptr != '\0')
    69: {
    70: printf("%c", **sptr);
    71: *sptr++;
    72: }
    73: ptr++;
    74: }
    75:
    76: return 0;
    77: }

    Thanks.

  • Eric Sosman

    #2
    Re: Multiple indirection mess-up...

    santosh wrote:[color=blue]
    > [...]
    > When trying to print character by character, the program is terminated
    > for a GPF. I suspect the fault is in the pointer manipulations between
    > lines 61 and 74.
    >
    > Can anyone find the exact mistake?
    > [...]
    >
    > 11: char **mptr = NULL;
    > 12: char **ptr = NULL;
    > 13: char **sptr = NULL;
    > [...]
    > 60: /* Now print the strings manually using multiple-indirection... */
    > 61: ptr = mptr;
    > 62: sptr = ptr;
    > 63: puts("\n\nPrint ing strings manually using multiple-indirection:");
    > 64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
    > 65: {
    > 66: printf("\nStrin g %u is: ", ctr+1);
    > 67: sptr = ptr;
    > 68: while(**sptr != '\0')
    > 69: {
    > 70: printf("%c", **sptr);
    > 71: *sptr++;[/color]

    This line doesn't do what you think it does.
    [color=blue]
    > 72: }
    > 73: ptr++;
    > 74: }[/color]

    --
    Eric Sosman
    esosman@acm-dot-org.invalid

    Comment

    • Flash Gordon

      #3
      Re: Multiple indirection mess-up...

      santosh wrote:[color=blue]
      > Hi all,
      >
      > In the following program I allocate a block of pointers to type char,
      > initialised to zero. I then point each of those pointers to a block of
      > allocated memory of fixed size (33 bytes). A unique 'string' is then
      > generated using itoa() and rand() for each block of memory.[/color]

      There is no standard function called itoa, why not use sprintf which is
      a standard function instead?
      [color=blue]
      > Finally using pointer-to-pointer of type char, I print the contents of
      > the blocks of memory, i.e. the strings, using both printf() and
      > manually, character by character.
      >
      > When trying to print character by character, the program is terminated
      > for a GPF. I suspect the fault is in the pointer manipulations between
      > lines 61 and 74.
      >
      > Can anyone find the exact mistake?
      >
      > The code follows:
      > 1: /* File: 006.c */[/color]

      Putting in line numbers like this is a pain because it means I can't
      just past it in to a file and compile it.
      [color=blue]
      > 2: #include <stdio.h>
      > 3: #include <stdlib.h>
      > 4: #include <time.h>
      > 5:
      > 6: #define DEF_ALLOC_ITEMS 32
      > 7: #define DEF_STR_SIZE 33 /* Because itoa() can return upto 33 bytes
      > */
      > 8:
      > 9: int main( void )
      > 10: {
      > 11: char **mptr = NULL;
      > 12: char **ptr = NULL;
      > 13: char **sptr = NULL;
      > 14: int rnd;
      > 15: size_t nitems = DEF_ALLOC_ITEMS ;
      > 16: size_t ctr;
      > 17:
      > 18: /* Allocate an array of pointers to type char, set to NULL */
      > 19: mptr = calloc(nitems, sizeof (char *));[/color]

      calloc sets the memory to all bits zero, this is not necessarily the
      same as a null pointer. In any case, you never try to read before going
      through setting up all the locations, so malloc would work just as well.
      Also, you could use "sizeof *mptr" instead of "sizeof (char *)" and this
      would, IMHO, be better style and easier to maintain if the type of mptr
      ever changes.
      [color=blue]
      > 20: if(mptr == NULL)
      > 21: exit(EXIT_FAILU RE);
      > 22: else
      > 23: ptr = mptr;
      > 24:
      > 25: /* Seed the pseudo-random number generator */
      > 26: srand((unsigned ) time(NULL));
      > 27:
      > 28: /* Use itoa() with rand() as parameter to get a character string.
      > 29: * Initialise each of the allocated pointers to a block of
      > 30: * allocated, zero'ed out memory, and pass it to itoa().
      > 31: * Thus we get a block of pointers to type char, each pointing to
      > 32: * a block of memory of size DEF_STR_SIZE, containing the character
      > 33: * string representation of a pseudo-random number.
      > 34: */
      > 35: nitems = DEF_STR_SIZE;
      > 36: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)[/color]

      You ought to be consistent about whether you are going to use nitems or
      DEF_ALLOC_ITEMS , personally I would go with the latter.
      [color=blue]
      > 37: {
      > 38: *ptr = calloc(nitems, sizeof (char));[/color]

      As you are going to overwrite it immediately, why bother with calloc?
      [color=blue]
      > 39: if(*ptr == NULL)
      > 40: exit(EXIT_FAILU RE);
      > 41: else
      > 42: {
      > 43: rnd = rand();
      > 44: printf("\nGener ated random number for string %u is: %d",
      > 45: ctr+1, rnd);[/color]

      Unless you have a good reason to do otherwise I consider it far better
      style to do the \n at the end of the line you are printing, instead of
      when you start printing the next line. Doing this will mean that the
      output actually occurs when you do the printf, instead of sitting in the
      line buffer until the next printf. It also ensures the last line gets
      printed, since there is no guarantee that it will be printed (or visible
      if it is printed) if you don't terminate the last line you print with a \n.
      [color=blue]
      > 46: itoa(rnd, *ptr, 10);
      > 47: }
      > 48: ptr++;
      > 49: }
      > 50:
      > 51: /* Now print the strings */
      > 52: ptr = mptr;
      > 53: puts("\nPrintin g strings via printf():");
      > 54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
      > 55: {
      > 56: printf("\nStrin g %u is: %s", ctr+1, *ptr);[/color]

      See previous comments about printf.

      Personally, I would not bother with ptr and would just use array
      indexing on ctr, it reduces the number of things you have to get right.
      [color=blue]
      > 57: ptr++;
      > 58: }
      > 59:
      > 60: /* Now print the strings manually using multiple-indirection... */
      > 61: ptr = mptr;
      > 62: sptr = ptr;
      > 63: puts("\n\nPrint ing strings manually using multiple-indirection:");
      > 64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
      > 65: {
      > 66: printf("\nStrin g %u is: ", ctr+1);
      > 67: sptr = ptr;
      > 68: while(**sptr != '\0')
      > 69: {
      > 70: printf("%c", **sptr);
      > 71: *sptr++;[/color]

      The above line is where you go wrong. It is not doing what you think.
      [color=blue]
      > 72: }
      > 73: ptr++;
      > 74: }
      > 75:
      > 76: return 0;
      > 77: }
      >
      > Thanks.[/color]
      --
      Flash Gordon
      Living in interesting times.
      Although my email address says spam, it is real and I read it.

      Comment

      • santosh

        #4
        Re: Multiple indirection mess-up...

        Eric Sosman wrote:[color=blue]
        > santosh wrote:[color=green]
        > > [...]
        > > When trying to print character by character, the program is terminated
        > > for a GPF. I suspect the fault is in the pointer manipulations between
        > > lines 61 and 74.
        > >
        > > Can anyone find the exact mistake?
        > > [...]
        > >
        > > 11: char **mptr = NULL;
        > > 12: char **ptr = NULL;
        > > 13: char **sptr = NULL;[/color][/color]
        [color=blue][color=green]
        > > [...]
        > > 60: /* Now print the strings manually using multiple-indirection... */
        > > 61: ptr = mptr;
        > > 62: sptr = ptr;
        > > 63: puts("\n\nPrint ing strings manually using multiple-indirection:");
        > > 64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
        > > 65: {
        > > 66: printf("\nStrin g %u is: ", ctr+1);
        > > 67: sptr = ptr;
        > > 68: while(**sptr != '\0')
        > > 69: {
        > > 70: printf("%c", **sptr);
        > > 71: *sptr++;[/color]
        >
        > This line doesn't do what you think it does.[/color]

        Thanks. You're right. I got the precedence messed-up.

        The book I'm using says that if two operators of the same precedence
        level are used in an expression, then operations are performed from
        left to right. If that's so, then the above statement should have
        worked correctly, shouldn't it?

        Anyway I changed it to:
        (*sptr)++;
        It works correctly.
        [color=blue][color=green]
        > > 72: }
        > > 73: ptr++;
        > > 74: }[/color]
        >
        > --
        > Eric Sosman[/color]
        [color=blue]
        > esosman@acm-dot-org.invalid[/color]

        Comment

        • santosh

          #5
          Re: Multiple indirection mess-up...

          Flash Gordon wrote:[color=blue]
          > santosh wrote:[color=green]
          > > Hi all,
          > >
          > > In the following program I allocate a block of pointers to type char,
          > > initialised to zero. I then point each of those pointers to a block of
          > > allocated memory of fixed size (33 bytes). A unique 'string' is then
          > > generated using itoa() and rand() for each block of memory.[/color]
          >
          > There is no standard function called itoa, why not use sprintf which is
          > a standard function instead?[/color]

          Now that I've checked, itoa() doesn't seem to be a standard library
          function. I was using the C runtime library help file provided with the
          Borland C++ Command Line compiler 5.5, available for free download,
          where it explicitly shows itoa() as a part of the ANSI standard for C.
          Guess, it's wrong/outdated information.
          [color=blue][color=green]
          > > The code follows:
          > > 1: /* File: 006.c */[/color]
          >
          > Putting in line numbers like this is a pain because it means I can't
          > just past it in to a file and compile it.[/color]

          Thanks. I'll keep that in mind when I post code next time.
          [color=blue][color=green]
          > > 18: /* Allocate an array of pointers to type char, set to NULL */
          > > 19: mptr = calloc(nitems, sizeof (char *));[/color]
          >
          > calloc sets the memory to all bits zero, this is not necessarily the
          > same as a null pointer. In any case, you never try to read before going
          > through setting up all the locations, so malloc would work just as well.[/color]

          Okay.
          [color=blue]
          > Also, you could use "sizeof *mptr" instead of "sizeof (char *)" and this
          > would, IMHO, be better style and easier to maintain if the type of mptr
          > ever changes.[/color]

          Good idea. Thanks.
          [color=blue]
          > You ought to be consistent about whether you are going to use nitems or
          > DEF_ALLOC_ITEMS , personally I would go with the latter.[/color]

          Yes. I noticed that redundancy and was going to remove that wasted
          variable later.
          [color=blue][color=green]
          > > 37: {
          > > 38: *ptr = calloc(nitems, sizeof (char));[/color]
          >
          > As you are going to overwrite it immediately, why bother with calloc?[/color]

          No real reason in this case. I suppose malloc() would have been
          fractionally faster?
          [color=blue][color=green]
          > > 39: if(*ptr == NULL)
          > > 40: exit(EXIT_FAILU RE);
          > > 41: else
          > > 42: {
          > > 43: rnd = rand();
          > > 44: printf("\nGener ated random number for string %u is: %d",
          > > 45: ctr+1, rnd);[/color]
          >
          > Unless you have a good reason to do otherwise I consider it far better
          > style to do the \n at the end of the line you are printing, instead of
          > when you start printing the next line. Doing this will mean that the
          > output actually occurs when you do the printf, instead of sitting in the
          > line buffer until the next printf. It also ensures the last line gets
          > printed, since there is no guarantee that it will be printed (or visible
          > if it is printed) if you don't terminate the last line you print with a \n.[/color]

          Thanks. I didn't know about this one. I knew printf() is buffered and I
          considered placing fflush(stdout) statements after each printf() call
          within the loops, but now that you say a terminating newline flushes
          the output, I'll use it, since codewise it will be cleaner and more
          concise than calls to fflush() all over the place.
          [color=blue][color=green]
          > > 54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
          > > 55: {
          > > 56: printf("\nStrin g %u is: %s", ctr+1, *ptr);[/color]
          >
          > See previous comments about printf.
          >
          > Personally, I would not bother with ptr and would just use array
          > indexing on ctr, it reduces the number of things you have to get right.[/color]

          Actually, I wanted to use multiple indirection, since it's a slightly
          grey area in my knowledge of C. That was the reason for allocating a
          block of pointers on the heap, rather than a static array of pointers.
          As I expected, I did mess-up though not in indirection, but in operator
          precedence.
          [color=blue][color=green]
          > > 60: /* Now print the strings manually using multiple-indirection... */
          > > 61: ptr = mptr;
          > > 62: sptr = ptr;
          > > 63: puts("\n\nPrint ing strings manually using multiple-indirection:");
          > > 64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
          > > 65: {
          > > 66: printf("\nStrin g %u is: ", ctr+1);
          > > 67: sptr = ptr;
          > > 68: while(**sptr != '\0')
          > > 69: {
          > > 70: printf("%c", **sptr);
          > > 71: *sptr++;[/color]
          >
          > The above line is where you go wrong. It is not doing what you think.[/color]

          Yes. But since both * and ++ have equal precedence and occur, in this
          case, in the same expression, and if evaluated from left to right as my
          book says it would be, shouldn't it produce the expected result?

          *sptr evaluates to the lvalue of a pointer, which would then be
          incremented...

          Comment

          • Michael Mair

            #6
            Re: Multiple indirection mess-up...

            santosh wrote:[color=blue]
            > Flash Gordon wrote:
            >[color=green]
            >>santosh wrote:
            >>[color=darkred]
            >>>Hi all,
            >>>
            >>>In the following program I allocate a block of pointers to type char,
            >>>initialise d to zero. I then point each of those pointers to a block of
            >>>allocated memory of fixed size (33 bytes). A unique 'string' is then
            >>>generated using itoa() and rand() for each block of memory.[/color]
            >>
            >>There is no standard function called itoa, why not use sprintf which is
            >>a standard function instead?[/color]
            >
            >
            > Now that I've checked, itoa() doesn't seem to be a standard library
            > function. I was using the C runtime library help file provided with the
            > Borland C++ Command Line compiler 5.5, available for free download,
            > where it explicitly shows itoa() as a part of the ANSI standard for C.
            > Guess, it's wrong/outdated information.
            >
            >[color=green][color=darkred]
            >>>The code follows:
            >>>1: /* File: 006.c */[/color]
            >>
            >>Putting in line numbers like this is a pain because it means I can't
            >>just past it in to a file and compile it.[/color]
            >
            >
            > Thanks. I'll keep that in mind when I post code next time.
            >
            >[color=green][color=darkred]
            >>>18: /* Allocate an array of pointers to type char, set to NULL */
            >>>19: mptr = calloc(nitems, sizeof (char *));[/color]
            >>
            >>calloc sets the memory to all bits zero, this is not necessarily the
            >>same as a null pointer. In any case, you never try to read before going
            >>through setting up all the locations, so malloc would work just as well.[/color]
            >
            >
            > Okay.
            >
            >[color=green]
            >>Also, you could use "sizeof *mptr" instead of "sizeof (char *)" and this
            >>would, IMHO, be better style and easier to maintain if the type of mptr
            >>ever changes.[/color]
            >
            >
            > Good idea. Thanks.
            >
            >[color=green]
            >>You ought to be consistent about whether you are going to use nitems or
            >>DEF_ALLOC_ITE MS, personally I would go with the latter.[/color]
            >
            >
            > Yes. I noticed that redundancy and was going to remove that wasted
            > variable later.
            >
            >[color=green][color=darkred]
            >>>37: {
            >>>38: *ptr = calloc(nitems, sizeof (char));[/color]
            >>
            >>As you are going to overwrite it immediately, why bother with calloc?[/color]
            >
            >
            > No real reason in this case. I suppose malloc() would have been
            > fractionally faster?
            >
            >[color=green][color=darkred]
            >>>39: if(*ptr == NULL)
            >>>40: exit(EXIT_FAILU RE);
            >>>41: else
            >>>42: {
            >>>43: rnd = rand();
            >>>44: printf("\nGener ated random number for string %u is: %d",
            >>>45: ctr+1, rnd);[/color]
            >>
            >>Unless you have a good reason to do otherwise I consider it far better
            >>style to do the \n at the end of the line you are printing, instead of
            >>when you start printing the next line. Doing this will mean that the
            >>output actually occurs when you do the printf, instead of sitting in the
            >>line buffer until the next printf. It also ensures the last line gets
            >>printed, since there is no guarantee that it will be printed (or visible
            >>if it is printed) if you don't terminate the last line you print with a \n.[/color]
            >
            >
            > Thanks. I didn't know about this one. I knew printf() is buffered and I
            > considered placing fflush(stdout) statements after each printf() call
            > within the loops, but now that you say a terminating newline flushes
            > the output, I'll use it, since codewise it will be cleaner and more
            > concise than calls to fflush() all over the place.
            >
            >[color=green][color=darkred]
            >>>54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
            >>>55: {
            >>>56: printf("\nStrin g %u is: %s", ctr+1, *ptr);[/color]
            >>
            >>See previous comments about printf.
            >>
            >>Personally, I would not bother with ptr and would just use array
            >>indexing on ctr, it reduces the number of things you have to get right.[/color]
            >
            >
            > Actually, I wanted to use multiple indirection, since it's a slightly
            > grey area in my knowledge of C. That was the reason for allocating a
            > block of pointers on the heap, rather than a static array of pointers.
            > As I expected, I did mess-up though not in indirection, but in operator
            > precedence.
            >
            >[color=green][color=darkred]
            >>>60: /* Now print the strings manually using multiple-indirection... */
            >>>61: ptr = mptr;
            >>>62: sptr = ptr;
            >>>63: puts("\n\nPrint ing strings manually using multiple-indirection:");
            >>>64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
            >>>65: {
            >>>66: printf("\nStrin g %u is: ", ctr+1);
            >>>67: sptr = ptr;
            >>>68: while(**sptr != '\0')
            >>>69: {
            >>>70: printf("%c", **sptr);
            >>>71: *sptr++;[/color]
            >>
            >>The above line is where you go wrong. It is not doing what you think.[/color]
            >
            >
            > Yes. But since both * and ++ have equal precedence and occur, in this
            > case, in the same expression, and if evaluated from left to right as my
            > book says it would be, shouldn't it produce the expected result?
            >
            > *sptr evaluates to the lvalue of a pointer, which would then be
            > incremented...[/color]

            Have a look at the thread following
            <1121769711.785 459.8030@g43g20 00cwa.googlegro ups.com>
            and feel free to ask if any questions remain :-)

            Cheers
            Michael
            --
            E-Mail: Mine is an /at/ gmx /dot/ de address.

            Comment

            • pete

              #7
              Re: Multiple indirection mess-up...

              santosh wrote:
              [color=blue]
              > 1: /* File: 006.c */
              > 2: #include <stdio.h>
              > 3: #include <stdlib.h>
              > 4: #include <time.h>
              > 5:
              > 6: #define DEF_ALLOC_ITEMS 32
              > 7: #define DEF_STR_SIZE 33 /* Because itoa() can return upto 33 bytes
              > */
              > 8:
              > 9: int main( void )
              > 10: {
              > 11: char **mptr = NULL;
              > 12: char **ptr = NULL;
              > 13: char **sptr = NULL;
              > 14: int rnd;
              > 15: size_t nitems = DEF_ALLOC_ITEMS ;
              > 16: size_t ctr;
              > 17:
              > 18: /* Allocate an array of pointers to type char, set to NULL */
              > 19: mptr = calloc(nitems, sizeof (char *));
              > 20: if(mptr == NULL)
              > 21: exit(EXIT_FAILU RE);
              > 22: else
              > 23: ptr = mptr;
              > 24:
              > 25: /* Seed the pseudo-random number generator */
              > 26: srand((unsigned ) time(NULL));
              > 27:
              > 28: /* Use itoa() with rand() as parameter to get a character string.
              > 29: * Initialise each of the allocated pointers to a block of
              > 30: * allocated, zero'ed out memory, and pass it to itoa().
              > 31: * Thus we get a block of pointers to type char, each pointing to
              > 32: * a block of memory of size DEF_STR_SIZE, containing the character
              > 33: * string representation of a pseudo-random number.
              > 34: */
              > 35: nitems = DEF_STR_SIZE;
              > 36: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
              > 37: {
              > 38: *ptr = calloc(nitems, sizeof (char));
              > 39: if(*ptr == NULL)
              > 40: exit(EXIT_FAILU RE);
              > 41: else
              > 42: {
              > 43: rnd = rand();
              > 44: printf("\nGener ated random number for string %u is: %d",
              > 45: ctr+1, rnd);
              > 46: itoa(rnd, *ptr, 10);
              > 47: }
              > 48: ptr++;
              > 49: }
              > 50:
              > 51: /* Now print the strings */
              > 52: ptr = mptr;
              > 53: puts("\nPrintin g strings via printf():");
              > 54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
              > 55: {
              > 56: printf("\nStrin g %u is: %s", ctr+1, *ptr);
              > 57: ptr++;
              > 58: }
              > 59:
              > 60: /* Now print the strings manually using multiple-indirection... */
              > 61: ptr = mptr;
              > 62: sptr = ptr;
              > 63: puts("\n\nPrint ing strings manually using multiple-indirection:");
              > 64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
              > 65: {
              > 66: printf("\nStrin g %u is: ", ctr+1);
              > 67: sptr = ptr;
              > 68: while(**sptr != '\0')
              > 69: {
              > 70: printf("%c", **sptr);
              > 71: *sptr++;
              > 72: }
              > 73: ptr++;
              > 74: }
              > 75:
              > 76: return 0;
              > 77: }[/color]

              /* BEGIN new.c */

              #include <stdio.h>
              #include <stdlib.h>
              #include <time.h>
              #include <limits.h>

              #define DEF_ALLOC_ITEMS 10
              #define DEF_STR_SIZE \
              ((size_t)((size of(int) * CHAR_BIT - 1) / 3.3) + 3)

              int main( void )
              {
              const size_t nitems = DEF_ALLOC_ITEMS ;
              char **const mptr = malloc(DEF_ALLO C_ITEMS * sizeof *mptr);
              char *(sptr)[DEF_STR_SIZE];
              char **ptr;
              int rnd;
              unsigned ctr;

              if (mptr == NULL) {
              puts("mptr == NULL");
              exit(EXIT_FAILU RE);
              }
              srand((unsigned ) time(NULL));
              ptr = mptr;
              for (ctr = 0; nitems != ctr; ++ctr) {
              *ptr = malloc(DEF_STR_ SIZE * sizeof **ptr);
              if (*ptr == NULL) {
              while (ctr-- != 0) {
              free(mptr[ctr]);
              }
              free(mptr);
              puts("*mptr == NULL");
              exit(EXIT_FAILU RE);
              } else {
              rnd = rand();
              printf("random number for string %u is: %d\n",
              ctr, rnd);
              sprintf(*ptr, "%d", rnd);
              }
              ++ptr;
              }
              puts("\nPrintin g strings via printf():\n");
              ptr = mptr;
              for (ctr = 0; nitems != ctr; ++ctr) {
              printf("String %u is: %s\n", ctr, *ptr);
              ++ptr;
              }
              puts("\nPrintin g strings manually using multiple-indirection:\n" );
              ptr = mptr;
              for (ctr = 0; nitems != ctr; ++ctr) {
              printf("String %u is: ", ctr);
              for (*sptr = *ptr++; **sptr != '\0'; ++*sptr) {
              putchar(**sptr) ;
              }
              putchar('\n');
              }
              ctr = nitems;
              while (ctr-- != 0) {
              free(mptr[ctr]);
              }
              free(mptr);
              puts("\nmptr freed");
              return 0;
              }

              /* END new.c */


              --
              pete

              Comment

              • Barry Schwarz

                #8
                Re: Multiple indirection mess-up...

                On 18 Dec 2005 10:12:39 -0800, "santosh" <santosh.k83@gm ail.com>
                wrote:
                [color=blue]
                >Eric Sosman wrote:[color=green]
                >> santosh wrote:[color=darkred]
                >> > [...]
                >> > When trying to print character by character, the program is terminated
                >> > for a GPF. I suspect the fault is in the pointer manipulations between
                >> > lines 61 and 74.
                >> >
                >> > Can anyone find the exact mistake?
                >> > [...]
                >> >
                >> > 11: char **mptr = NULL;
                >> > 12: char **ptr = NULL;
                >> > 13: char **sptr = NULL;[/color][/color]
                >[color=green][color=darkred]
                >> > [...]
                >> > 60: /* Now print the strings manually using multiple-indirection... */
                >> > 61: ptr = mptr;
                >> > 62: sptr = ptr;
                >> > 63: puts("\n\nPrint ing strings manually using multiple-indirection:");
                >> > 64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
                >> > 65: {
                >> > 66: printf("\nStrin g %u is: ", ctr+1);
                >> > 67: sptr = ptr;
                >> > 68: while(**sptr != '\0')
                >> > 69: {
                >> > 70: printf("%c", **sptr);
                >> > 71: *sptr++;[/color]
                >>
                >> This line doesn't do what you think it does.[/color]
                >
                >Thanks. You're right. I got the precedence messed-up.
                >
                >The book I'm using says that if two operators of the same precedence
                >level are used in an expression, then operations are performed from
                >left to right. If that's so, then the above statement should have
                >worked correctly, shouldn't it?[/color]

                It applies to binary operators only. It does not apply to the unary
                operators, as you have now discovered, nor does it apply to the
                ternary operator (?:). Unary and ternary operators associate right to
                left. The assignment operators (=, +=, etc) also associate right to
                left.
                [color=blue]
                >
                >Anyway I changed it to:
                > (*sptr)++;
                >It works correctly.
                >[color=green][color=darkred]
                >> > 72: }
                >> > 73: ptr++;
                >> > 74: }[/color]
                >>
                >> --
                >> Eric Sosman[/color]
                >[color=green]
                >> esosman@acm-dot-org.invalid[/color][/color]


                <<Remove the del for email>>

                Comment

                • Barry Schwarz

                  #9
                  Re: Multiple indirection mess-up...

                  On 18 Dec 2005 08:13:11 -0800, "santosh" <santosh.k83@gm ail.com>
                  wrote:
                  [color=blue]
                  >Hi all,
                  >
                  >In the following program I allocate a block of pointers to type char,
                  >initialised to zero. I then point each of those pointers to a block of
                  >allocated memory of fixed size (33 bytes). A unique 'string' is then
                  >generated using itoa() and rand() for each block of memory.
                  >
                  >Finally using pointer-to-pointer of type char, I print the contents of
                  >the blocks of memory, i.e. the strings, using both printf() and
                  >manually, character by character.
                  >
                  >When trying to print character by character, the program is terminated
                  >for a GPF. I suspect the fault is in the pointer manipulations between
                  >lines 61 and 74.
                  >
                  >Can anyone find the exact mistake?
                  >
                  >The code follows:
                  >1: /* File: 006.c */
                  >2: #include <stdio.h>[/color]

                  Please leave the line numbers of postings. Someone trying to
                  duplicate your problem needs to delete them before compiling. If you
                  need to highlight a particular line, do so with a comment.
                  [color=blue]
                  >3: #include <stdlib.h>
                  >4: #include <time.h>
                  >5:
                  >6: #define DEF_ALLOC_ITEMS 32
                  >7: #define DEF_STR_SIZE 33 /* Because itoa() can return upto 33 bytes
                  >*/
                  >8:
                  >9: int main( void )
                  >10: {
                  >11: char **mptr = NULL;
                  >12: char **ptr = NULL;
                  >13: char **sptr = NULL;
                  >14: int rnd;
                  >15: size_t nitems = DEF_ALLOC_ITEMS ;
                  >16: size_t ctr;
                  >17:
                  >18: /* Allocate an array of pointers to type char, set to NULL */
                  >19: mptr = calloc(nitems, sizeof (char *));[/color]

                  calloc sets each byte to all bits zero. For the bytes that make up a
                  pointer, this may or may not be a valid value and, if valid, may or
                  may not represent NULL. Since you do properly initialize each pointer
                  before use, the resources spent by calloc performing this
                  initialization are wasted.
                  [color=blue]
                  >20: if(mptr == NULL)[/color]

                  A short error message identifying the failure would be nice.
                  [color=blue]
                  >21: exit(EXIT_FAILU RE);
                  >22: else
                  >23: ptr = mptr;[/color]

                  A more common idiom is to include this in the first clause of the
                  following for statement.
                  [color=blue]
                  >24:
                  >25: /* Seed the pseudo-random number generator */
                  >26: srand((unsigned ) time(NULL));
                  >27:
                  >28: /* Use itoa() with rand() as parameter to get a character string.
                  >29: * Initialise each of the allocated pointers to a block of
                  >30: * allocated, zero'ed out memory, and pass it to itoa().
                  >31: * Thus we get a block of pointers to type char, each pointing to
                  >32: * a block of memory of size DEF_STR_SIZE, containing the character
                  >33: * string representation of a pseudo-random number.
                  >34: */
                  >35: nitems = DEF_STR_SIZE;
                  >36: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
                  >37: {
                  >38: *ptr = calloc(nitems, sizeof (char));[/color]

                  While an all bits zero char is guaranteed to be valid, this
                  initialization is also wasted since you initialize each allocated area
                  with a string prior to use.
                  [color=blue]
                  >39: if(*ptr == NULL)
                  >40: exit(EXIT_FAILU RE);
                  >41: else
                  >42: {
                  >43: rnd = rand();
                  >44: printf("\nGener ated random number for string %u is: %d",
                  >45: ctr+1, rnd);[/color]

                  ctr+1 probably has type size_t. This is an unsigned integer type but
                  not necessarily an unsigned int, which is required by the %u format.
                  Either cast the expression to unsigned int or, if you have a C99
                  compiler, use the %zu format.
                  [color=blue]
                  >46: itoa(rnd, *ptr, 10);[/color]

                  itoa is a non-standard function. You can achieve the same result with
                  sprintf.
                  [color=blue]
                  >47: }
                  >48: ptr++;[/color]

                  A more common idiom is to include this in the third clause of the for
                  statement.
                  [color=blue]
                  >49: }
                  >50:
                  >51: /* Now print the strings */
                  >52: ptr = mptr;
                  >53: puts("\nPrintin g strings via printf():");
                  >54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
                  >55: {
                  >56: printf("\nStrin g %u is: %s", ctr+1, *ptr);
                  >57: ptr++;
                  >58: }
                  >59:
                  >60: /* Now print the strings manually using multiple-indirection... */
                  >61: ptr = mptr;
                  >62: sptr = ptr;[/color]

                  This statement is superfluous.
                  [color=blue]
                  >63: puts("\n\nPrint ing strings manually using multiple-indirection:");
                  >64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
                  >65: {
                  >66: printf("\nStrin g %u is: ", ctr+1);
                  >67: sptr = ptr;
                  >68: while(**sptr != '\0')
                  >69: {
                  >70: printf("%c", **sptr);[/color]

                  putc or fputc is probably more efficient here.
                  [color=blue]
                  >71: *sptr++;
                  >72: }[/color]

                  You need to output a \n here to avoid having all your strings appear
                  on one line.
                  [color=blue]
                  >73: ptr++;[/color]

                  Previously identified as the source of your problem.
                  [color=blue]
                  >74: }
                  >75:
                  >76: return 0;
                  >77: }
                  >
                  >Thanks.[/color]


                  <<Remove the del for email>>

                  Comment

                  • Chris Torek

                    #10
                    Re: Multiple indirection mess-up...

                    >>santosh wrote:[color=blue][color=green][color=darkred]
                    >>> 71: *sptr++;[/color][/color][/color]
                    [color=blue]
                    >Eric Sosman wrote:[color=green]
                    >> This line doesn't do what you think it does.[/color][/color]

                    In article <1134929559.042 678.84120@g43g2 000cwa.googlegr oups.com>
                    santosh <santosh.k83@gm ail.com> replied:[color=blue]
                    >Thanks. You're right. I got the precedence messed-up.
                    >
                    >The book I'm using says that if two operators of the same precedence
                    >level are used in an expression, then operations are performed from
                    >left to right. ...[/color]

                    This is incorrect, or at the very least, incomplete.

                    I find it is often wise to avoid thinking in terms of "precedence ",
                    and especially to avoid using phrases like "performed from left to
                    right" or, more generally, phrases like "X is performed first, then
                    Y" (for any two operations X and Y) in this kind of expression.
                    The reason is that, with the exception of what are called "sequence
                    points", the C language does not constrain a C compiler to do
                    anything in any particular order.

                    Of course, saying "don't think of it that way" is not very helpful.
                    Even if you decide to heed that advice, how then *should* you think
                    of it? While (as Gildor said) "advice is a dangerous gift, even
                    from the wise to the wise", in this case I do have some: use the
                    verb "bind" to describe how operators attach to their operands, and
                    draw a parse tree. In this case, the expression *sptr++ binds as:

                    *
                    |
                    postfix-++
                    |
                    sptr

                    (Expression trees are of course "more interesting" when there are
                    binary operators involved:

                    a + b * c

                    parses as:

                    +
                    / \
                    a *
                    / \
                    b c

                    which is rather less vertical than the "*sptr++" version. Note that
                    if we were to replace a, b, or c with *p++, we would get a mixed
                    tree, such as:

                    +
                    / \
                    U* *
                    | / \
                    post++ b c
                    |
                    p

                    which is admittedly a bit peculiar-looking, even if we represent
                    "unary *" as "U*" to distinguish it from the multiplication "*".)
                    [color=blue]
                    >Anyway I changed it to:
                    > (*sptr)++;
                    >It works correctly.[/color]

                    Indeed. This one binds as:

                    postfix-++
                    |
                    *
                    |
                    sptr

                    Having drawn a parse tree, the next step is to work out the effect
                    of each operator on its operands (or whether the operands are even
                    allowed). In the second case, the postfix "++" operator applies
                    to the result of the unary "*" operator. The unary "*" operator
                    takes the value in sptr (which must be a valid pointer value),
                    follows it to the object to which it points, and yields up that
                    object; the post-increment then has an object (which it requires),
                    schedules an increment to occur on that object, and produces as
                    its value the value that was in the object before the increment
                    occurred.

                    If this is the entire expression, the final value -- the one produced
                    by the postfix "++" operator -- is discarded. It is, I think,
                    instructive to compare this to what happens if we use the tree:

                    prefix-++
                    |
                    *
                    |
                    sptr

                    Again, the unary * operator produces the object to which sptr must
                    point. The prefix "++" operator then schedules an increment on
                    this object, and also produces as its value the value that will be
                    stored by that increment. The only difference between these
                    two parse trees (aside from the actual time of the increment, which
                    the compiler may choose at random provided it occurs "before the
                    next sequence point") is the final value, and if that is to be
                    discarded, this difference is no difference at all. But we can
                    obtain the second parse tree by writing either of the following
                    two lines:

                    ++(*sptr);
                    ++*sptr;

                    (along with many other possible versions that add even more
                    parentheses), while we cannot produce the parse tree that uses the
                    postfix-++ operator without at least one set of parentheses. The
                    unparenthesized version ("*sptr++") does not bind the way we want
                    it to.
                    --
                    In-Real-Life: Chris Torek, Wind River Systems
                    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
                    email: forget about it http://web.torek.net/torek/index.html
                    Reading email is like searching for food in the garbage, thanks to spammers.

                    Comment

                    • santosh

                      #11
                      Re: Multiple indirection mess-up...

                      Barry Schwarz wrote:[color=blue]
                      > On 18 Dec 2005 10:12:39 -0800, "santosh" <santosh.k83@gm ail.com>
                      > wrote:[color=green][color=darkred]
                      > >> > 71: *sptr++;
                      > >>
                      > >> This line doesn't do what you think it does.[/color]
                      > >
                      > >Thanks. You're right. I got the precedence messed-up.
                      > >
                      > >The book I'm using says that if two operators of the same precedence
                      > >level are used in an expression, then operations are performed from
                      > >left to right. If that's so, then the above statement should have
                      > >worked correctly, shouldn't it?[/color]
                      >
                      > It applies to binary operators only. It does not apply to the unary
                      > operators, as you have now discovered, nor does it apply to the
                      > ternary operator (?:). Unary and ternary operators associate right to
                      > left. The assignment operators (=, +=, etc) also associate right to
                      > left.[/color]
                      Thanks.
                      In that case, does the expression:
                      *sptr++;
                      resolve as:
                      *(sptr++);

                      And, is the * operator, unary?

                      Comment

                      • santosh

                        #12
                        Re: Multiple indirection mess-up...

                        santosh wrote:[color=blue]
                        > Barry Schwarz wrote:[color=green]
                        > > On 18 Dec 2005 10:12:39 -0800, "santosh" <santosh.k83@gm ail.com>
                        > > wrote:[color=darkred]
                        > > >> > 71: *sptr++;
                        > > >>
                        > > >> This line doesn't do what you think it does.
                        > > >
                        > > >Thanks. You're right. I got the precedence messed-up.
                        > > >
                        > > >The book I'm using says that if two operators of the same precedence
                        > > >level are used in an expression, then operations are performed from
                        > > >left to right. If that's so, then the above statement should have
                        > > >worked correctly, shouldn't it?[/color]
                        > >
                        > > It applies to binary operators only. It does not apply to the unary
                        > > operators, as you have now discovered, nor does it apply to the
                        > > ternary operator (?:). Unary and ternary operators associate right to
                        > > left. The assignment operators (=, +=, etc) also associate right to
                        > > left.[/color]
                        > Thanks.
                        > In that case, does the expression:
                        > *sptr++;
                        > resolve as:
                        > *(sptr++);[/color]
                        If the postfix form of the unary increment schedules an increment to
                        occur on the object and yields the value of the object before it's
                        increment, then *sptr++ should resolve as:
                        *sptr

                        Is my conclusion correct?

                        Comment

                        • santosh

                          #13
                          Re: Multiple indirection mess-up...

                          Chris Torek wrote:[color=blue][color=green][color=darkred]
                          > >>santosh wrote:
                          > >>> 71: *sptr++;[/color][/color]
                          >[color=green]
                          > >Eric Sosman wrote:[color=darkred]
                          > >> This line doesn't do what you think it does.[/color][/color]
                          >
                          > In article <1134929559.042 678.84120@g43g2 000cwa.googlegr oups.com>
                          > santosh <santosh.k83@gm ail.com> replied:[color=green]
                          > >Thanks. You're right. I got the precedence messed-up.
                          > >
                          > >The book I'm using says that if two operators of the same precedence
                          > >level are used in an expression, then operations are performed from
                          > >left to right. ...[/color]
                          >
                          > This is incorrect, or at the very least, incomplete.[/color]

                          Thanks for your clear explanation.

                          I still have a few grey areas in this matter. I'm learning by writing
                          lots of small test programs and I'll post questions to this board as
                          when they arise.

                          Comment

                          • santosh

                            #14
                            Re: Multiple indirection mess-up...

                            pete wrote:[color=blue]
                            > /* BEGIN new.c */
                            >
                            > #include <stdio.h>
                            > #include <stdlib.h>
                            > #include <time.h>
                            > #include <limits.h>
                            >
                            > #define DEF_ALLOC_ITEMS 10[/color]
                            [color=blue]
                            > #define DEF_STR_SIZE \
                            > ((size_t)((size of(int) * CHAR_BIT - 1) / 3.3) + 3)[/color]

                            This macro is mystifying. What exactly does division by 3.3 and
                            addition of 3 accomplish? Are these "magic" values given in any
                            standard headers? In what way is it better than my hardcoded value?
                            [color=blue]
                            > int main( void )
                            > {
                            > const size_t nitems = DEF_ALLOC_ITEMS ;[/color]

                            I guess const modifier is to let the compiler catch inadvertant
                            modofications to a value that is used in fixed manner throughout the
                            program...
                            [color=blue]
                            > char **const mptr = malloc(DEF_ALLO C_ITEMS * sizeof *mptr);[/color]

                            Here const is used because the variable is left unchanged throughout
                            execution and also because array indexing is used on it. Am I correct?
                            [color=blue]
                            > char *(sptr)[DEF_STR_SIZE];[/color]

                            Would:
                            char (*sptr)[DEF_STR_SIZE];
                            be correct.
                            [color=blue]
                            > char **ptr;
                            > int rnd;
                            > unsigned ctr;[/color]

                            I recall reading somewhere in this group, that size_t is considered a
                            blemish.
                            [color=blue]
                            > if (mptr == NULL) {
                            > puts("mptr == NULL");
                            > exit(EXIT_FAILU RE);
                            > }
                            > srand((unsigned ) time(NULL));
                            > ptr = mptr;
                            > for (ctr = 0; nitems != ctr; ++ctr) {
                            > *ptr = malloc(DEF_STR_ SIZE * sizeof **ptr);
                            > if (*ptr == NULL) {
                            > while (ctr-- != 0) {[/color]
                            I guess using --ctr above would skip one pointer.
                            [color=blue]
                            > free(mptr[ctr]);[/color]
                            Can this indexing be used even if mptr is not modified with const?

                            <snip>[color=blue]
                            > puts("\nPrintin g strings manually using multiple-indirection:\n" );
                            > ptr = mptr;
                            > for (ctr = 0; nitems != ctr; ++ctr) {
                            > printf("String %u is: ", ctr);
                            > for (*sptr = *ptr++; **sptr != '\0'; ++*sptr) {[/color]
                            This is tricky but neat for loop; does a lot of things.
                            [color=blue]
                            > putchar(**sptr) ;
                            > }
                            > putchar('\n');
                            > }
                            > ctr = nitems;
                            > while (ctr-- != 0) {
                            > free(mptr[ctr]);
                            > }
                            > free(mptr);
                            > puts("\nmptr freed");
                            > return 0;
                            > }
                            >
                            > /* END new.c */
                            >
                            >
                            > --
                            > pete[/color]
                            Thanks.
                            You're version is more compact and correct, plus I learned a couple of
                            tricks.

                            Comment

                            • Michael Mair

                              #15
                              Re: Multiple indirection mess-up...

                              santosh wrote:[color=blue]
                              > pete wrote:
                              >[color=green]
                              >>/* BEGIN new.c */
                              >>
                              >>#include <stdio.h>
                              >>#include <stdlib.h>
                              >>#include <time.h>
                              >>#include <limits.h>
                              >>
                              >>#define DEF_ALLOC_ITEMS 10[/color]
                              >
                              >[color=green]
                              >>#define DEF_STR_SIZE \
                              >>((size_t)((si zeof(int) * CHAR_BIT - 1) / 3.3) + 3)[/color]
                              >
                              > This macro is mystifying. What exactly does division by 3.3 and
                              > addition of 3 accomplish? Are these "magic" values given in any
                              > standard headers? In what way is it better than my hardcoded value?[/color]

                              3.3 is less than log(10)/log(2) but a sufficiently good approximation.
                              3.3 and 3 are, in some sense, indeed magic numbers but they are not
                              subject to change.
                              This is better than a hardcoded value as it will hold for arbitrary
                              number of bits/int.

                              [color=blue][color=green]
                              >>int main( void )
                              >>{
                              >> const size_t nitems = DEF_ALLOC_ITEMS ;[/color]
                              >
                              > I guess const modifier is to let the compiler catch inadvertant
                              > modofications to a value that is used in fixed manner throughout the
                              > program...[/color]

                              const tells the implementation that nitems is not subject to change.
                              If you do not lie to the implementation, this indeed can be used
                              to catch inadvertant modifications.
                              [color=blue][color=green]
                              >> char **const mptr = malloc(DEF_ALLO C_ITEMS * sizeof *mptr);[/color]
                              >
                              > Here const is used because the variable is left unchanged throughout
                              > execution and also because array indexing is used on it. Am I correct?[/color]

                              What the heck has array indexing to do with that?
                              mptr is supposed to hold the same value throughout its
                              lifetime. And that's it.

                              [color=blue][color=green]
                              >> char *(sptr)[DEF_STR_SIZE];[/color]
                              >
                              > Would:
                              > char (*sptr)[DEF_STR_SIZE];
                              > be correct.[/color]

                              No. Get cdecl if you are unsure about that:
                              ,----
                              | cdecl> explain char (*sptr)[5]
                              | declare sptr as pointer to array 5 of char
                              | cdecl> explain char *(sptr)[5]
                              | declare sptr as array 5 of pointer to char
                              `----
                              [color=blue][color=green]
                              >> char **ptr;
                              >> int rnd;
                              >> unsigned ctr;[/color]
                              >
                              > I recall reading somewhere in this group, that size_t is considered a
                              > blemish.[/color]

                              This depends on your point of view: As soon as you start
                              using size_t, you should use it throughout the whole
                              program and you have to take care with unsigned integer
                              loop variables counting down (They are always >= 0...).

                              However, the same argument can be made regarding the use
                              of "const": Once you start, you should stay with it.
                              Casting away constness usually is a bad idea and can
                              even be undefined behaviour if the object was declared as
                              const (and could therefore reside in a "read only" storage
                              area).

                              If used prudently, however, size_t is very useful:
                              It is the type which is _guaranteed_ to be able to "count"
                              things. It is the type returned by the sizeof operator and
                              the strlen() function and is used as parameter type for
                              many of the standard library functions.

                              Some prefer using size_t to int, others don't.

                              If you know that you do not _need_ it and decide against it,
                              then make at least a comment about it. Or write it down as
                              design or implementation decision.

                              [color=blue][color=green]
                              >> if (mptr == NULL) {
                              >> puts("mptr == NULL");
                              >> exit(EXIT_FAILU RE);
                              >> }
                              >> srand((unsigned ) time(NULL));
                              >> ptr = mptr;
                              >> for (ctr = 0; nitems != ctr; ++ctr) {
                              >> *ptr = malloc(DEF_STR_ SIZE * sizeof **ptr);
                              >> if (*ptr == NULL) {
                              >> while (ctr-- != 0) {[/color]
                              >
                              > I guess using --ctr above would skip one pointer.[/color]

                              Worse: If ctr is 0 at the begin of the loop, you run through
                              all unsigned int values.
                              [color=blue][color=green]
                              >> free(mptr[ctr]);[/color]
                              >
                              > Can this indexing be used even if mptr is not modified with const?[/color]

                              Yes. That is what the declaration as
                              "pointer to pointer to char" is for.
                              So, mptr can point to storage containing a pointer to char.
                              This has nothing whatsoever to do with constness.
                              [color=blue]
                              > <snip>
                              >[color=green]
                              >> puts("\nPrintin g strings manually using multiple-indirection:\n" );
                              >> ptr = mptr;
                              >> for (ctr = 0; nitems != ctr; ++ctr) {
                              >> printf("String %u is: ", ctr);
                              >> for (*sptr = *ptr++; **sptr != '\0'; ++*sptr) {[/color]
                              >
                              > This is tricky but neat for loop; does a lot of things.
                              >
                              >[color=green]
                              >> putchar(**sptr) ;
                              >> }[/color][/color]

                              Note: If you think that this is "nifty", then you should be
                              careful when using it. It may be well beyond your abilities
                              to debug it quickly if you make an error.
                              [color=blue][color=green]
                              >> putchar('\n');
                              >> }
                              >> ctr = nitems;
                              >> while (ctr-- != 0) {
                              >> free(mptr[ctr]);
                              >> }
                              >> free(mptr);
                              >> puts("\nmptr freed");
                              >> return 0;
                              >>}
                              >>
                              >>/* END new.c */[/color]
                              >
                              > Thanks.
                              > You're version is more compact and correct, plus I learned a couple of
                              > tricks.[/color]

                              Do not learn tricks. Learn tools and methods and how you
                              can express certain things with the language.
                              There is an important difference.


                              Cheers
                              Michael
                              --
                              E-Mail: Mine is an /at/ gmx /dot/ de address.

                              Comment

                              Working...