Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C Pointer to Pointer and Pass by Reference

Tags:

c

pointers

I'm trying to learn C, and I'm hung up a bit on Pointers to Pointers. I think I understand why you need them, but can't quite get my head wrapped around what is happening.

For instance, the following code doesn't seem to work as I would expect it to:

#include <stdio.h>

int newp(char **p) {
  char d = 'b';
  *p = &d;
  /*printf("**p = %c\n", **p);*/
  return 1;
}

int main() {
  char c = 'a';
  char *p = &c;
  int result;

  result = newp(&p);
  printf("result = %d\n", result);
  printf("*p = %c\n", *p);
  printf("c = %c\n", c);

  return 0;
}

The result I get is this:

result = 1
*p = 
c = a

*p prints as nothing. Instead, I would expect *p = b.

However, if I uncomment line 6 (the printf in the newp function), then I get this:

**p = b
result = 1
*p = b
c = a

What am I missing?

like image 735
Tim Morgan Avatar asked Jun 28 '11 16:06

Tim Morgan


People also ask

Can you pass a pointer by reference C?

In C, pass by reference is emulated by passing a pointer to the desired type. That means if you have an int * that you want to pass to a function that can be modified (i.e. a change to the int * is visible in the caller), then the function should accept an int ** .

Is pass by reference the same as pass-by-pointer?

The difference between pass-by-reference and pass-by-pointer is that pointers can be NULL or reassigned whereas references cannot. Use pass-by-pointer if NULL is a valid parameter value or if you want to reassign the pointer. Otherwise, use constant or non-constant references to pass arguments.

What is the difference between pass by value and pass-by-pointer in C?

The difference between pass-by-pointer and pass-by-value is that modifications made to arguments passed in by pointer in the called function have effect in the calling function, whereas modifications made to arguments passed in by value in the called function can not affect the calling function.

Is passing by reference faster than pointer?

We take advantage of this small size when storing data and when passing parameters to functions. It's much faster and memory-efficient to copy a pointer than to copy many of the things a pointer is likely to point to. A reference is stored in as many bytes as required to hold an address on the computer.


4 Answers

You are dealing with undefined behaviour. The variable d is local (resides on the stack) and is not available after the enclosing function (newp) returns.

When dereferencing p outside newp, the address on the stack &d may be overwritten by some other local variable or it may contain garbage.

like image 107
Blagovest Buyukliev Avatar answered Sep 21 '22 21:09

Blagovest Buyukliev


You are storing the address of a local variable (d) in *p and then dereferencing it when the variable has gone out of scope. Undefined Behavior

like image 41
Armen Tsirunyan Avatar answered Sep 17 '22 21:09

Armen Tsirunyan


You might be "missing" the keyword static, as in:

int newp(char **p) {
    static char d = 'b';   /* <--- HERE */
    *p = &d;
    /*printf("**p = %c\n", **p);*/
    return 1;
}

This static keyword causes the compiler to locate the local variable in "static storage," which continues to exist (i.e. maintains its value) during the time periods after newp() has been called. However, there is only one copy of this memory -- each subsequent invocation of the containing function (newp) re-uses the same memory location and may overwrite the value at that time.

Without the static keyword to qualify your local variable declaration, the storage will be "automatic", which means that it is automatically discharged from current use after the containing function has returned. After newp returns, the memory formerly used for the local variable can be reused for any purpose.

like image 36
Heath Hunnicutt Avatar answered Sep 18 '22 21:09

Heath Hunnicutt


#include <stdio.h>

// Here *pointer means that the parameter that this function 
// will expect will be a pointer. 
void changeViaPointer(int *pointer);

// Pointer of a pointer.
void changeViaPointerInBetween(int **pointer);

int main(){

    int number;
    number = 20;

    // Here *pointer means that the variable that is declared will be a pointer.
    int *pointer;

    // Actually asigning value to the pointer variable.
    pointer = &number;

    // Pointer of a pointer.
    int **pointerInBetween;

    // Assigning value to the pointer of a pointer. 
    // Assigning the memory location where this pointer points to. 
    // So this is a pointer in between.
    pointerInBetween = &pointer;

    printf("The number before changing is %d\n", number);

    // Pass the pointer variable.
    changeViaPointer(pointer);
    printf("The number after pointer changing is %d\n", number);

    // Pass the pointer of a pointer variable.
    changeViaPointerInBetween(pointerInBetween);
    printf("The number after pointer in between changing is %d\n", number);

    return 0;
}

void changeViaPointer(int *pointer){

    // Okay, at this point we have received a variable called pointer,
    // which points to some value. In order to access this value
    // we need to use *pointer.
    // BUT THIS IS DIFFERENT FROM THE *pointer IN THE FUNCTION DECLARATION!!!
    *pointer = *pointer + 20;
}

void changeViaPointerInBetween(int **pointer){

    // **pointer explanation:
    // Only pointer is the memory location
    // *pointer  is the value of that memory location, which in this specific case is also a memory location
    // **pointer is the value of what the other pointer points to.
    **pointer = **pointer + 20;
}
like image 30
Bilger Yahov Avatar answered Sep 18 '22 21:09

Bilger Yahov