Multiple indirection mess-up...

S

santosh

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_FAILURE);
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_FAILURE);
41: else
42: {
43: rnd = rand();
44: printf("\nGenerated 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("\nPrinting strings via printf():");
54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
55: {
56: printf("\nString %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\nPrinting strings manually using multiple-indirection:");
64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
65: {
66: printf("\nString %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.
 
E

Eric Sosman

santosh said:
[...]
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\nPrinting strings manually using multiple-indirection:");
64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
65: {
66: printf("\nString %u is: ", ctr+1);
67: sptr = ptr;
68: while(**sptr != '\0')
69: {
70: printf("%c", **sptr);
71: *sptr++;

This line doesn't do what you think it does.
 
F

Flash Gordon

santosh said:
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.

There is no standard function called itoa, why not use sprintf which is
a standard function instead?
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 */

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

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.
20: if(mptr == NULL)
21: exit(EXIT_FAILURE);
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++)

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

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

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.
46: itoa(rnd, *ptr, 10);
47: }
48: ptr++;
49: }
50:
51: /* Now print the strings */
52: ptr = mptr;
53: puts("\nPrinting strings via printf():");
54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
55: {
56: printf("\nString %u is: %s", ctr+1, *ptr);

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.
57: ptr++;
58: }
59:
60: /* Now print the strings manually using multiple-indirection... */
61: ptr = mptr;
62: sptr = ptr;
63: puts("\n\nPrinting strings manually using multiple-indirection:");
64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
65: {
66: printf("\nString %u is: ", ctr+1);
67: sptr = ptr;
68: while(**sptr != '\0')
69: {
70: printf("%c", **sptr);
71: *sptr++;

The above line is where you go wrong. It is not doing what you think.
 
S

santosh

Eric said:
santosh said:
[...]
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\nPrinting strings manually using multiple-indirection:");
64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
65: {
66: printf("\nString %u is: ", ctr+1);
67: sptr = ptr;
68: while(**sptr != '\0')
69: {
70: printf("%c", **sptr);
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?

Anyway I changed it to:
(*sptr)++;
It works correctly.
 
S

santosh

Flash said:
There is no standard function called itoa, why not use sprintf which is
a standard function instead?

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

Thanks. I'll keep that in mind when I post code next time.
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.
Okay.

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.

Good idea. Thanks.
You ought to be consistent about whether you are going to use nitems or
DEF_ALLOC_ITEMS, personally I would go with the latter.

Yes. I noticed that redundancy and was going to remove that wasted
variable later.
As you are going to overwrite it immediately, why bother with calloc?

No real reason in this case. I suppose malloc() would have been
fractionally faster?
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.

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

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.
The above line is where you go wrong. It is not doing what you think.

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

Michael Mair

santosh said:
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.




Thanks. I'll keep that in mind when I post code next time.




Good idea. Thanks.




Yes. I noticed that redundancy and was going to remove that wasted
variable later.




No real reason in this case. I suppose malloc() would have been
fractionally faster?




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.




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.




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

Have a look at the thread following
<[email protected]>
and feel free to ask if any questions remain :)

Cheers
Michael
 
P

pete

santosh said:
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_FAILURE);
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_FAILURE);
41: else
42: {
43: rnd = rand();
44: printf("\nGenerated 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("\nPrinting strings via printf():");
54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
55: {
56: printf("\nString %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\nPrinting strings manually using multiple-indirection:");
64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
65: {
66: printf("\nString %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: }

/* 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)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3)

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

if (mptr == NULL) {
puts("mptr == NULL");
exit(EXIT_FAILURE);
}
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_FAILURE);
} else {
rnd = rand();
printf("random number for string %u is: %d\n",
ctr, rnd);
sprintf(*ptr, "%d", rnd);
}
++ptr;
}
puts("\nPrinting strings via printf():\n");
ptr = mptr;
for (ctr = 0; nitems != ctr; ++ctr) {
printf("String %u is: %s\n", ctr, *ptr);
++ptr;
}
puts("\nPrinting 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 */
 
B

Barry Schwarz

Eric said:
santosh said:
[...]
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\nPrinting strings manually using multiple-indirection:");
64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
65: {
66: printf("\nString %u is: ", ctr+1);
67: sptr = ptr;
68: while(**sptr != '\0')
69: {
70: printf("%c", **sptr);
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?

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.
Anyway I changed it to:
(*sptr)++;
It works correctly.


<<Remove the del for email>>
 
B

Barry Schwarz

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>

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

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.
20: if(mptr == NULL)

A short error message identifying the failure would be nice.
21: exit(EXIT_FAILURE);
22: else
23: ptr = mptr;

A more common idiom is to include this in the first clause of the
following for statement.
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));

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.
39: if(*ptr == NULL)
40: exit(EXIT_FAILURE);
41: else
42: {
43: rnd = rand();
44: printf("\nGenerated random number for string %u is: %d",
45: ctr+1, rnd);

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.
46: itoa(rnd, *ptr, 10);

itoa is a non-standard function. You can achieve the same result with
sprintf.
47: }
48: ptr++;

A more common idiom is to include this in the third clause of the for
statement.
49: }
50:
51: /* Now print the strings */
52: ptr = mptr;
53: puts("\nPrinting strings via printf():");
54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
55: {
56: printf("\nString %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;

This statement is superfluous.
63: puts("\n\nPrinting strings manually using multiple-indirection:");
64: for(ctr = 0; ctr < DEF_ALLOC_ITEMS; ctr++)
65: {
66: printf("\nString %u is: ", ctr+1);
67: sptr = ptr;
68: while(**sptr != '\0')
69: {
70: printf("%c", **sptr);

putc or fputc is probably more efficient here.
71: *sptr++;
72: }

You need to output a \n here to avoid having all your strings appear
on one line.
73: ptr++;

Previously identified as the source of your problem.
74: }
75:
76: return 0;
77: }

Thanks.


<<Remove the del for email>>
 
C

Chris Torek

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

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 "*".)
Anyway I changed it to:
(*sptr)++;
It works correctly.

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

santosh

Barry said:
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.
Thanks.
In that case, does the expression:
*sptr++;
resolve as:
*(sptr++);

And, is the * operator, unary?
 
S

santosh

santosh said:
Thanks.
In that case, does the expression:
*sptr++;
resolve as:
*(sptr++);
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?
 
S

santosh

Chris said:
This is incorrect, or at the very least, incomplete.

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

santosh

pete said:
/* 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)((sizeof(int) * CHAR_BIT - 1) / 3.3) + 3)

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?
int main( void )
{
const size_t nitems = DEF_ALLOC_ITEMS;

I guess const modifier is to let the compiler catch inadvertant
modofications to a value that is used in fixed manner throughout the
program...
char **const mptr = malloc(DEF_ALLOC_ITEMS * sizeof *mptr);

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

Would:
char (*sptr)[DEF_STR_SIZE];
be correct.
char **ptr;
int rnd;
unsigned ctr;

I recall reading somewhere in this group, that size_t is considered a
blemish.
if (mptr == NULL) {
puts("mptr == NULL");
exit(EXIT_FAILURE);
}
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) {
I guess using --ctr above would skip one pointer.
free(mptr[ctr]);
Can this indexing be used even if mptr is not modified with const?

puts("\nPrinting 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) {
This is tricky but neat for loop; does a lot of things.
putchar(**sptr);
}
putchar('\n');
}
ctr = nitems;
while (ctr-- != 0) {
free(mptr[ctr]);
}
free(mptr);
puts("\nmptr freed");
return 0;
}

/* END new.c */
Thanks.
You're version is more compact and correct, plus I learned a couple of
tricks.
 
M

Michael Mair

santosh said:
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?

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.

I guess const modifier is to let the compiler catch inadvertant
modofications to a value that is used in fixed manner throughout the
program...

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.
Here const is used because the variable is left unchanged throughout
execution and also because array indexing is used on it. Am I correct?

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.

char *(sptr)[DEF_STR_SIZE];

Would:
char (*sptr)[DEF_STR_SIZE];
be correct.

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
`----
I recall reading somewhere in this group, that size_t is considered a
blemish.

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.

I guess using --ctr above would skip one pointer.

Worse: If ctr is 0 at the begin of the loop, you run through
all unsigned int values.
free(mptr[ctr]);

Can this indexing be used even if mptr is not modified with const?

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.
This is tricky but neat for loop; does a lot of things.

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.
putchar('\n');
}
ctr = nitems;
while (ctr-- != 0) {
free(mptr[ctr]);
}
free(mptr);
puts("\nmptr freed");
return 0;
}

/* END new.c */

Thanks.
You're version is more compact and correct, plus I learned a couple of
tricks.

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
 
P

pete

santosh said:
This macro is mystifying. What exactly does division by 3.3 and
addition of 3 accomplish?

(sizeof(int) * CHAR_BIT - 1) is the maximum number of possible
value bits in an int.
3.3 is a little less than (log(10) / log(2)).
Dividing by a little less, means that at worst,
the result will be a little big, which is OK.
+ 1 completes the formula for the number of decimal digits,
+ 1 for the sign,
+ 1 for the null terminator.
Are these "magic" values given in any standard headers?

No.
In what way is it better than my hardcoded value?

It works for any size int.

Here const is used because the variable is left unchanged throughout
execution and also because array indexing is used on it. Am I correct?

Just because it is left unchanged.
It's good to have some value saved for the free function,
and mptr might as well be it.

char *(sptr)[DEF_STR_SIZE];

Would:
char (*sptr)[DEF_STR_SIZE];
be correct.

No.
sptr is a pointer to an array of DEF_STR_SIZE char.
I recall reading somewhere in this group, that size_t is considered a
blemish.

Not by me. I like size_t.
I chose unsigned because of this line:
printf("random number for string %u is: %d\n", ctr, rnd);
unsigned is easier to print in C89.
I guess using --ctr above would skip one pointer.

Like Michael Mair said,
it could be a real problem if ctr is initially zero.
free(mptr[ctr]);
Can this indexing be used even if mptr is not modified with const?

Yes, but only if mptr has the right value.
ctr = nitems;
while (ctr-- != 0) {
free(mptr[ctr]);
}

The above is my prefered way for indexing through an array.

It's good to get into the habbit of freeing
what's been allocated.
Thanks.
You're version is more compact and correct,
plus I learned a couple of tricks.

You're welcome.
I tried to make a good job of it.
 
K

Keith Thompson

santosh said:
In that case, does the expression:
*sptr++;
resolve as:
*(sptr++);
Yes.

And, is the * operator, unary?

Of course. (How many operands does it have?)

This raises a question. Is there a utility program that parses C
expressions the way cdecl parses declarations? The output could be
either a fully parenthesized expression or a parse tree. (It
shouldn't be too hard to write one.)
 
K

Keith Thompson

Michael Mair said:
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.

To quote Brian Kernighan (the "K" of "K&R"):

Debugging is at least twice as hard as programming. If your code
is as clever as you can possibly make it, then by definition
you're not smart enough to debug it.
 
B

Barry Schwarz

Thanks.
In that case, does the expression:
*sptr++;
resolve as:
*(sptr++);
Yes.


And, is the * operator, unary?

How many operands does it have (the dereference operator, not the
multiplication one)?


<<Remove the del for email>>
 
B

Barry Schwarz

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?

The expression *sptr++ evaluates to the value that sptr points to
prior to the increment. The increment of sptr is a side effect of the
++ operator and the only thing you know about it is that it occurs
sometime prior to the next sequence point.


<<Remove the del for email>>
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top