Interesting Pointer-to-pointer problem 
Author Message
 Interesting Pointer-to-pointer problem

Hi all,
     I'm having problems understanding a pointer-to-pointer problem.  I
have a function which expects a pointer-to-a-pointer.  But of the two
cases I have below, only one works.  Why??
    The program prints out "Hello, world!" in the first run, but cores
on the second call to 'allocstr':(gdb output):
            Hello, world!

            Program received signal SIGBUS, Bus error.
            0x2300 in allocstr (len=13, retptr=0x0) at main.c:10
            10              *retptr = p;

#include <sys/time.h>

/* function expects a pointer-to-a-pointer */
int allocstr(int len, char **retptr)
        {
        char *p = (char *)malloc(len + 1);
        if (p == NULL)
                return 0;
        *retptr = p;
        return 1;
        }

main ()
        {
        char *string = "Hello, world!";
        char *copyptr;
        char **copyptr_ptr;

        /* case 1 - pass adrress of a pointer - works great */
        if(allocstr(strlen(string), &copyptr))
                {
                strcpy(copyptr, string);
                printf ("%s\n",copyptr);
                }

        /* case 2 - pass pointer to a pointer - core dumps */
        if(allocstr(strlen(string), copyptr_ptr))
                {
                strcpy(*copyptr_ptr, string);
                printf ("%s\n",*copyptr_ptr);
                }
        }



Sat, 01 Mar 2003 04:03:49 GMT  
 Interesting Pointer-to-pointer problem

Quote:

> #include <sys/time.h>

Not a standard C header.  Also, you forgot to #include <stdlib.h>
and <stdio.h>.

Quote:
> /* function expects a pointer-to-a-pointer */
> int allocstr(int len, char **retptr)
>         {
>         char *p = (char *)malloc(len + 1);

Don't cast the result of malloc().  This may be masking your
failure to #include <stdlib.h>.

Quote:
>         if (p == NULL)
>                 return 0;
>         *retptr = p;
>         return 1;
>         }

> main ()

You shouldn't use implicit int in new code because it is
disallowed by C99.

Quote:
>         {
>         char *string = "Hello, world!";
>         char *copyptr;
>         char **copyptr_ptr;

>         /* case 1 - pass adrress of a pointer - works great */
>         if(allocstr(strlen(string), &copyptr))
>                 {
>                 strcpy(copyptr, string);
>                 printf ("%s\n",copyptr);
>                 }

>         /* case 2 - pass pointer to a pointer - core dumps */
>         if(allocstr(strlen(string), copyptr_ptr))

What do you expect to happen?  You didn't point copyptr_ptr to
anything, so allocstr() dereferencing it causes undefined
behavior.

Quote:
>                 {
>                 strcpy(*copyptr_ptr, string);
>                 printf ("%s\n",*copyptr_ptr);
>                 }

You should return a value.

Quote:
>         }

--
"Large amounts of money tend to quench any scruples I might be having."
  -- Stephan Wilms


Sat, 01 Mar 2003 04:08:18 GMT  
 Interesting Pointer-to-pointer problem
Quote:

> Hi all,
>      I'm having problems understanding a pointer-to-pointer problem.  I
> have a function which expects a pointer-to-a-pointer.  But of the two
> cases I have below, only one works.  Why??
>     The program prints out "Hello, world!" in the first run, but cores
> on the second call to 'allocstr':(gdb output):
>             Hello, world!

>             Program received signal SIGBUS, Bus error.
>             0x2300 in allocstr (len=13, retptr=0x0) at main.c:10
>             10              *retptr = p;

#include <stdlib.h> /* see below */
Quote:
> #include <sys/time.h>

> /* function expects a pointer-to-a-pointer */
> int allocstr(int len, char **retptr)
>         {
>         char *p = (char *)malloc(len + 1);

Lose the cast. It is unnecessary and hides the fact that you
failed to #include <stdlib.h>
Quote:
>         if (p == NULL)
>                 return 0;
>         *retptr = p;
>         return 1;
>         }

