NAVIGATION

SWE596 Dynamic Web Term Project

course by Haluk BINGOL

C++ Pointers

Reha YILMAZLAR (10.02.2021)





Pointers


A pointer is a variable that holds the address of another variable. It is the direct memory address location such as 0x74FA7686

How to declare a pointer variable?

Pointer is declared just like any other variable in C++ with a slight difference. You add an asterisk "*" before the variable name.

  • You must declare a type and a variable name.
  • type_of_data *variable_name
  • To assign the address of the variable to the pointer, "&" operator is used. "&" operator returns the address of a variable.
  • 
    int intNumber = 5; // integer type variable declaration.
    int *intPtr; // pointer declaration.
    intPtr = &intNumber; //assigning the address of the variable to the pointer.
    
    double dblNumber = 6.2;
    double *doublePtr;
    doublePtr = &dblNumber;
    
    char exampleChar = 'A';
    char *charPtr;
    charPtr = &exampleChar;
            

    Note that, variable and the pointer that points to that variable should be the same type. That means to store the address of an integer in a pointer, pointer should have the integer type as well.

    
    int intNumber = 5;
    int *intPtr;
    intPtr = &intNumber;
            

    What happens in the background?


    When we declare a variable, a memory address is reserved for that variable. When we declare a pointer and assign a variable's address to that pointer, basically we take the address of the original variable and store it in the pointer as the pointer's value.

    
    #include <iostream>
    using namespace std;
    
    int main() {
    int intNumber = 5;
    int* intPtr;
    intPtr = &intNumber;
    
    cout << "The value of intNumber: " << intNumber << endl;
    cout << "The value of &intNumber: " << &intNumber << endl;
    cout << "The value of intPtr: " << intPtr << endl;
    cout << "The value of *intPtr: " << *intPtr << endl;
    
    return 0;
    
    }
    
    
    //OUTPUT
    The value of intNumber: 5
    The value of &intNumber: 0x74FA7686
    The value of intPtr: 0x74FA7686
    The value of *intPtr: 5
    

    As seen above, if we try to output inPtr variable's value directly, we get the address of intNumber element. We had declared it like that already, hence it is not surprising.

    What happens in the background?


    Call by reference and by value

    What happens in the background?


    When we declare a variable, a memory address is reserved for that variable. When we declare a pointer and assign a variable's address to that pointer, basically we take the address of the original variable and store it in the pointer as the pointer's value.

    
    int intNumber = 5;
    int* intPtr;
    intPtr = &intNumber;
    
    cout << "The value of intNumber: " << intNumber << endl;
    cout << "The value of &intNumber: " << &intNumber << endl;
    cout << "The value of intPtr: " << intPtr << endl;
    cout << "The value of *intPtr: " << *intPtr << endl;
    
    
     //OUTPUT
    The value of intNumber: 5
    The value of &intNumber: 0x74FA7686
    The value of intPtr: 0x74FA7686
    The value of *intPtr: 5
    

    Now, if we try to change the pointer's value, what happens is, the new value will be stored in the memory location that the pointer is pointing to. In our case, it will overwrite the intNumber's value with the new value of 10.

    
    int intNumber = 5;
    int *intPtr;
    intPtr = &intNumber;
    *intPtr = 10;
            

    What happens in the background?


    Call by reference and by value

    Dereferencing The Pointer


    As seen in the previous examples, we could access the value that is stored in the original variable by pointer. In order to access that value, we use dereferencing operator "*" again.

    Let's see an example to remember and understand better.

    
    #include <iostream>
    using namespace std;
    
    int main() {
    int intNumber = 5; // Declare a variable and set the initial value to 5.
    int *intPtr; //Declare the pointer.
    intPtr = &intNumber; // Assigning the address of variable to the pointer.
    
    cout << "The value of intNumber: " << intNumber << endl;
    cout << "The address of intNumber(&intNumber): " << &intNumber << endl;
    cout << "The value of intPtr: " << intPtr << endl;
    cout << "Dereferencing intPtr (*intPtr): " << *intPtr << endl;
    
    return 0;
    
    }
            
    
    //OUTPUT
    The value of intNumber: 5
    The address of intNumber(&intNumber): 0x00FCFD98
    The value of intPtr: 0x00FCFD98
    Dereferencing intPtr (*intPtr): 5
            

    Note that, address is assigned dynamically and might change everytime you run the code.

    Call by Methods in C++


    In order to understand better where we can make use the pointers, first we must know the following terms: call by reference, call by value.

    
    #include <iostream>
    using namespace std;
    
    // Pass value
    int doubleIt(int number)
    {
    // Address of number1 in doubleIt is not the same as number in main()
    cout << "Address of number1 in doubleIT(): " << &number << "\n";
    
    // only the clone gets modified inside this function not the real number that we are sending from mnain().
    number *= 2;
    return number;
    }
    // Pass value by reference with pointer arg.
    void doubleItReferenceWithPointer(int* number)
    {
    // Address of number in doubleItReferenceWithPointer is the same as number in main()
    cout << "address of number2 in doubleItReferenceWithPointer(): " << number << "\n";
    
    // Explicit de-referencing to get the value pointed-to
    *number *= 2;
    }
    
    // Pass value by reference with reference arg.
    void doubleItReferenceWithReference(int& number)
    {
    // Address of number3 in square3() is the same as n3 in main()
    cout << "Address of number3 in doubleItReferenceWithReference(): " << &number << "\n";
    
    // Here Implicit de-referencing takes place. (without using of dereferencing operator '*')
    number *= 2;
    }
    int main(){
    // Call by Value
    int number1 = 3;
    cout << "Address of number1 in main(): " << &number1 << "\n";
    cout << "Double of number1: " << doubleIt(number1) << "\n";
    cout << "There is no change in number1: " << number1 << "\n";
    
    // Call by Reference with Pointer Arguments
    int number2 = 3;
    cout << "Address of number2 in main(): " << &number2 << "\n";
    doubleItReferenceWithPointer(&number2);
    cout << "Double of number2: " << number2 << "\n";
    cout << "Change reflected in number2 and nowthe new value of number2 is: " << number2 << "\n";
    
    // Call by Reference with Reference Arguments
    int number3 = 3;
    cout << "Address of number3 in main(): " << &number3 << "\n";
    doubleItReferenceWithReference(number3);
    cout << "Double of number3: " << number3 << "\n";
    cout << "Change reflected in number3 and now the new value of number3 is: " << number3 << "\n";
    
    return 0;
    }
    

    Call by Methods in C++


    Call by reference and by value

    Call by Methods in C++


    In order to understand better where we can make use the pointers, first we must know the following terms: call by reference, call by value.

    
    #include <iostream>
    using namespace std;
    
    // Pass value
    int doubleIt(int number)
    {
    // Address of number1 in doubleIt is not the same as number in main()
    cout << "Address of number1 in doubleIT(): " << &number << "\n";
    
    // only the clone gets modified inside this function not the real number that we are sending from mnain().
    number *= 2;
    return number;
    }
    // Pass value by reference with pointer arg.
    void doubleItReferenceWithPointer(int* number)
    {
    // Address of number in doubleItReferenceWithPointer is the same as number in main()
    cout << "address of number2 in doubleItReferenceWithPointer(): " << number << "\n";
    
    // Explicit de-referencing to get the value pointed-to
    *number *= 2;
    }
    
    // Pass value by reference with reference arg.
    void doubleItReferenceWithReference(int& number)
    {
    // Address of number3 in square3() is the same as n3 in main()
    cout << "Address of number3 in doubleItReferenceWithReference(): " << &number << "\n";
    
    // Here Implicit de-referencing takes place. (without using of dereferencing operator '*')
    number *= 2;
    }
    int main(){
    // Call by Value
    int number1 = 3;
    cout << "Address of number1 in main(): " << &number1 << "\n";
    cout << "Double of number1: " << doubleIt(number1) << "\n";
    cout << "There is no change in number1: " << number1 << "\n";
    
    // Call by Reference with Pointer Arguments
    int number2 = 3;
    cout << "Address of number2 in main(): " << &number2 << "\n";
    doubleItReferenceWithPointer(&number2);
    cout << "Double of number2: " << number2 << "\n";
    cout << "Change reflected in number2 and nowthe new value of number2 is: " << number2 << "\n";
    
    // Call by Reference with Reference Arguments
    int number3 = 3;
    cout << "Address of number3 in main(): " << &number3 << "\n";
    doubleItReferenceWithReference(number3);
    cout << "Double of number3: " << number3 << "\n";
    cout << "Change reflected in number3 and now the new value of number3 is: " << number3 << "\n";
    
    return 0;
    }
    

    Call by Methods in C++





    
    //OUTPUT
    Address of number1 in main(): 0x00B6FC10
    Address of number1 in doubleIT(): 0x00B6FB20
    Double of number1: 6
    There is no change in number1: 3
    
    Address of number2 in main(): 0x00B6FC04
    address of number2 in doubleItReferenceWithPointer(): 0x00B6FC04
    Double of number2: 6
    Change reflected in number2 and nowthe new value of number2 is: 6
    
    Address of number3 in main(): 0x00B6FBF8
    Address of number3 in doubleItReferenceWithReference(): 0x00B6FBF8
    Double of number3: 6
    Change reflected in number3 and now the new value of number3 is: 6
                 

    It is important to see that ordinary function calls (the ones that we normally use) do not change the original value of the variable. Whereas when the variables are sent as references, their values are changed as well. Notice that because of this, reference functions do not have a return value as the variables' values have already changed.

    Arrays and Pointers


    There is a close relationship with arrays and pointers. If you check the value of the array name, you will see that it points to the first element of the array in C++. That means it is like a pointer to the array's first element. And it is possible to use array name like a pointer.(In almost all cases, there are exceptions.) To give an example let's check the following code:

    
    #include <iostream>
    
    using namespace std;
    
    int main() {
    
    int intArray[4] = { 1, 2, 3, 4 };
    int *arrayPointer;
    arrayPointer = intArray;
    
    cout << "The value of intArray: " << intArray << endl;
    cout << "The value of the arrayPointer: " << arrayPointer << endl;
    cout << "The address of the intArray (&intArray) is: " << &intArray << endl;
    cout << "Dereferencing the arrayPointer (*arrayPointer): " << *arrayPointer << endl;
    // We did not declare this as a pointer, but since it is an array name it behaves like one.
    cout << "Dereferencing the intArray(*intArray): " << *intArray << endl;
    return 0;
    }
                
    
    //OUTPUT
    The value of intArray: 0x0078FECC
    The value of the arrayPointer: 0x0078FECC
    The address of the intArray (&intArray) is: 0x0078FECC
    Dereferencing the arrayPointer (*arrayPointer): 1
    Dereferencing the intArray(*intArray): 1
           

    As you can see above, intArray and arrayPointer have the same values which is the address to the first element in the array in memory.

    Arrays and Pointers


    Let's see one more example with a for loop:

    
    #include <iostream>
    
    using namespace std;
    
    int main() {
    
    int intArray[4] = { 1, 2, 3, 4 };
    int *arrayPointer;
    arrayPointer = intArray;
    
    for (int i = 0; i < 4; i++) {
    cout << "intArray[" << i << "]: " << intArray[i] << endl;
    }
    
    for (int i = 0; i < 4; i++) {
    cout << "*(arrayPointer+" << i << "): " << *(arrayPointer + i) << endl;
    }
    
    cout << "*arrayPointer: " << *arrayPointer << endl;
    cout << "*intArray: " << *intArray << endl;
    
    return 0;
    }
               
    
    intArray[0]: 1
    intArray[1]: 2
    intArray[2]: 3
    intArray[3]: 4
    
    *(arrayPointer+0): 1
    *(arrayPointer+1): 2
    *(arrayPointer+2): 3
    *(arrayPointer+3): 4
    
    *arrayPointer: 1 // first element of the array.
    *intArray: 1 // first element of the array.
                 

    As can be seen from the example above, array name and pointers can be used interchangeably. That is because array names are also pointers. They point to the first element of the array.

    Arrays and Pointers


    Let's see how it looks in memory:

    
    #include <iostream>
    
    using namespace std;
    
    int main() {
    
    int intArray[4] = { 1, 2, 3, 4 };
    int *arrayPointer;
    arrayPointer = intArray;
    
    cout << "Value of arrayPointer: " << arrayPointer << endl;
    cout << "Address of intArray's first element: " << intArray << endl;
    cout << "Address of intArray's second element: " << intArray + 1 << endl;
    cout << "Address of intArray's third element: " << intArray + 2 << endl;
    cout << "Address of intArray's fourth element: " << intArray + 3 << endl;
    cout << "*arrayPointer: " << *arrayPointer << endl;
    cout << "*intArray: " << *intArray << endl;
    
    return 0;
    }
               
    
    //OUTPUT
    Value of arrayPointer: 0x0118FA40
    Address of intArray's first element: 0x0118FA40
    Address of intArray's second element: 0x0118FA44
    Address of intArray's third element: 0x0118FA48
    Address of intArray's fourth element: 0x0118FA4C
    *arrayPointer: 1
    *intArray: 1
                 

    See that arrayPointer and intArray both point the same location in the memory.

    Arrays and Pointers


    Array

    THE END

    Reha YILMAZLAR