473,769 Members | 1,730 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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.

Dec 18 '05 #1
19 3065
santosh wrote:
[...]
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++;
This line doesn't do what you think it does.
72: }
73: ptr++;
74: }


--
Eric Sosman
es*****@acm-dot-org.invalid
Dec 18 '05 #2
santosh wrote:
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_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++)
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_FAILU RE);
41: else
42: {
43: rnd = rand();
44: printf("\nGener ated 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("\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);
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\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++;
The above line is where you go wrong. It is not doing what you think.
72: }
73: ptr++;
74: }
75:
76: return 0;
77: }

Thanks.

--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Dec 18 '05 #3
Eric Sosman wrote:
santosh wrote:
[...]
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++;
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.
72: }
73: ptr++;
74: }


--
Eric Sosman

es*****@acm-dot-org.invalid


Dec 18 '05 #4
Flash Gordon wrote:
santosh wrote:
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?


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


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


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.
37: {
38: *ptr = calloc(nitems, sizeof (char));


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


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.
54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
55: {
56: printf("\nStrin g %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.


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


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

Dec 18 '05 #5
santosh wrote:
Flash Gordon wrote:
santosh wrote:
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.


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.

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.

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

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.

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_ITE MS, personally I would go with the latter.

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

37: {
38: *ptr = calloc(nitems, sizeof (char));


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?

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


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.

54: for(ctr = 0; ctr < DEF_ALLOC_ITEMS ; ctr++)
55: {
56: printf("\nStrin g %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.

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.

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


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


Have a look at the thread following
<11************ ********@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.
Dec 18 '05 #6
santosh wrote:
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: }


/* 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
Dec 18 '05 #7
On 18 Dec 2005 10:12:39 -0800, "santosh" <sa*********@gm ail.com>
wrote:
Eric Sosman wrote:
santosh wrote:
> [...]
> 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++;
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.
> 72: }
> 73: ptr++;
> 74: }


--
Eric Sosman

es*****@acm-dot-org.invalid

<<Remove the del for email>>
Dec 18 '05 #8
On 18 Dec 2005 08:13:11 -0800, "santosh" <sa*********@gm ail.com>
wrote:
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_FAILU RE);
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_FAILU RE);
41: else
42: {
43: rnd = rand();
44: printf("\nGener ated 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("\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;
This statement is superfluous.
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);
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>>
Dec 18 '05 #9
>>santosh wrote:
71: *sptr++;
Eric Sosman wrote:
This line doesn't do what you think it does.

In article <11************ *********@g43g2 000cwa.googlegr oups.com>
santosh <sa*********@gm ail.com> replied: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.
--
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.
Dec 19 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
11526
by: blimeyoreilly | last post by:
Hi I've a small problem .. can anyone figure it out? I am working in VS.NET in C++ with MFC. I have a CWinApp-based class called CTestHarnessApp. I keep getting the 'differs in levels of indirection from' error whenever I compile this: CTestHarnessApp theApp; //CTestHarnessApp* pTheApp = &theApp; CTestHarnessApp* pTheApp;
26
14145
by: pb648174 | last post by:
I have a table called BidItem which has another table called BidAddendum related to it by foreign key. I have another table called BidFolder which is related to both BidItem and BidAddendum, based on a column called RefId and one called Type, i.e. type 1 is a relationship to BidItem and type 2 is a relationship to BidAddendum. Is there any way to specify a foreign key that will allow for the different types indicating which table the...
1
2356
by: glennpierce | last post by:
Hi I was wondering if anyone knows of a method to achieve the creation of events in c. currently I use a function pointer to call one callback. However, I really need to map the function pointer or event to multiple callback functions. I thought I would have functions like NewSignal, EmitSignal and ConnectSignal but I don't know how I would construct function pointers at any other time other than compile time. Each new signal would...
22
23384
by: Matthew Louden | last post by:
I want to know why C# doesnt support multiple inheritance? But why we can inherit multiple interfaces instead? I know this is the rule, but I dont understand why. Can anyone give me some concrete examples?
4
4702
by: Matt Kruse | last post by:
While developing an internal IE6-only webapp, a discussion started about the 'best' way to apply classes to data tables across multiple pages. The two arguments were: 1. Apply a single class to each table. That class (possibly in combination with other classes on child elements) controls every part of the table - layout, colors, fonts, etc. Example: class="data" PROS: Easier to standardize, less specificity confusion, everything is...
7
26345
by: Andrew Tatum | last post by:
Alright, so I have this problem. I want to make it easy for me and others to be able to run a query and easily choose whether we want Merchants or NonMerchants. Previously, we would have to comment out bits of code and would leave things messy (it would also leave room for error). So, I'm thought DECLARE and SET would work. Wrong. This is what I have.... DECLARE @Merchant VARCHAR
6
13734
by: Angus | last post by:
I am using a global which is a void* I have it defined in one file as: void* hFlag; and one other header file as: extern void* hFlag; But I get this compile error:
6
3990
by: Joseph Geretz | last post by:
I have the following class which I am serializing and passing back and forth between my Web Service application and the client. public class Token : SoapHeader { public string SID; public string UID; public string PWD; }
14
1977
by: Jeff | last post by:
Let's say we have this: <div class="some_class some_other_class"> Is it possible to change *one* of the classnames. Jeff
1
3451
Markus
by: Markus | last post by:
I'm having a hard time grasping the concept of multiple levels of indirection, that is for example a char **. I understand that passing a pointer to some data to a function means that memory for that data doesn't have to be allocated on the stack, thereby reducing overhead (of course memory for the pointer has to be allocated to the stack, 'though). Another use as I understand (and see the benefits for) is that if a pointer to data is given to a...
0
9589
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9423
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
9994
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8870
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7408
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5298
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5447
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3958
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3561
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.