> main ()
int main( void )
>         {
>         char *string = "Hello, world!";
>         char *copyptr;
>         char **copyptr_ptr;

>         /* case 1 - pass adrress of a pointer - works great */
>         if(allocstr(strlen(string), &copyptr))
>                 {
>                 strcpy(copyptr, string);
>                 printf ("%s\n",copyptr);
>                 }

>         /* case 2 - pass pointer to a pointer - core dumps */
>         if(allocstr(strlen(string), copyptr_ptr))

What is copyptr_ptr pointing to? (specifically when you
dereference it in allocstr()). That's your problem.

Quote:
>                 {
>                 strcpy(*copyptr_ptr, string);
>                 printf ("%s\n",*copyptr_ptr);
>                 }
>         }

HTH,
--ag
--
Artie Gold, Austin, TX  (finger the cs.utexas.edu account
for more info)

--
"I'd sooner fly another combat mission than ride the Cyclone
again" -- Joseph Heller


Sat, 01 Mar 2003 04:10:14 GMT  
 Interesting Pointer-to-pointer problem
Thanks guys,
        I understand, but now suppose I still want to use the second
method.  How do I give the pointer-to-a-pointer (copyptr_ptr) an initial
value?  Do I have to create some initial dummy variable for it to point
to?  I can't set copyptr_ptr = NULL, because I'm then dereferencing a NULL
pointer (?) which also does not make sense (I think).  What if I wish to
use a pointer-to-pointer-to-pointer?  I'm just trying to wrap my head
around the idea of the "contents of" vs. the "address of".
    As well, a pointer is a pointer is a pointer.  That is, we do not need
to cast a pointer unless we wish to interpret the contents of what the
pointer points to.  Is this notion correct?  This is what I'm getting from
the "not casting the malloc( ) with allocstr( )".

Regards,
Vinnie.

Round 2.....

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

/* function expects a pointer-to-a-pointer */
int allocstr(int len, char **retptr)
        {
        char *p = malloc(len + 1);
        if (p == NULL)
                return 0;
        *retptr = p;
        return 1;
        }

int main (void)
        {
        char *string = "Hello, world!";
        char *copyptr = NULL;
        char **copyptr_ptr = NULL;

        /* case 1 - pass address of a pointer - works great */
        if(allocstr(strlen(string), &copyptr))
                {
                strcpy(copyptr, string);
                printf ("%s\n",copyptr);
                }

        /* case 2 - pass pointer to a pointer - core dumps */
        if(allocstr(strlen(string), copyptr_ptr))
                {
                strcpy(*copyptr_ptr, string);
                printf ("%s\n",*copyptr_ptr);
                }

        return (0);
        }



Sat, 01 Mar 2003 08:36:10 GMT  
 Interesting Pointer-to-pointer problem

Quote:

>         I understand, but now suppose I still want to use the second
> method.  How do I give the pointer-to-a-pointer (copyptr_ptr) an initial
> value?  Do I have to create some initial dummy variable for it to point
> to?  I can't set copyptr_ptr = NULL, because I'm then dereferencing a NULL
> pointer (?) which also does not make sense (I think).  What if I wish to
> use a pointer-to-pointer-to-pointer?  I'm just trying to wrap my head
> around the idea of the "contents of" vs. the "address of".

char buf[] = "Hello, world!";
char *bufp = buf;
char **bufpp = &bufp;
char ***bufppp = &bufpp;
char ****bufpppp = &bufppp;
...etc...
--
"This is a wonderful answer.
 It's off-topic, it's incorrect, and it doesn't answer the question."
--Richard Heathfield


Sat, 01 Mar 2003 10:29:04 GMT  
 Interesting Pointer-to-pointer problem

Quote:

> Thanks guys,
>         I understand, but now suppose I still want to use the second
> method.  How do I give the pointer-to-a-pointer (copyptr_ptr) an initial
> value?  

You need to point it to a variable of type *char.  Either explicitly
as for instance

    char *copyptr;
    char **copyptr_ptr;

    copyptr_ptr = &copyptr;

or by allocating memory appropriately.  The following is OK:

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

