03.POINTERS

SYNTAX

dataType *pointerID;

EXAMPLE

//p is a pointer to a memory location of type integer
//*p will contain actual data
int *p
 * ALT: int* p
 
//p is a pointer to a memory location of type integer
//q is a regular variable
int *p, q

//p & q are pointers to a memory location of type integer
int *p, *q

DEFINITIONS

POINTERS

  • variables whose content is a memory address/location

  • C++ doesn't automatically initializes pointer variables

    • use the following to initializes pointer variables

p = 0             //initialize the variable p to nothing
p = NULL          //initialize the variable p to nothing - equivalent to p = 0

ADDRESS OF OPERATOR (&)

  • the "&" is a unary operator that returns the "address of" its operand

#include <iostream>

using namespace std;

int main()
{
  int x = 25;
  //p is a pointer to a memory location of type integer
  //*p will contain actual data
  int *p;
  p = &x;                 //assign the memory address of x to the pointer p
                          //p = memory address while *p = 25  
  cout << *p << endl;     //print the value pointed by p which is 25
  *p = 55;                //change the content of memory location pointed by p to 55
                          //p = memory address of x while *p = 55
                          //x is now 55  
  cout << *p << endl;     //print the value 55 while "p" is just a memory location
  
  return 0;
}

ASSIGNING MEMORY LOCATIONS

  • CAVEAT: the two instructions below are different! you can't use the & operator using two pointers

//two pointers - assigning memory location
int *p, *q;
p = q;          //this is how you assign the address of q to p with two pointers

//one pointer - assigning memory location
int *p, q;
p = &q;

/********************************************************************************
the declaration int *p, *q declares two pointers, p and q, which can hold the memory address of an integer variable.
however, the assignment of p = &q is not valid because q is not an integer variable - q is a pointer to an integer variable.
therefore, you can't take its address with the "address of" operator (&)

if you want to make p point to q, you can simply assign the value of q to p using the assignment operator (=).
 * e.g.,
   int *p, *q
   p = q;
*********************************************************************************/

OPERATIONS ON POINTER VARIABLES

int main()
{
  int *p, *q;        //p & q are pointers to a memory location of type integer
  char *ch;          //ch is a pointer variable to a memory location of type character
  double *d;         //d is a pointer to a memory location of type double
  p = q;             //assign the address of q to p
                     //*p & *q contains data while p & q contains memory address
                     //any changes made to *p automatically changes the value of
                     //*q & vice versa
  if (p == q)        //compare whether p & q points to the same memory location
  if (p != q)
  p++;               //increment p by 4 bytes - p is type integer; p now points +4 bytes from the base memory location
  d++;               //increment d by 8 bytes - d is type double; d now points +8 bytes from the base memory location
  ch++;              //increment ch by 1 byte - ch is type char; ch now points +1 byte from the base memory location
  
  return 0;
}

DYNAMIC VARIABLES

  • these are variables that are created during a program's execution

  • can be created with the help of pointers

  • uses the operators "new" and "delete"

    • the "new" operator is used to create dynamic variables

      • it allocates memory of the desired type & returns a pointer (the address) to it

    • the "delete" operator is used to delete dynamic variables

new dataType;             //create & allocate a single dynamic variable
new dataType[intExp];     //create & allocate an array of dynamic variables

STATIC VARIABLES

  • these are variables that are created prior to a program's execution (think pre-loaded)

DYNAMIC ARRAYS

  • created during program execution

STATIC ARRAYS

  • fixed size; everytime a program executes, the size of the array is fixed (limitation of static array)

FUNCTIONS & POINTERS

  • pass-by-value

  • pass-by-reference

void functionVar(int* &p, double* q){
  //both p & q are pointers
  //the parameter p is a reference parameter - pass-by-reference
  //the parameter q is a value parameter - pass-by-value
}

//this is a fnction with a pointer as a return type
int* functionVar(int* &p, double* q){
  //the return type of the function is a pointer of type int
}

ISSUES WITH CLASSES & POINTERS

  • if one gets deleted, then all are deleted

    • to resolve this issue, overload the assignment operator IOT have two copies

class List
{
  //private: access specifier is assumed by default if not specifically written
  int *p, n;
  public:
    List();
    void insertEnd(int);
    void print() const;
    void destroyList();
};

List::List(){
  n = 0;
  p = new int[5];
}

