Confused about accessing structure members via a pointer

I am new to C and I am confused with the results I get when referencing a structure member using a pointer. See the following code for an example. What happens when I reference the tst-> number the first time? What is the main thing am I missing here?

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

typedef struct {
   int number;
} Test;

Test* Test_New(Test t,int number) {
    t.number = number;
    return &t;
}    

int main(int argc, char** argv) {    
    Test test;
    Test *tst = Test_New(test,10);
    printf("Test.number = %d\n",tst->number);
    printf("Test.number = %d\n",tst->number);
    printf("Test.number = %d\n",tst->number);
}

      

Output:

Test.number = 10
Test.number = 4206602
Test.number = 4206602

      

+1


source to share


8 answers


When you pass a test to your Test_New function, you are passing it by value, and therefore a local copy is made on the stack for the function scope of your Test_New function. Since you're returning the address of a variable as soon as the function returns the stack, it's useless, but you've returned a pointer to a structure on the old stack! So you can see that your first call is returning the correct value as nothing has overwritten your stack value, and subsequent calls (which all use the stack) overwrite your value and give you erroneous results.

To do this, rewrite the Test_New function correctly to take a pointer and pass a pointer to a structure to the function.



Test* Test_New(Test * t,int number) {
    t->number = number;
    return t;
}

int main(int argc, char ** argv)  {
   Test test;
   Test * tst = Test_New(&test,10);

   printf("Test.number = %d\n",tst->number);
   printf("Test.number = %d\n",tst->number);
   printf("Test.number = %d\n",tst->number);

}

      

+13


source


Regardless struct

, it is always wrong to return the address of a local variable . It is usually also wrong to put the address of a local variable in a global variable or store it in an object allocated on the heap with malloc

. Typically, if you need to return a pointer to an object, you either need to get someone else to specify the pointer for you, or you will need to allocate space with a help malloc

that will return the pointer. In this case, part of the API for your function should specify who is responsible for calling free

when the object is no longer needed.



+3


source


You are returning the address t

as specified in the method Test_New

, not the address test

that you passed to that method. That is, it is test

passed by value, and you should instead pass a pointer to it.

So this is what happens when you call Test_New

. A new structure is created test

with a name t

and t.number

set to a value test.number

(which you have not initialized). Then you set t.number

equal to the parameter number

you passed to the method and then you return the address t

. But it t

is a local variable and goes out of scope as soon as the method ends. This way you are returning a pointer to data that no longer exists and therefore you end up in garbage.

Change your ad Test_New

to

Test* Test_New(Test* t,int number) {
    t->number = number;
    return t;
}

      

and call it through

Test *tst = Test_New(&test,10);

      

and everything will go as you expect.

+1


source


The problem is that you are not passing a reference to Test_New

, you are passing a value. Then you return the memory location of the local variable. Consider this code that demonstrates your problem:

#include <stdio.h>

typedef struct {
} Test;

void print_pass_by_value_memory(Test t) {
  printf("%p\n", &t);
}

int main(int argc, char** argv) {
  Test test;
  printf("%p\n", &test);
  print_pass_by_value_memory(test);

  return 0;
}

      

The output of this program on my computer:

0xbfffe970
0xbfffe950

      

+1


source


Just to expand on BlodBath's answer, think about what's going on in memory when you do this.

When you enter your main routine, a new automatic test structure is created - on the stack, as it is automatic. So your stack looks something like

    | return address for main | will be used at bottom
    | argc | copied onto stack from environment
    | argv address | copied onto stack from environment
-> | test.number | created by definition Test test;

c ->

, pointing the stack pointer to the last used stack element.

Now you call Test_new()

and it updates the stack like this:

    | return address for main | will be used at bottom
    | argc | copied onto stack from environment
    | argv address | copied onto stack from environment
    | test.number | created by definition Test test;
    | return addr for Test_new | used to return at bottom
    | copy of test.number | copied into the stack because C ALWAYS uses call by value
-> | 10 | copied onto stack

When you return &t

, what address do you get? Answer: the address of the data on the screen. BUT THEN you return, the stack pointer is decremented. When you call printf

these words are reused on the stack, but your address still matches them. It happens that a number in the place on the stack that is interpreted as an address points to the value 4206602, but this is a pure chance; in fact, it was kind of a bad luck, as luck would have been something that caused a segmentation fault, letting you know that something was indeed violated.

+1


source


The test t declared in Test_New () is a local variable. You are trying to return the address of a local variable. When the local variable is destroyed after the function exists, the memory will be freed, the compiler can put a different value in the location where your local variable was stored.

In your program, when you try to access the value a second time, the memory location may have been assigned to another variable or process. Hence, you are getting the wrong result.

Your best bet would be to pass the structure from main () by reference, not by value.

+1


source


You passed the test content by value Test_New. IOW a new copy of the test structure was allocated on the stack when Test_New was called. This is the address of this test that you return from the function.

When you use tst-> number, the first time the value 10 is popped, because although that stack was unwound, no other use of that memory was made. However, once that first printf has been called, the stack memory is reused for whatever it needs, but tst still points to that memory. Hence, sub-sequential use of tst-> number returns whatever printf is left there in that memory.

Use Test & t in your function signature instead.

0


source


You can do something like this to make it a little easier:

typedef struct test {
   int number;
} test_t;

test_t * Test_New(int num)
{
   struct test *ptr;

   ptr = (void *) malloc(sizeof(struct test));
   if (! ptr) {
     printf("Out of memory!\n");
     return (void *) NULL;
   }

   ptr->number = num;

   return ptr;
}

void cleanup(test_t *ptr)
{
    if (ptr)
     free(ptr);
}

....

int main(void)
{
    test_t *test, *test1, *test2;

    test = Test_New(10);
    test1 = Test_New(20);
    test2 = Test_new(30);

    printf(
        "Test (number) = %d\n"
        "Test1 (number) = %d\n"
        "Test2 (number) = %d\n",
        test->number, test1->number, test2->number);
    ....

    cleanup(test1);
    cleanup(test2);
    cleanup(test3);

    return 0;
}

      

... As you can see, it's easy to allocate space for several completely different instances of test_t, for example if you need to keep the existing state of one so you can come back later .. or for some reason.

Unless of course there is some reason why you should keep it local .. but I really can't think of it.

0


source







All Articles