Académique Documents
Professionnel Documents
Culture Documents
Pointer is a variable that holds a memory address of another variable. It supports dynamic allocation of memory It can improve the efficiency of certain algorithms.
Memory Addresses
During program execution, each object (such as a variable or an array) is located somewhere in an area of memory. The location of an object in the memory is called its address. In C++ there is an address (or referencing ) operator, &, which allows you to obtain an object's address. The value returned by this address operator indicates the location of an object in memory. Memory locations are determined by the operating system and it is possible that objects' addresses may be different during repeated runs of a program. C++ offers two mechanisms for dealing with addresses: references (&) and pointers(*).
Heap :
Static Memory Allocation : The amount of memory to be allocated is known in advance and it allocated during compilation, it is referred to as Static Memory Allocation. Eg. int a; // This will allocate 2 bytes for a during compilation. Dynamic Memory Allocation(DMA) : The amount of memory to be allocated is not known beforehand rather it is required to allocated as and when required during runtime, it is referred to as dynamic memory allocation. C++ offers two operator for DMA new and delete. Free Store : It is a pool of unallocated heap memory given to a program that is used by the program for dynamic memory allocation during execution.
Two special unary operator * and & are used with pointers. The & is a unary operator that returns the memory address of its operand. Example:. int x = 10; int *p; p = &x; p gets the address of x in memory. *p = 20; *p is the value at the address p. 1
Pointer arithmetic:
Two arithmetic operations, addition and subtraction, may be performed on pointers. When you add 1 to a pointer, you are actually adding the size of whatever the pointer is pointing at. That is, each time a pointer is incremented by 1, it points to the memory location of the next element of its base type. Eg. int *p; p++; If current address of p is 1000, then p++ statement will increase p to 1002, not 1001. If *c is char pointer and *p is integer pointer then Char pointer Address Int pointer C 100 p c+1 101 c+2 102 p+1 c+3 103 c+4 104 p+2 c+5 105 c+6 106 p+3 c+7 107
Adding 1 to a pointer actually adds the size of pointers base type. Base address : A pointer holds the address of the very first byte of the memory location where it is pointing to. The address of the first byte is known as BASE ADDRESS.
Creating Dynamic Array(Using new with arrays) : Syntax : pointer-variable = new data-type [size]; int x = 10; Eg. int * array = new int[10]; Now array[0] will refer to the first element of array, array[1] will refer to the second element. No initializes can be specified for arrays. All array sizes must be supplied when new is used for array creation. 2
int* nums1 = new int[10]; // ok int* nums2 = new int[20]; // ok Initializes an array of 20 integers on the heap.
C++ treats the name of an array as if it were a pointer i.e. memory address of some element. C++ interprets an array name as the address of its first element. 3
That is, if marks is an int array to hold 10 integers then marks stores the address of marks[0], the first element of the array i.e., the array name marks is a pointer to an integer which is the first element of array marks[10]. void main() { int *m; int marks[10]; cout << \n Enter marks :; for (int i = 0; i < 10; i++) cin >> marks[i]; m = marks; cout << \n m points to << *m; cout << \n Marks points to << *marks; } The name of an array is actually a pointer pointing to the first element of the array. Since the name of an array is a pointer to its first element, the array+1 gives the address of the second element, array+2 gives the address of the third element, and so on. Thus, to print the fourth element of array marks, we can give either of the following : Cout << marks [3]; OR cout << * (marks+3);
Here is an example of an array as we learned when studying them: #include <iostream> void main() { int a[] = { 31, 28, 31, 30, 31 }; cout << "List of as"; cout << "\na 1: " << a[0]; cout << "\na 2: " << a[1]; cout << "\na 3: " << a[2]; cout << "\na 4: " << a[3]; cout << "\na 5: " << a[4]; } In this case, the a variable is an array of 5 integer values. Because a variable declared as array is first of all a variable, using its name, let us find its address. Consider the following program: #include <iostream> void main() { int a[] = { 31, 28, 31, 30, 31}; cout << "\n a : cout << "\n&a : cout << "\n&a[0] : } This would produce: a : &a : &a[0] : 1245020 1245020 1245020 " << a; " << &a; " << &a[0] << endl;
This demonstrates that a, &a, and &a[0] have the same value. As we learned with pointers, the use of the ampersand "&" allows us to get the address of a variable. Therefore, &a gives us the address of the array variable. Furthermore, since &a and &a[0] have the same value, and seeing that all three (a, &a, and &a[0]) have the same value, this demonstrates that the name of the variable in fact carries, or holds, or represents, the address of the first value of the array. In fact, consider the following program: #include <iostream> Void main() { int a[] = { 31, 28, 31, 30, 31}; cout << "An integer occupies " << sizeof(int) << " bytes\n"; cout << "\n a: " << a; cout << "\n &a[0]: " << &a[0] << endl; cout << "\n a+1: " << a+1; cout << "\n&a:[1] " << &a[1] << endl; cout << "\n a+2: " << a+2;
cout << "\n&a:[2] " << &a[2] << endl; } This would produce: An integer occupies 2 bytes a: 1245020
a[0]: 1245020 a+1: 1245024 &a:[1] 1245024 a+2: 1245028 a:[2] 1245028 Notice that, by adding as to the name of the variable, we are able to get the address of any member of the array.
#include <iostream> void main() { int a[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int *p = a; cout << "Addresses"; cout << "\n a : " << a; cout << "\np : " << p; cout << "\n\nValues"; cout << "\n a [0] : " << a[0]; cout << "\np[0] : " << p[0]; cout << "\n a [1] : " << a[1]; cout << "\np[1] : " << p[1]; } This would produce: Addresses a : p : Values a [0] : p[0] : a [1] : p[1] : 1245020 1245020 31 31 28 28
At this time, we know how to get the address of the first member of the array, with either a or p. To get the address of the second member of the array, we increment that address value, as in a+1. Since A is an address and not a value, adding 1 to it adds the size of its type, in this case 4 bytes, in order to get to the next address. In the same way, using a pointer that has been initialized with an array, to get the address of the next member of the array, simply increment its name. Here is an example: #include <iostream> void main() { int a[] = { 31, 28, 31, 30, 31}; int *p = a; cout << "Addresses"; cout << "\n a : " << a; cout << "\np : " << p; cout << "\n a +1 : " << a+1; cout << "\np+1 : " << p+1; cout << "\n a +2 : " << a+2; cout << "\np+2 : " << p+2; } This would produce: Addresses a : p : a +1 : p+1 : a +2 : p+2 : 1245020 1245020 1245024 1245024 1245028 1245028
Now we know that by writing p or p+n, we get the address of the member that "lives" at p or p+n. We already saw that, by writing *p, we can get the value of the first member of the array. When writing *p, we are in fact asking the compiler to retrieve the value that p points to. If we want to get the value of the next member of the array, we must first give its address, which is done by adding the index of the member of the array to p. Once we have communicated the address, we use the asterisk operator to retrieve the actual value of the member of the array. Because the asterisk operator has a higher precedence than the addition operator, to get the address before the value, you must use parentheses to delimit the operation: #include <iostream> void main() { int a[] = { 31, 28, 31, 30, 31}; int *p = a; cout << "Values - Using the Array"; cout << "\n a[0]: " << a[0]; cout << "\n a[1]: " << a[1]; cout << "\n a[2]: " << a[2]; cout << "\n a[3]: " << a[3]; cout << "\n a[4]: " << a[4]; cout << "\n\nValues - Using the Pointer - No Parentheses";
cout cout cout cout cout cout cout cout cout cout cout
<< << << << << << << << << << <<
"\n*p: " << *p; "\n*p+1: " << *p+1; "\n*p+2: " << *p+2; "\n*p+3: " << *p+3; "\n*p+4: " << *p+4; "\n\nValues - Using the Pointer - With Parentheses"; "\n*p: " << *p; "\n*(p+1): " << *(p+1); "\n*(p+2): " << *(p+2); "\n*(p+3): " << *(p+3); "\n*(p+4): " << *(p+4);
} This would produce: Values - Using the Array a[0]: 31 a[1]: 28 a[2]: 31 a[3]: 30 a[4]: 31 Values - Using the Pointer - No Parentheses *p: 31 *p+1: 32 *p+2: 33 *p+3: 34 *p+4: 35 Values - Using the Pointer - with Parentheses *p: 31 *(p+1): 28 *(p+2): 31 *(p+3): 30 *(p+4): 31 Press any key to continue... Therefore, as long as you increment the address of the variable, you can use a for loop to navigate the array to get the value of each member of the array: #include <iostream.h> void main() { int a[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int *p = a; int aOfMembers = sizeof(A) / sizeof(int); cout << "List of As"; for(int i = 0; i < aOfMembers; i++) cout << "\nA " << i + 1 << ": " << *(p+i); }
Array of Pointers :
To declare an array holding 10 int pointers int * ip[10]; That would be allocated for 10 pointers that can point to integers. Now each of the pointers, the elements of pointer array, may be initialized. To assign the address of an integer variable phy to the forth element of the pointer array, we have to write ip[3] = & phy; Now with *ip[3], we can find the value of phy. int *ip[5]; Index address 0 1000 1 1002 2 1004 3 1006 4 1008
a 12 1050
b 23 1065
c 34 2001
d 45 2450
e 56 2725
ip[0] = &a;
ip[4] = &e;
ip is now a pointer pointing to its first element of ip. Thus ip is equal to address of ip[0], i.e. 1000 *ip (the value of ip[0]) = 1050 * (* ip) = the value of *ip = 12 * * (ip+3) = * * (1006) = * (2450) = 45
Allocating Memory
Here are examples of dynamic arrays: double *Distance = new double[12]; unsigned int *pRanges = new unsigned int[120]; float *Prices = new float[44]; After dynamically creating an array, the compiler allocates the necessary memory space for all the members of the array, based on the data type and accommodating each. Just like any variable, the memory allocated for each member of the array contains garbage. It is your responsibility to fill it up for appropriate values. This can be taken care of by assigning a value to each member of the array. Each member of the array can be accessed by using its index on the name of the array. You have two options. You can apply the index of an array member on the name of the pointer. Here is an example: int *p p[0] = p[1] = p[2] = p[3] = = new int[12]; 31; 29; 31; 30;
You can also access the address of the desired member, then assign it a value. Here is an example: int *p *(p+4) *(p+5) *(p+6) *(p+7) = = = = = new int[12]; 31; 30; 31; 31;
In the same way, you can use either method to retrieve the value of a member of the array: #include <iostream> void main() { int *p = new int[12]; p[0] = 31; p[1] = 29; p[2] = 31; p[3] = 30; *(p+4) = 31; *(p+5) = 30; *(p+6) = 31; *(p+7) = 31; *(p+8) = 30; *(p+9) = 31; p[10] = 30; p[11] = 31; cout << "List of as"; cout << "\n 1: " << *p; cout << "\n 2: " << *(p+1); cout << "\n 3: " << *(p+2); cout << "\n 4: " << *(p+3);
This would produce: List of as 1: 31 2: 29 3: 31 4: 30 5: 31 6: 30 7: 31 8: 31 9: 30 10: 31 11: 30 12: 31 Press any key to continue...
Disposing of Memory
After using a pointer that was pointing to an array, when you do not need it anymore, you should delete it from memory and reclaim the space it was using. This is done using the delete operator. The syntax used is: delete [] pointer VariableName; The required delete operator is used to let the compiler know that you want to delete a pointer variable that was pointing to an array. Here is an example: #include <iostream> void main() { int a[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int *p = a; int aOfMembers = sizeof(a) / sizeof(int); cout << "List of as"; for(int i = 0; i < aOfMembers; i++) cout << "\na " << i + 1 << ": " << *(p+i); delete [] p; } This operation is usually performed on a dynamically created array, that is, on a pointer that was used to create an array. The formula is the same: after using the dynamic array, delete the pointer using the delete operator. To avoid memory leak, you can also assign NULL to the name of the array. Here is an example #include <iostream> void main() { int *p = new int[12]; p[0] = 31; p[1] = 28; p[2] = 31; p[3] = 30; *(p+4) = 31; *(p+5) = 30; *(p+6) = 31; *(p+7) = 31; *(p+8) = 30; *(p+9) = 31; p[10] = 30; p[11] = 31; cout << "List of as"; for(int i = 0; i < Size; i++) cout << "\na " << i + 1 << ":
delete [] p; p = NULL; }
Pointers to pointers
C++ allows the use of pointers that point to pointers, that these, in its turn, point to data (or even to other pointers). In order to do that, we only need to add an asterisk (*) for each level of reference in their declarations:
The value of each variable is written inside each cell; under the cells are their respective addresses in memory. The new thing in this example is variable c, which can be used in three different levels of indirection, each one of them would correspond to a different value:
c has type char** and a value of 8092 *c has type char* and a value of 7230 **c has type char and a value of 'z'
void pointers
The void type of pointer is a special type of pointer. In C++, void represents the absence of type, so void pointers are pointers that point to a value that has no type. This allows void pointers to point to any data type, from an integer value or a float to a string of characters. But in exchange they have a great limitation: the data pointed by them cannot be directly dereferenced (which is logical, since we have no type to dereference to), and for that reason we will always have to cast the address in the void pointer to some other pointer type that points to a concrete data type before dereferencing it.
Null pointer
A null pointer is a regular pointer of any pointer type which has a special value that indicates that it is not pointing to any valid reference or memory address. This value is the result of type-casting the integer value zero to any pointer type.
int * p; p = null;
Do not confuse null pointers with void pointers. A null pointer is a value that any pointer may take to represent that it is pointing to "nowhere", while a void pointer is a special type of pointer that can point to somewhere without a specific type. One refers to the value stored in the pointer itself and the other to the type of data it points to.
Remember, functions can return only ONE value. Until now it was impossible to change two different non-array values within a function and return both values to main( ).
By Reference:
We can now swap two variables, by using the addresses of the variables from within the function. When the function reverses the values, main( ) will also recognize the changes. #include <iostream.h> void swap(int &num1, int &num2); void main(void) { int a=10,bj=20; cout<< "Before the swap, a is " << a << " and b is " << b << "."<< endl; swap(a,b); cout<< "After the swap, a is " << a << " and b is " << b << "."<< endl; } //-------------- Function to reverse two values ---------------------------------------void swap(int &num1, int &num2) // receiving addresses not values { int temp; // temporary holding variable temp = num1; num1 = num2; num2 = temp; // main( )'s variables, not copies of them, have been changed }
By Pointers:
Let's try this same swapping process using pointers instead of addresses. #include <iostream.h> void p_swap(int *pNum1, int *pNum2); void main(void) { int a=10, b=20; cout<< "Before the swap, a is " << a << " and b is " << b << "."<< endl; p_swap(&a, &b); //ps the addresses cout<< "After the swap, a is " << a << " and b is " << b << "."<< endl; } //-------------- Function to reverse two values ----------------------------------------void p_swap(int *pNum1, int *pNum2) // receiving addresses not values { int temp; // temporary holding variable temp = *pNum1; // swap the values stored at the addresses *pNum1 = *pNum2; *pNum2 = temp; // main( )'s variables, not copies of them, have been changed } Invoking Function by Passing the References : When parameters are passed to the functions by reference, then the formal parameters become references (or aliases) to the actual parameters to the calling function. That means the called function does not create its own copy of original values, rather, it refers to the original values by different names i.e. their references. For example the program of swapping two variables with reference method : #include<iostream.h> void main() { void swap(int &, int &); int a = 5, b = 6; cout << \n Value of a : << a << and b : << b; 11
swap(a, b); cout << \n After swapping value of a : << a << and b : << b; } void swap(int &m, int &n) { int temp; temp = m; m = n; n = temp; } output : Value of a : 5 and b : 6 After swapping value of a : 6 and b : 5 Invoking Function by Passing the Pointers: When the pointers are passed to the function, the addresses of actual arguments in the calling function are copied into formal arguments of the called function. That means using the formal arguments (the addresses of original values) in the called function, we can make changing the actual arguments of the calling function. For example the program of swapping two variables with Pointers: #include<iostream.h> void main() { void swap(int *m, int *n); int a = 5, b = 6; cout << \n Value of a : << a << and b : << b; swap(&a, &b); cout << \n After swapping value of a : << a << and b : << b; } void swap(int *m, int *n) { int temp; temp = *m; *m = *n; *n = temp; } iutput : Value of a : 5 and b : 6 After swapping value of a : 6 and b : 5 Function returning Pointers : The way a function can returns an int, an float, it also returns a pointer. The general form of prototype of a function returning a pointer would be Type * function-name (argument list); #include <iostream.h> int* min(int &, int &); void main() { int a, b, *c; cout << \nEnter a :; cin >> a; cout << \nEnter b :; cint >> b; c = min(a, b); cout << \n The minimum no is : << *c; } int* min(int &x, int &y) { if (x < y ) return (&x); else return (&y); } 12
Pointers and Structures : C++ allows pointers to structures just as it allows to int or char or float or any other data type. Pointers to structures are known as structure pointers. Let us consider the following Structure: struct student{ int roll; char nm[20]; }; student s1; student *ptr; Object s1 can access the data members through dot operator(.) as given below: //To read the values of data members cin>>s1.roll; gets(s1.nm) //To display the values of data members cout<<s1.roll; puts(s1.nm); Pointer Variable can access the data members through arrow operator(.) (minus sign followed by greater than sign)as given below: ptr=&s1; //To read the values of data members cin>>ptr->roll; gets(ptr->.nm) //To display the values of data members cout<<ptr->roll; puts(ptr->nm);
Dynamic structures : The new operator can be used to create dynamic structures also i.e. the structures for which the memory is dynamically allocated. struct-pointer = new struct-type; Eg: student *stu; stu = new Student; A dynamic structure can be released using the deallocation operator delete as shown below : delete stu; Objects as Function arguments : Objects are passed to functions in the same way as any other type of variable is passed. When it is said that objects are passed through the call-by-value, it means that the called function creates a copy of the passed object. A called function receiving an object as a parameter creates the copy of the object without invoking the constructor. However, when the function terminates, it destroys this copy of the object by invoking its destructor function. If you want the called function to work with the original object so that there is no need to create and destroy the copy of it, you may pass the reference of the object. Then the called function refers to the original object using its reference or alias. Class Objects and pointers : Eg : #include<iostream.h> class Point { private : int x, y public : Point() 13
{ x = y = 0; } void getPoint(int x1, int y1) { x = x1; y = y1; } void putPoint() { cout << \n Point : ( << x << , << y << ); } }; void main() { Point p1, *p2; cout << \n Set point at 3, 5 with object; p1.getPoint(3,5); cout << \n The point is :; p1.putPoint(); p2 = &p1; cout << \n Print point using object pointer :; p2->putPoint(); cout << \n Set point at 6,7 with object pointer; p2->getPoint(6,7); cout<< \n The point is :; p2->putPoint(); cout << \n Print point using object :; p1.getPoint(); } If you make an object pointer point to the first object in an array of objects, incrementing the pointer would make it point to the next object in sequence. student stud[5], *sp; --sp = stud; // sp points to the first element (stud[0])of stud sp++; sp + = 2; sp--; // sp points to the second element (stud[1]) of stud // sp points to the fourth element (stud[3]) of stud // sp points to the third element (stud[2]) of stud
You can even make a pointer point to a data member of an object. Two points should be considered : 1. A Pointer can point to only public members of a class. 2. The data type of the pointer must be the same as that of the data member it points to.
this Pointer :
In class, the member functions are created and placed in the memory space only once. That is only one copy of functions is used by all objects of the class. Therefore if only one instance of a member function exists, how does it come to know which objects data member is to be manipulated ? Member Function1 Member Function2 Member Function3
14
For the above figure, if Member Function2 is capable of changing the value of Data Member3 and we want to change the value of Data Member3 of Object3. How would the Member Function2 come to know which Objects Data Member3 is to be changed? To overcome this problem this pointer is used. When a member function is called, it is automatically passed an implicit argument that is a pointer to the object that invoked the function. This pointer is called This. That is if ojbect3 is invoking member function2, then an implicit argument is passed to member function2 that points to object3 i.e. this pointer now points to object3. This Pointer The This pointer represents an object that invokes a member function. It stores the address of the object that is invoking a member function and it (this pointer ) is an implicit argument to the member function. In short the this pointer is an object pointer which points to the currently calling object. Program for this pointer: #include<iostream.h> #include<cstring.h> Class person { char name[20]; float age; public: person(char *s, float a) { Strcpy(name, s); age=a; } person& greater(person & x) { If (x.age >= age) return x; else return *this; } void display( ) { cout<<Name :<<name<<\n; cout<<Age:<<age<<\n; } }; void main() { person p1(john,37.50), p2(ahmed,29.0), p3(hebber,40.25); person p= p1.greater (p3); //p3.greater(p1) cout<<Elder person is :\n; p.display (); p=p1.greater(p2); //p2.greater(p1) cout<<Elder person is:\n; p.display(); } Output: Elder person is: Name: hebber Age: 40.25 Elder person is: Name: john 15
Age: 37.5
Q1 Distinguish between int *ptr=new int(5); int *ptr=new int[5]; Q2 Differentiate between the following expressions: this->data and (*this).data Self referential structures
A structure containing an element that refers to the structure(containing it) itself, is called Self referential structures. Example : struct employee { int empno; char name[26]; float basic; float experience; employee * next; };
16