int main()
{
  List list1, list2
  for (int i = 0; i < 5; i++)
    list1.insertEnd(10*i);
  
  list2 = list1;       //list1 & list2 are both pointed by the same pointer
  list1.print();       //0 10 20 30 40
  list2.print();       //0 10 20 30 40
  list2.destroyList(); //both list1 & list2 will be destroyed
}
const List& List::operator =(const List& otherList){
  if (this != &otherList){     //this avoids self-assignment
                               //the "this" keyword refers to the 1st object
                               //it refers to the 1st List object NOT the
                               //otherList object
    if (p != NULL)
      destroyList();
    
    n = otherList.n;
    p = new int[5];
    
    for (int i = 0; i < 5; i++)
      p[i] = otherList.p[i];
  }
  
  return *this;
}

DYNAMIC VARIABLES IMPLEMENTATION

int main()
{
  int *p, x;            //p is a pointer to a memory location while *p contains data
  p = &x;               //assign the memory address of x to p; *p contains data
  p = new int;          //create a dynamic variable & allocate memory space of type int
  char *name;           //name is a pointer to a memory location of type char
  name = new char[5];   //create an array of dynamic variables
                        //allocate memory for an array of 5 char elements & store
                        //the base address of the array in name
  strcpy(name, "John"); //store "John" in name
  delete[] name;        //destroy the memory space allocated for the array name
  
  return 0;
}

OBJECT POINTERS IMPLEMENTATION

class classExample{
  int x;
  public:
  void setX(int a){
    x = a;
  }
  void print(){
    cout << "x = " << x << endl;
  }
};

int main()
{
  classExample *cExpPtr, cExpObject;           //cExpPtr is a pointer to a memory location of type classExample
  cExpPtr = &cExpObject;                       //assign the address of cExpObject to cExpPtr;
                                               //*cExpPtr holds actual value
  cExpPtr->setX(5);                            //this syntax is the simply calling the setX function and
                                               //passing the value 5 as argument
                                               //the role of cExpPtr in cExpPtr->setX(5)
                                               //the cExpPtr pointer is used to access the setX() method of the
                                               //cExpObject object - if you remove the pointer, you'll need
                                               //to access the method directly on the object as in
                                               // cExpObject.setX(5) instead of cExpPtr->setX(5)
  cExpPtr->print();                            //displays x = 5

  cExpObject.print();                          //displays x = 5
  cExpObject.setX(100);                        
  cExpPtr->print();                            //displays x = 100
  return 0;
}

/***********************************************
 NOTE: the bottom portion shows calling the setX & print functions directly via the DOT operator
        - the dot operator is used when direct calling (no pointer calling)
 NOTE: the top portion shows calling the setX & print functions using a pointer via the arrow operator
        - the arrow operator is used when a pointer object calls a function
***********************************************/

OVERLOADING THE ASSIGNMENT OPERATOR IMPLEMENTATION

SOURCE FILE: pointers.cpp

#include <iostream>
using namespace std;

class List
{
  int *p, n;
  public:
    List();
    void insertEnd(int);
    void print() const;
    void destroyList();
    const List& operator=(const List& otherList); // overolad the assignment operator
};

List::List(){
  n = 0;
  p = new int[5];
}

void List::insertEnd(int x){
  if(n<5)
  p[n++] = x;
}

void List::print() const{
  if(n==0)
    cout<<"Empty list\n";
  else
    for (int i = 0; i < n; i++)
      cout<<p[i] << " ";
  cout << "\n";
}

void List::destroyList(){
  delete[] p;
  p = NULL;
  n = 0;
}

const List& List::operator =(const List& otherList){
  if (this != &otherList){ // avoid self-assignment
    if (p != NULL)
      destroyList();
    n = otherList.n;
    p = new int[5];
    for (int i = 0; i < 5; i++)
      p[i] = otherList.p[i];
  }
  return *this;
}

int main()
{
  List l1, l2;
  for (int i = 0; i < 5; i++)
    l1.insertEnd(10*i);
    l2 = l1; 
    cout << "list1: ";
    l1.print();
    cout << "list2: ";
    l2.print();
    l1.destroyList(); //both l1 and l2 will be destroyed!
    cout << "list1: ";
    l1.print();
    cout << "list2: ";
    l2.print();
    
    return 0;
}

Last updated