int allocstr(int len, char **retptr)
{
    char *p = malloc(len + 1);

    if (p == NULL)
        return 0;
    *retptr = p;
    return 1;

Quote:
}

int main (void)
{
    char *string = "Hello, world!";
    char **copyptr_ptr;

    copyptr_ptr = malloc(sizeof(char*));

    /* pass pointer to a pointer */
    if(allocstr(strlen(string), copyptr_ptr))
        {
            strcpy(*copyptr_ptr, string);
            printf ("%s\n", *copyptr_ptr);
        }
    return 0;

Quote:
}



Sat, 01 Mar 2003 11:15:17 GMT  
 Interesting Pointer-to-pointer problem

Quote:

> Thanks guys, I understand, but now suppose I still want to use the second
> method.  How do I give the pointer-to-a-pointer (copyptr_ptr) an initial
> value?  Do I have to create some initial dummy variable for it to point
> to?

    The second way dosn't look like a good idea. This is the way it
appears that allocstr was intended to be called.

        char * copyptr;
        allocstr(strlen(string), & copyptr);

This would work too (it's close to the second way), but would waste
memory:
        char * copyptr;
        char **copyptr_ptr  = & copyptr;
        allocstr(strlen(string), copyptr_ptr);

Quote:
> I can't set copyptr_ptr = NULL, because I'm then dereferencing a NULL
> pointer (?) which also does not make sense (I think).

    You are correct

Quote:
> What if I wish to use a pointer-to-pointer-to-pointer?  I'm just trying to
> wrap my head around the idea of the "contents of" vs. the "address of".

    Just think of memory like a wall of safety-deposit boxes at a bank
or post office (This is how I was taught). Each box has an address, and
contents. For example:

//These are all boxes (the numbers are just for the mailbox analogie):
int x;      //Box 100
char c;     //Box 101
char *p;    //Box 102
char **pp;  //Box 103

//At this point, all of the boxes contain garbage left over from
//the previous inconsiderate customers

x   = 5;    //This puts a little slip of paper inside box 100
            //That says "This is a five"

c   = 'X';  //This puts a little slip of paper inside box 101
            //That says "This is a capital x"

p   = &c;   //This puts a little slip of paper inside box 102
            //However this paper says "look in box 101"

pp  = &p;   //This puts a little slip of paper inside box 103
            //However this paper says "look in box 102"

    In this example, the contents of the boxes equate to the contents of
the variables, while the numbers on the boxes are equivelant to the
addresses of the variables. It's best to think of the address of a
variable like a unique label.

Quote:
>     As well, a pointer is a pointer is a pointer.  That is, we do not need
> to cast a pointer unless we wish to interpret the contents of what the
> pointer points to.  Is this notion correct?  This is what I'm getting from
> the "not casting the malloc( ) with allocstr( )".

    For the most part, yes, a void* (what malloc returns) can represent
any other type of pointer, but it's best not to mix other pointer types
when it can be avoided.


Sat, 01 Mar 2003 14:35:03 GMT  
 Interesting Pointer-to-pointer problem

Quote:

>     As well, a pointer is a pointer is a pointer.  That is, we do not need
> to cast a pointer unless we wish to interpret the contents of what the
> pointer points to.  Is this notion correct?  This is what I'm getting from
> the "not casting the malloc( ) with allocstr( )".

No; but malloc() returns a void * which is specifically guaranteed to be
compatible with every other object pointer type, so you _can_ do it with
this one.
Assigning random pointer types to random other pointer types can lead to
problems (the alignment requirements might be different, for example),
but you can always assign any object pointer to void * and then back to
the original type, without any loss; and you can always assign the
return value from malloc() to any object pointer.
What you can't do, for example, is to assign a foo * to a void *, and
then from that void * to a bar *, and expect the result to be valid.

Richard



Sat, 01 Mar 2003 16:30:32 GMT  
 Interesting Pointer-to-pointer problem
Thanks all for zee answers.  Helped greatly.  Now back to my 12 hour days
of irradiation in front of my monitor.....

Regards,
Vinnie



Sun, 02 Mar 2003 01:07:10 GMT  
 Interesting Pointer-to-pointer problem
Groovy hepcat Vincent Dang was jivin' on Mon, 11 Sep 2000 18:36:10
-0600 in comp.lang.c.
Re: Interesting Pointer-to-pointer problem's a cool scene! Dig it!

Quote:
>        I understand, but now suppose I still want to use the second
>method.  How do I give the pointer-to-a-pointer (copyptr_ptr) an initial
>value?  Do I have to create some initial dummy variable for it to point

  You already have a perfectly good object for it to point at,
copyptr. But, there's one thing you have to do first. Since copyptr
has already been allocated some memory to point at, you'll have to
free that memory before re-using copyptr, otherwise your program will
lose contact with that memory, and you'll have a memory leak. For
every allocation there must be a coresponding deallocation.
Alternatively you could use another pointer variable and point
copyptr_ptr at that.

Quote:
>to?  I can't set copyptr_ptr = NULL, because I'm then dereferencing a NULL
>pointer (?) which also does not make sense (I think).  What if I wish to

  That's right.

Quote:
>use a pointer-to-pointer-to-pointer?  I'm just trying to wrap my head
>around the idea of the "contents of" vs. the "address of".

  Well, what's there to wrap around? This is an extremely simple
concept. A pointer is an object whose purpose is to contain the
address of another object. All objects (except those with static
duration - but never mind that for now) contain garbage values at
start up. In order for them to contain useful values you must give
them those values. Pointers are no exception. A pointer must contain
the address of another object in order to be useful. Now, a pointer to
pointer must, obviously, contain the address of another pointer. So, a
pointer to pointer to char must contain the address of a pointer to
char. How do you get the address of an object? Well, you already know
that. You use the & operator. So, how do you assign the address of a
pointer to char to a pointer to pointer to char? It's unbelievebly
easy:

char *foo;
char **bar;

bar = &foo;

  I honestly have no idea why people have so much trouble with this. I
can't see where they get mixed up. It's not hard to understand
pointers.

Quote:
>    As well, a pointer is a pointer is a pointer.  That is, we do not need
>to cast a pointer unless we wish to interpret the contents of what the
>pointer points to.  Is this notion correct?  This is what I'm getting from

  I'm not sure what you mean, but it doesn't sound right.

Quote:
>the "not casting the malloc( ) with allocstr( )".

  Oh, well then, you've definitely missed the point. A void *, which
is the type returned by malloc(), can be assigned to any other pointer
type (except pointer to function - but never mind that for now)
without an explicit cast. A pointer to any type (except pointer to
function - never mind for now) can be assigned to a void * without an
explicit cast.
  However, since you didn't include stdlib.h, and therefore don't have
a declaration of malloc() in scope when it is called, the compiler
assumes it returns int. This is, of course, wrong. First of all, the
actual function itself doesn't return an int, it returns a void *. But
the compiler interprets this an an int. What this means is that
anithing could happen. A void * might be smaller than an int, causing
too many bytes to be popped off the program's stack, causing all sorts
of havock. Or a void * might be larger than an int, causing the value
to be truncated when treated as an int. Or the void * might be encoded
in some strange way, which gives some strange value when interpreted
as an int, which becomes an invalid address when cast to another
pointer type. Basically, *anithing* could happen, as I said. There
could be a serious error resulting from this.
  An int may not be assigned to a pointer, and vice versa, without a
cast. But when you cast the return from malloc(), you hide the fact
that the compiler is expecting malloc() to return int and you are
assigning that int to a char *. If you remove the cast, you get a
compiler diagnostic telling you that you cannot assign an int to a
char *. This gives you some indication that something is wrong. Since
the compiler is assuming malloc() returns an int, you can deduce that
there is no valid declaration of malloc() in scope, and thus you can
deduce that you didn't include stdlib.h.
  Now, if you included stdlib.h ITFP, then the compiler would know
that malloc() returns void *, and the cast would be redundant since
you can assign void * to other pointer types without a cast.
--

----- Dig the EVEN NEWER, MORE IMPROVED news sig!! -----

-------------- Shaggy was here! ---------------
    http://aardvark.apana.org.au/~phaywood/
============= Ain't I'm a dawg!! ==============



Mon, 03 Mar 2003 12:12:37 GMT  
 Interesting Pointer-to-pointer problem

Quote:
> ... I'm just trying to wrap my head
> around the idea of the "contents of" vs. the "address of".
>     As well, a pointer is a pointer is a pointer.  That is, we do not need
> to cast a pointer unless we wish to interpret the contents of what the
> pointer points to.  Is this notion correct?  This is what I'm getting from
> the "not casting the malloc( ) with allocstr( )".

No, all pointers are not the same.  In C, for any two types
T and U, pointer-to-T and pointer-to-U are different types.
On *most* systems, they are all *implemented* as
(uniform) addresses, but they are different types.

Pointer to void, declared with void*, is special; you can't
actually use it to access anything, but can convert
a pointer to any object (or incomplete) type to void*,
and back again.  (You may need a cast to lose
const and/or volatile "qualification".)  Since malloc
returns void*, you can assign its value to any object pointer.

And since malloc if successful returns a pointer (to space)
which is correctly aligned for any object type, you can
even dereference the object pointer you assigned!  <G>

The same is true for realloc and calloc.

C99 does guarantee that you can *convert* one object
(or incomplete) pointer to another if it is suitably aligned
and back, but there is no portable way to ensure that,
and similarly one function pointer to another and back.
But this does not mean that the pointers must have
the same representation.

--
- David.Thompson 1 now at worldnet.att.net



Sun, 09 Mar 2003 12:27:26 GMT  
 Interesting Pointer-to-pointer problem

Quote:

> >     As well, a pointer is a pointer is a pointer.  That is, we do not need
> > to cast a pointer unless we wish to interpret the contents of what the
> > pointer points to.  Is this notion correct?  This is what I'm getting from
> > the "not casting the malloc( ) with allocstr( )".

> No; but malloc() returns a void * which is specifically guaranteed to be
> compatible with every other object pointer type, so you _can_ do it with
> this one.

Or more precisely, void* is convertible to or from every other object
(or incomplete) pointer type without loss or error, but not necessarily
"compatible" as that term is used in the C standard which means
effectively having the same representation layout in storage.
(Although it's actually defined more abstractly and formally.)
On *many* platforms all pointers are just a flat address,
and are compatible, but this is not required by the standard.

Quote:
> Assigning random pointer types to random other pointer types can lead to
> problems (the alignment requirements might be different, for example),
> but you can always assign any object pointer to void * and then back to
> the original type, without any loss; and you can always assign the
> return value from malloc() to any object pointer.
> What you can't do, for example, is to assign a foo * to a void *, and
> then from that void * to a bar *, and expect the result to be valid.

Yes.  Although C99 now guarantees that *if the alignment is OK*
the value is preserved, which C89 did not, but as there is no fully
portable way to ensure or even check alignment this is not as useful
as one might wish, except for pointers to character types.

C99, unlike C89, also guarantees lossless conversions among
pointers-to-function, but not between them and object/incomplete pointers.

--
- David.Thompson 1 now at worldnet.att.net



Sun, 09 Mar 2003 13:39:52 GMT  
 
 [ 12 post ] 

 Relevant Pages 

1. Dereferencing f-pointers, arrays of f-pointers, pointers to f-pointers

2. memory leak: pointer->pointer->pointer->struct

3. Pointer of Pointers was Pointer of arrays...

4. memory block containing pointers, aka pointer to pointer i believe

5. pointers pointers pointers!!!

6. memory Leak: pointer->pointer->pointer->struct

7. Pointer Functions and Pointers to Pointer Functions

8. Pointer to Pointer to Pointer....

9. Question on pointer-to-pointer-to-pointer

10. How to use (pointer to function), and function and pointer to (pointer to function)

11. double pointer (or pointer to pointer)

12. Pointers: return of pointer to array of pointers to main

 

 
Powered by phpBB® Forum Software