pointers and array of pointers

Discussion in 'C Programming' started by Piotrek, Apr 2, 2007.

  1. Piotrek

    Piotrek Guest

    Hi,
    Like almost all of beginners I have problem understanding pointers.
    Please, look at this piece of code, and please explain me why myswap
    function doesn't work as it's supposed to do, whereas myswap2 is doing
    exactly what I want it to do - swaping pointers. Where I made a mistake?
    Thanks

    void myswap(char *pa, char *pb){
    char *tmp;
    tmp=pa;
    pa=pb;
    pb=tmp;
    }

    void myswap2(char *sw[]){
    char *tmp;
    tmp=sw[0];
    sw[0]=sw[1];
    sw[1]=tmp;
    }

    int main(void){
    char *a="1111", *b="2222", *A[]={"1111","2222"};
    printf("1: %s, 2: %s\n", a,b); //stdout: 1: 1111, 2: 2222
    myswap(a,b);
    printf("1: %s, 2: %s\n", a,b); //stdout: 1: 1111, 2: 2222
    //Not working :/

    printf("2: %s, 2: %s\n", A[0],A[1]); //stdout: 1: 1111, 2: 2222
    myswap2(A);
    printf("2: %s, 2: %s\n", A[0],A[1]); //stdout: 1: 2222, 2: 1111
    //Here it works!
    return 0;
    }

    --
    Piotrek
     
    Piotrek, Apr 2, 2007
    #1
    1. Advertising

  2. Piotrek

    santosh Guest

    Piotrek wrote:
    > Hi,
    > Like almost all of beginners I have problem understanding pointers.
    > Please, look at this piece of code, and please explain me why myswap
    > function doesn't work as it's supposed to do, whereas myswap2 is doing
    > exactly what I want it to do - swaping pointers. Where I made a mistake?
    > Thanks


    First include the stdio.h header for printf.

    > void myswap(char *pa, char *pb){
    > char *tmp;
    > tmp=pa;
    > pa=pb;
    > pb=tmp;
    > }


    The objects pa and pb are local to myswap, i.e. they are _copies_ of
    the arguments the calling function passed to myswap, not the original
    objects themselves. This method of passing parameters to functions is
    called "pass by value." This is the only method C supports. To modify
    the objects in the calling function, pointers to them are needed.

    > void myswap2(char *sw[]){
    > char *tmp;
    > tmp=sw[0];
    > sw[0]=sw[1];
    > sw[1]=tmp;
    > }


    Arrays are always accessed by function through a pointer to their
    first element. Thus the function, in this case myswap2 acts directly
    on the caller's array. No copies are made.

    > int main(void){
    > char *a="1111", *b="2222", *A[]={"1111","2222"};
    > printf("1: %s, 2: %s\n", a,b); //stdout: 1: 1111, 2: 2222
    > myswap(a,b);
    > printf("1: %s, 2: %s\n", a,b); //stdout: 1: 1111, 2: 2222
    > //Not working :/
    >
    > printf("2: %s, 2: %s\n", A[0],A[1]); //stdout: 1: 1111, 2: 2222
    > myswap2(A);
    > printf("2: %s, 2: %s\n", A[0],A[1]); //stdout: 1: 2222, 2: 1111
    > //Here it works!
    > return 0;
    > }


    Just remember that a function's arguments are local objects for that
    function. They're copies of whatever the calling function passed. To
    modify the objects in the calling function, you need to access them
    through pointers, which is what you uknowingly did, by supplying an
    array argument to myswap2.
     
    santosh, Apr 2, 2007
    #2
    1. Advertising

  3. Piotrek

    pete Guest

    Piotrek wrote:
    >
    > Hi,
    > Like almost all of beginners I have problem understanding pointers.
    > Please, look at this piece of code, and please explain me why myswap
    > function doesn't work as it's supposed to do, whereas myswap2 is doing
    > exactly what I want it to do - swaping pointers.
    > Where I made a mistake?


    If you want a function to swap the values
    of two objects outside the function,
    then you need to give to the function
    the addresses of the objects in question.

    > void myswap(char *pa, char *pb){
    > char *tmp;
    > tmp=pa;
    > pa=pb;
    > pb=tmp;
    > }


    void myswap(char **pa, char **pb)
    {
    char *tmp;

    tmp = *pa;
    *pa = *pb;
    *pb = tmp;
    }

    > myswap(a,b);


    myswap(&a, &b);

    --
    pete
     
    pete, Apr 2, 2007
    #3
  4. Piotrek wrote:
    > Hi,
    > Like almost all of beginners I have problem understanding pointers.
    > Please, look at this piece of code, and please explain me why myswap
    > function doesn't work as it's supposed to do, whereas myswap2 is doing
    > exactly what I want it to do - swaping pointers. Where I made a mistake?
    > Thanks
    >
    > void myswap(char *pa, char *pb){
    > char *tmp;
    > tmp=pa;
    > pa=pb;
    > pb=tmp;
    > }


    void cpointer_swap(char **pa, char **pb){
    char *tmp;
    tmp=*pa;
    *pa=*pb;
    *pb=tmp;
    }

    [call with cpointer_swap(&ptr1, &ptr2);]
     
    Martin Ambuhl, Apr 2, 2007
    #4
  5. Piotrek <> writes:
    > Like almost all of beginners I have problem understanding pointers.
    > Please, look at this piece of code, and please explain me why myswap
    > function doesn't work as it's supposed to do, whereas myswap2 is doing
    > exactly what I want it to do - swaping pointers. Where I made a
    > mistake?
    >
    > void myswap(char *pa, char *pb){
    > char *tmp;
    > tmp=pa;
    > pa=pb;
    > pb=tmp;
    > }


    Within the myswap function, pa and pb are local copies of the
    arguments that were passed when the function was called. You swap the
    local copies, which has no effect on anything outside the function.

    If you want to swap two FOOs (where FOO is any arbitrary type), you
    need a function that takes *pointers* to the FOOs you want to swap.
    If you want to swap two pointers (of type char*), you need to pass
    pointers to them (of type char**).

    > void myswap2(char *sw[]){
    > char *tmp;
    > tmp=sw[0];
    > sw[0]=sw[1];
    > sw[1]=tmp;
    > }


    In a function declaration, what looks like an array parameter is
    really a pointer parameter. The declaration

    void myswap2(char *sw[])

    means exactly the same thing as

    void myswap2(char **sw)

    and using the latter form can avoid confusion.

    [snip]

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Apr 2, 2007
    #5
  6. Piotrek <> writes:
    > Like almost all of beginners I have problem understanding pointers.

    [...]

    I forgot to mention: if you haven't already done so, read sections 4
    (Pointers) and 6 (Arrays and Pointers) of the comp.lang.c FAQ,
    <http://www.c-faq.com/>.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Apr 2, 2007
    #6
  7. Piotrek

    Klarth Guest

    I often think of pointers as a VARIABLE that contains a reference to
    an address. So when you are calling myswap, you are passing in copies
    of the references. Want you want to do in myswap is pass the pointers
    by reference so you can change it. You do this by passing in type char
    ** and passing the address of the pointers instead. In myswap2, you
    are already effectively passing by reference, which is why the swap is
    reflected when it returns.
     
    Klarth, Apr 3, 2007
    #7
  8. Piotrek

    CBFalconer Guest

    Klarth wrote:
    >
    > I often think of pointers as a VARIABLE that contains a reference
    > to an address. So when you are calling myswap, you are passing in
    > copies of the references. Want you want to do in myswap is pass the
    > pointers by reference so you can change it. You do this by passing
    > in type char ** and passing the address of the pointers instead. In
    > myswap2, you are already effectively passing by reference, which is
    > why the swap is reflected when it returns.


    What, if anything, does this mean? See below.

    --
    If you want to post a followup via groups.google.com, ensure
    you quote enough for the article to make sense. Google is only
    an interface to Usenet; it's not Usenet itself. Don't assume
    your readers can, or ever will, see any previous articles.
    More details at: <http://cfaj.freeshell.org/google/>



    --
    Posted via a free Usenet account from http://www.teranews.com
     
    CBFalconer, Apr 3, 2007
    #8
  9. Piotrek

    Chris Torek Guest

    In article <eurobb$7v7$>
    Piotrek <> wrote:
    >Like almost all of beginners I have problem understanding pointers.


    In my experience, the usual underlying cause of problems with
    understanding pointers is that they seem "special" and "magical".
    The trick, then, is to realize: pointers are not special or
    magical at all, in any way.

    Consider an ordinary integer:

    #include <stdio.h>

    void silly(int x) {
    x = 0;
    }

    int main(void) {
    int i = 42;

    silly(i);
    printf("i is %d\n", i);
    return 0;
    }

    The function silly() is indeed pretty silly (it does nothing useful,
    setting x to 0 and then returning), but, after you get used to
    by-value parameters, it is no longer surprising that it has no
    effect on the variable "i" in main(). The function silly() gets
    a *copy* of the value of i -- a copy of the 42, in other words --
    and it changes the copy, not the original.

    Pointers are not special! Pointer variables, like ordinary "int"
    variables, hold values. If you change a *copy*, the original is
    unchanged:

    #include <stdio.h>

    void silly_2(int *xp) {
    xp = NULL;
    }

    int main(void) {
    int i = 42;
    int *ip = &i;

    silly_2(ip);
    printf("i is %d\n", i);
    if (ip == &i)
    printf("ip still points to i\n");
    return 0;
    }

    Here, silly_2() gets a *copy* of the value in ip. It changes xp
    -- the copy -- which affects neither ip itself, nor *ip.

    On the other hand, we can make a less-silly function:

    void less_silly(int *xp) {
    *xp = 0;
    }

    and call that (instead of silly_2()) from main():

    int main(void) {
    int i = 42;
    int *ip = &i;

    less_silly(ip);
    printf("i is %d\n", i);
    if (ip == &i)
    printf("ip still points to i\n");
    return 0;
    }

    The call to less_silly() again gives out a *copy* of the value in
    ip, but now less_silly() uses that copy (in xp) to find the place
    the pointer points -- which is main()'s variable "i" -- and change
    that. So less_silly() changes main()'s "i". Since less_silly()
    has only a copy of the value in ip, it cannot change the value in
    ip -- but it can change the value in *ip: the copy in *xp points
    to main()'s "i", and the original in *ip also points to main()'s
    "i".

    >Please, look at this piece of code, and please explain me why myswap
    >function doesn't work as it's supposed to do, whereas myswap2 is doing
    >exactly what I want it to do ...


    Here you are running into something that *is* tricky, in C. While
    pointers are simple (once you understand the gimmick, i.e., that
    pointers are not special at all), *arrays* in C *are* special. And
    the part that is most special of all is what happens when you declare
    a function's formal parameter as an array type, as in myswap2()
    below:

    >void myswap(char *pa, char *pb){
    > char *tmp;
    > tmp=pa;
    > pa=pb;
    > pb=tmp;
    >}


    Here, myswap() does not work because it gets copies of the original
    values (as always) and then changes the two copies. So pa and pb,
    in myswap(), change; but those copies are then thrown away and the
    changes vanish.

    >void myswap2(char *sw[]){


    Here you get the Secret Extra-Special Feature of C.

    The myswap2() function has one parameter, which is named "sw".
    This part is straightforward and normal. It *looks* like sw2 has
    type "array (of unknown size) of pointer to char", but this part
    is *not* normal.

    Whenever a formal parameter has type "array N of T", for any integer
    constant N and type T, the constant N is thrown away and the formal
    parameter's type is rewritten as "pointer to T". (The constant N
    is thrown away, so it can even be omitted, as in this case.) This
    is part of The Rule about arrays and pointers in C -- for more on
    that, see, e.g., <http://web.torek.net/torek/c/pa.html>.

    In this case, it means that "sw" -- which *seems* to have type
    "array ? of pointer to char" -- *really* has type "pointer to
    pointer to char". In other words, the "true" type of myswap2()
    is:

    void myswap2(char **sw) {

    > char *tmp;
    > tmp=sw[0];
    > sw[0]=sw[1];
    > sw[1]=tmp;
    >}


    So, now that we know that myswap2() really takes a "char **",
    consider also what sw[0] "means". The subscript operator takes
    one pointer, and one integer. It adds the two and then does
    an indirection. The pointer here is "sw", and the integer is
    zero. Adding 0 has no effect, so sw[0] "means" the same thing
    as "*sw". Hence, the first three lines can be written as:

    void myswap2(char **sw) {
    char *tmp;
    tmp = *sw;
    *sw = ... the rest goes here ...

    (With sw[1], things are a little less simple. Adding 1 *does* have
    an effect, so this is the same as *(sw + 1). This relies on the
    way arrays are laid out -- which is not surprising after all: it
    just means that C's arrays rely on the way C's arrays work, so C's
    arrays have to work for C's arrays to work. Well, of course they
    do.)

    If we stop relying on arrays, though, we can write a myswap3():

    void myswap3(char **ppa, char **ppb) {
    char *tmp;

    tmp = *ppa;
    *ppa = *ppb;
    *ppb = tmp;
    }

    and now we can call myswap3() from main(), passing &a and &b,
    or passing &A[0] and &A[1]:

    >int main(void){
    > char *a="1111", *b="2222", *A[]={"1111","2222"};
    > printf("1: %s, 2: %s\n", a,b); //stdout: 1: 1111, 2: 2222
    > myswap(a,b);
    > printf("1: %s, 2: %s\n", a,b); //stdout: 1: 1111, 2: 2222
    > //Not working :/
    >
    > printf("2: %s, 2: %s\n", A[0],A[1]); //stdout: 1: 1111, 2: 2222
    > myswap2(A);
    > printf("2: %s, 2: %s\n", A[0],A[1]); //stdout: 1: 2222, 2: 1111
    > //Here it works!
    > return 0;
    >}


    Note that passing "A" is, by The Rule, the same thing as passing
    &A[0]. "The Rule" about arrays and pointers in C tells us that
    the "value" of an array object like "A", whenever we try to use
    its value anyway -- such as in a function call -- is just a pointer
    to the first element of the array. So myswap2(A) "means" myswap2(&A[0])
    -- these are just two ways to write the same thing.
    --
    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.
     
    Chris Torek, Apr 6, 2007
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roger Leigh
    Replies:
    8
    Views:
    473
    Karl Heinz Buchegger
    Nov 17, 2003
  2. Peter B. Steiger

    Can a static array contain a dynamic array of pointers?

    Peter B. Steiger, Apr 19, 2004, in forum: C Programming
    Replies:
    8
    Views:
    2,130
    Dave Thompson
    Apr 26, 2004
  3. mann!

    pointer to array v/s array of pointers

    mann!, Feb 25, 2005, in forum: C Programming
    Replies:
    6
    Views:
    356
    E. Robert Tisdale
    Feb 26, 2005
  4. Sean
    Replies:
    2
    Views:
    658
    loufoque
    Sep 24, 2006
  5. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    729
Loading...

Share This Page