-3

In the following code why doesn't the address of j gets overwritten in p when we call the foo function?

#include <stdio.h>
        int main()
        {
            int i = 97, *p = &i;
            foo(&i);
            printf("%d ", *p);
        }
        void foo(int *p)
        {
            int j = 2;
            p = &j;
            printf("%d ", *p);
        }
  • the `p` in `main` and the `p` in `foo` are two totally different variables in totally different scopes. – yano Jan 04 '18 at 17:52
  • 1
    He needs to add a * and remove a &, but figuring out which is probably the reason the homework was assigned :o) – Will Crawford Jan 04 '18 at 17:58
  • 1
    `foo(&i);` passes the address of `main` `i` to `foo()`. `foo(int *p)` receives that address as `p` and then assigns `foo` `p` to the address of the local `j` effectively ignoring whatever was passed into `foo`. – chux - Reinstate Monica Jan 04 '18 at 18:05

4 Answers4

4

You are printing with foo - which sets p to 2, then you call a print to p, which is still set to 97 in that scope. foo does not set p globally.

meaning-matters
  • 21,929
  • 10
  • 82
  • 142
Josh Adams
  • 2,113
  • 2
  • 13
  • 25
2

Because p in main is another variable than p in the function. Consequently, even if p is changed inside the function, the value of p in main is still the same and still points to 97.

In more details:

    int main()
    {
        int i = 97, *p = &i;  // i is 97 and p points to i
        foo(&i);
        printf("%d ", *p);    // This prints what p points to, i.e. 97
    }
    void foo(int *p)
    {
        int j = 2;   // Here p still points to i in main
        p = &j;      // Now p points to j, i.e. the value 2
        printf("%d ", *p);  // So this prints 2
    }

Just to repeat: The important thing is that p in main and p in foo are two different variables.

If you want the program to print 2 2 you can change the function to:

    void foo(int *p)
    {
        int j = 2;
        *p = j;     // Change this line. This will change i in main
                    // and thereby also the value that p in main points to
        printf("%d ", *p);
    }
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • 2
    p isn't even passed. It's a reference to i that's passed. But yeah. – JGroven Jan 04 '18 at 17:48
  • 1
    @JGroven - There is no references in C. But your right - what is passed is the address of `i` which just happens to be the same value that is assigned to `p` in main. – Support Ukraine Jan 04 '18 at 17:51
  • @4386427 There is no pass-by-reference in C. Yet `&i` can rightly be called a referencing of `i`. `&i` in itself has nothing to do with the function call. – chux - Reinstate Monica Jan 04 '18 at 17:57
  • @chux What to you mean by: "&i in itself has nothing to do with the function call"? It is exactly what is passed to the function. – Support Ukraine Jan 04 '18 at 18:01
  • The referencing of `i`, done with `&`, results in the address of `i`. That operation is prior to the function call and so is not part of the function call's pass by value. It is as if `int *q = &i; foo(q);` Hence the [comment](https://stackoverflow.com/questions/48100752/why-is-the-output-of-the-following-program-2-97-and-not-2-2/48100828?noredirect=1#comment83176766_48100828) concerning @JGroven "It's a reference to i that's passed". – chux - Reinstate Monica Jan 04 '18 at 18:10
  • 1
    @chux Of cause `&i` is evaluated before the function call but to me it is too much nitpicking to state that it is unrelated to `&i` as the value passed is simply the address of `i`. Anyway - C doesn't have references. A pointer is something different than a reference. And a reference is not limited to passing to a function like in "pass by reference" – Support Ukraine Jan 04 '18 at 18:15
  • 1
    @JGroven - As the answers in your link says, there is no such thing as references in C. C passes by value and C doesn't have references locally either. C has pointers which is different from references. See https://stackoverflow.com/questions/4305673/does-c-have-references – Support Ukraine Jan 04 '18 at 18:27
  • @4386427 TIL and thank you. Pointers can still be dereferenced, though, which I think leads to a lot of confusion in this semantical matter. – JGroven Jan 04 '18 at 18:38
  • 2
    C spec uses "reference" as [@JGroven](https://stackoverflow.com/questions/48100752/why-is-the-output-of-the-following-program-2-97-and-not-2-2/48100828?noredirect=1#comment83176766_48100828) uses it. "A pointer type describes an object whose value provides a _reference_ to an entity of the referenced type." – chux - Reinstate Monica Jan 04 '18 at 19:09
0

Below are the steps:

    int main()
    {
        int  i = 97;
        int* p = &i;        // 1. p points to i, i is 97.
        foo(&i);            // 2. Pass the address of i by value.

        printf("%d ", *p);  // 6. Print the value of i as neither p nor i have not changed inside foo().
    }

    // I've renamed the parameter name from p to q for clarity. q is local to
    // foo() only; changes made to q are only visible within foo().
    void foo(int* q)
    {                      // 3. q contains a copy of i's address.
        int j = 2;
        q     = &j;        // 4. q is set to the address of j. 

        printf("%d ", *q); // 5. Print the value of j.
    }

If you would have done *q = 2 inside foo() you would have changed i's value to 2. That's because q contains the address of i.

meaning-matters
  • 21,929
  • 10
  • 82
  • 142
0

The p in main is a different object in memory than the p in foo. Writing to one has no effect on the other. If you want foo to update the value of p in main, then you must pass a pointer to p:

#include <stdio.h>
int main()
{
    int i = 97, *p = &i;
    foo(&p);
    printf("%d ", *p);
}

void foo(int **p)
{
    int j = 2;
    *p = &j;
    printf("%d ", **p);
}

WARNING - doing this will invoke undefined behavior, since p will point to an object that no longer exists - once foo exits, j no longer exists, and p will be an invalid pointer. You may get the output you expect, or you may not.

In order for a function to write to a parameter, you must pass a pointer to that parameter:

void foo( T *ptr )
{
  *ptr = new_value(); // updates the thing ptr points to
}

void bar( void )
{
  T var;              // var is an instance of T
  foo( &var );        // have foo update the value of var
}

This is true for any non-array type T, including pointer types. If we replace T with the pointer type P *, we get

void foo( P * *ptr )
{
  *ptr = new_value(); // updates the thing ptr points to
}

void bar( void )
{
  P * var;            // var is an instance of P *
  foo( &var );        // have foo update the value of var
}

The semantics are exactly the same - the only thing that's changed is that var starts out as a pointer type.

Things get weird with array types, which we're not going to go into quite yet.

John Bode
  • 119,563
  • 19
  • 122
  • 198