#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    6
    Rep Power
    0

    Pointers,structures, call by value and call by reference parameters


    Hi guys,

    Code:
    #include <stdio.h>
    typedef struct
    {
        float *px,x;
    }Something;
    Something read(void);
    int main()
    {
        Something *py,y;
        py=&y;
        (*py)=read();
        printf("\n main() *(py->px) : %.2f\n",*(py->px));  //it prints correctly
        printf("\n\n main() *(py->px) : %.2f\n\n",*(py->px)); // Why it is 0.00  ???
    }
    Something read(void)
    {
        Something temp,*pt;
        pt=&temp;
        pt->px=&(*pt).x;
        pt->x=3;
        printf("\n\n read() *(pt->px) : %.2f\n",*(pt->px));
        return temp;
    }

    if u ask why do u need this code, ı dont need this code, ı am just trying to understand pointers,structures, call by value and call by reference parameters very well. Thats why i am trying to write codes using pointers.

    When i am compiling code, in the second printf it gives 0.00 and i really can't understand why.

    if u share what u know about this situation, i will be gratefull :)
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,086
    Rep Power
    2222
    Compiling your code with MinGW gcc on Win7:
    C:\otros\dcw>gcc -Wall bashburak1.c
    bashburak1.c: In function `main':
    bashburak1.c:14: warning: control reaches end of non-void function

    C:\otros\dcw>
    You quite correctly declare main to return int, but then you never do return that int. You lied to the compiler. You need to return an int at the end of main; returning zero at the end of successfully execution is standard.

    That has nothing to do with your question, but it must be taken care of. Along with your dangerous practice of running a program despite warnings.

    Well, that certain is a convoluted example. And it certainly does look strange at first glance that the exact-same printf would output something different the second time it's called. As if the first call had changed the data. Which is exactly what happened.

    Your problem is that you are using a pointer to data that no longer exists and which has been overwritten.

    I'm assuming that you understand the stack and how functions use the stack when called and the consequences that these facts have for the local variables within the function. temp is a local variable within read() and you are trying to access a field within it after its memory was recycled following the return from read().

    When you called read(), space on the stack was allocated for temp. When you returned from read(), that space for temp was released. When you called printf the first time in main(), that space that temp used to be in was given to printf to use. Quite obviously, printf wrote something to the memory location that temp used to have. Then in the second printf, you tried to access that memory location that no longer belonged to temp and that the first printf had written to. Quite naturally, the second printf output what the first printf had written to that location.

    QED

    If you were to declare temp as static, then you would move it off of the stack and into read/write memory (along with the global variables) where it would continue to exist after the return from read() and for the entire duration of the program. When I made that one change (actually, I split the declarations of temp and *ptr into two lines), this is the output I got:
    C:\otros\dcw>a


    read() *(pt->px) : 3.00

    main() *(py->px) : 3.00


    main() *(py->px) : 3.00


    C:\otros\dcw>

    Comments on this post

    • bashburak agrees : Thanks for help :)
  4. #3
  5. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,086
    Rep Power
    2222
    As an experiment, I modified your program slightly by adding extra fields around the two fields in the Something struct:
    Code:
    typedef struct
    {
        int   dummy1[10];
        float *px,x;
        int   dummy2[10];
    }Something;
    When I compiled and ran that, here is my output:
    C:\otros\dcw>a


    read() *(pt->px) : 3.00

    main() *(py->px) : 3.00


    main() *(py->px) : 1674927921392962400000000000000000.00


    C:\otros\dcw>
    What you get in that last printf all depends on just what random garbage just happens to be in that memory location. Effectively, you have turned that px field into an uninitialized pointer.
    Last edited by dwise1_aol; December 22nd, 2013 at 02:14 AM.
  6. #4
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    6
    Rep Power
    0
    first of all i wrote an example that not includes structure type parameters,

    1.
    Code:
    #include <stdio.h>
    int read(void);
    int main()
    {
        int *px,x;
        px=&x;
        x=read();
        printf("\n *px : %d \n",*px);  // it is ok
        printf("\n *px : %d \n",*px);  // it is ok
        return 0;
    }
    int read(void)
    {
        int temp;
        temp=3;
    then i did it with more pointers,

    2.
    Code:
    #include <stdio.h>
    int read(void);
    int main()
    {
        int *px,x;
        px=&x;
        (*px)=read();
        printf("\n *px : %d \n",*px); // it is ok
        printf("\n *px : %d \n",*px); // it is ok
        return 0;
    }
    int read(void)
    {
        int *pt,temp;
        pt=&temp;
        (*pt)=3;
        return temp;
    }
    and then i used structure type variables, 3. code is the similar as the 1. code, only difference is variable types.

    in 1. code my variable type is int, and in 3. code my variable type is Something.

    3.
    Code:
    #include <stdio.h>
    typedef struct
    {
        float *px,x;
    }Something;
    Something read(void);
    int main()
    {
        Something *py,y;
        py=&y;
        (*py).px=&py->x;
        y=read();
        printf("\n main() *(py->px) : %.2f\n",*(py->px));  	  // i was not expecting this
        printf("\n\n main() *(py->px) : %.2f\n\n",*(py->px)); // i was not expecting this
        return 0;
    }
    Something read(void)
    {
        Something temp;
        temp.x=3;
        return temp;
    }
    and then i understand that structure type variables are a little bit different from int,float, etc type variables.

    lets say we have 2 int variables named with x and y and we have *px pointer which is keeping x's address. what ever i do with

    x will effect same on *px. for example if x=3, *px is 3. lets say y=5 and x=y then *px is 5. I mean pointers value will change

    but adress will be same until u manually change it.

    but it is not same in structure type variables.

    4.
    Code:
    #include <stdio.h>
    typedef struct
    {
        float *px,x;
    }Something;
    int main()
    {
        Something *py,y,z;
        py=&y;
        (*py).px=&py->x;
        *(py->px)=3;
        printf("\n main() *(py->px) : %.2f\n",*(py->px));
        z.x=5;
        y=z;
        printf("\n main() *(py->px) : %.2f\n",*(py->px));
        printf("\n main() py->px : %.2f\n",py->x);
        return 0;
    }
    in 4. code, *py remains keeping y's address, (*py).x is changed but (*py).px is lost :D Because for z, z.px didn't have any address.

    thats why i should write z.px=&z.x before y=z, or i should rewrite (*py).px=&py->x after y=z.


    but when it comes to 5. code which is similar to 2. code, i understood that, for now, i am not able to understand whats going on with

    this pointers. both y and temp has same things. I mean temp has *px pointer which shows x, y has *px pointers that also have adress.

    5.
    Code:
    #include <stdio.h>
    typedef struct
    {
        float *px,x;
    }Something;
    Something read(void);
    int main()
    {
        Something *py,y;
        py=&y;
        py->px=&py->x; // 
        y=read();
        printf("\n main() *(py->px) : %.2f\n",*(py->px));
        printf("\n\n main() *(py->px) : %.2f\n\n",*(py->px));
        return 0;
    }
    Something read(void)
    {
        Something *pt, temp;
        pt=&temp;
        pt->px=&(*pt).x;
        *(pt->px)=3;
        printf("\n\n read() *(pt->px) : %.2f\n",*(pt->px));
        return temp;
    }
    As i said before,for now, it seems i am not able to understand this pointers think very well. This knowledge is enough about pointers

    for now. Because it is my first book that i am finishing to study. After i finish this book and do some projects, i will repeat

    this topics again. Maybe with another book.


    This is the Best way for me now :D ,

    6.
    Code:
    #include <stdio.h>
    typedef struct
    {
        float *px,x;
    }Something;
    void read(Something*);
    int main()
    {
        Something *py,y;
        py=&y;
        read(py);
        printf("\n main() *(py->px) : %.2f\n",*(py->px));
        printf("\n\n main() *(py->px) : %.2f\n\n",*(py->px));
        return 0;
    }
    void read(Something *r)
    {
        r->px=&(*r).x;
        r->x=3;
        printf("\n\n read() *(r->px) : %.2f\n",*(r->px));
    }
    Here in 6. code, main() calls read() with "call by reference" parameter. So, everything goes ok with this code :D


    Anyway thanks for reply, good luck :D
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,086
    Rep Power
    2222
    1 through 3 are OK (I assume that in #1 you returned temp).

    This is also correct:
    lets say we have 2 int variables named with x and y and we have *px pointer which is keeping x's address. what ever i do with

    x will effect same on *px. for example if x=3, *px is 3. lets say y=5 and x=y then *px is 5. I mean pointers value will change

    but adress will be same until u manually change it.
    But I disagree in general with the next statement:
    but it is not same in structure type variables.
    Your assessment of what happens in #4 is correct. The pointer field in z is never set, so it contains garbage (whatever just happened to be in memory from the last time that memory location was written to by whatever process preceded this one). The assignment of z to y caused every field in z to be copied to y, such that y->px will contain the same address as z->px, which in this case is garbage.

    In #5, you go back and repeat what you had tried before. Unfortunately, I get the feeling that you did not understand why that did not work. It all is based on some basic principles that apply to everything in C, not just to pointers or to structs.

    BASIC PRINCIPLE: Local variables exist only within their function and only for as long as the function call is in progress. Ie:
    1. Before you call the function, its local variables do not exist.
    2. When you call the function, its local variables are created. This is normally done on the stack, which is a special region of memory that is constantly allocated and reallocated to the various functions as they are called.
    3. When you return from the function, then its local variables are freed up to be used by the next function. Conceptually, they cease to exist and that is the best way to think about them. Implementation-wise, they are marked by the system to be allocated to the next function call; conceptually, they have become garbage, the exact-same type of garbage I was talking about above.

    So in #5, temp is a local variable of the function read(). It comes into existence when you call read and it ceases to exist when you return from read. When you return from read, it becomes garbage waiting to be recycled.

    BASIC PRINCIPLE: a pointer must always point to something. That means that whenever you are about to use a pointer, you must ask yourself whether it actually points to something. That is something that every C programmer must always keep in mind.

    In #5, you set the px field of temp to point to x. As long as you are inside that function, temp exists and the px field contains a valid address. As soon as you exit from read, temp no longer exists and has become garbage. The same would be true of any local variable.

    read() returns temp. That means that the function created a copy of temp that it stored in a special place for the calling function. The px field of that copy of temp contains the same address that the px field of temp did. When you assign that copy, the return value of read, to y, then y->px gets loaded with that same address; it is the very same address as before, but now it points to garbage.

    I do not think that there is anything wrong with your understand of pointers as demonstrated here. Your only problem is not understanding what happens when what you are pointing to no longer exists.


    Your #6 is quite correct. As a matter of fact, as much as possible I pass and return structs with pointers rather than by value. It's my personal preference and it feels cleaner.

    What I really want you to come out of this with is the realization that a pointer must always be pointing to something that actually exists.

IMN logo majestic logo threadwatch logo seochat tools logo