Sunteți pe pagina 1din 13

POINTERS CSC1 38

TOPIC 8

POINTERS

Learning objectives: To learn about the pointer data type and pointer variables Explore how to declare and manipulate pointer variables Learn about the address of operator and the dereferencing operator Discovery dynamic variables Learn about pointer arithmetic Discover dynamic arrays

pnh/FSKM/UiTM Perak

Page 1

POINTERS CSC1 38
1.0 DEFINITION: it's a variable that holds the address of another variable, function or data. The address or the value refers to another memory space and the data is typically stored in this memory space. Therefore, when you declare a pointer variable, you also specify the data type of the value to be stored in the memory location pointed to by the pointer variable

Address: All memory locations, whether in RAM or ROM have an address in the range 0 to 4 billion. (Or more accurately 232-1 = 4,294,967,295. Not all addresses in this range are valid- if there isn't any RAM or ROM at the specified address range then an exception will occur if any attempt is made to read or write to an address in that range.

1.1 DECLARATION & INITIALIZATION Syntax: Datatype *identifier;

where: the * character is used to refer to a pointer. int variable // declares an int variable int * variable // declares a pointer to an int variable int * variable[5] // declares an array of 5 pointers, each to an int variable
Example 1: #include <iostream.h> #include <conio.h> int main() { // Declare and initialize a pointer. int * pPointer = 0; // Declare an integer variable and initialize it with 35698 int twoInt = 35698; // Declare an integer variable and initialize it with 77 int oneInt = 77; // Use address-of operator & to assign a memory address of // twoInt to a pointer pPointer = &twoInt; // Pointer pPointer now holds a memory address of twoInt // Print out associated memory addresses and its values cout << "pPointer's memory address:\t\t" << &pPointer << endl; cout << "Integer's oneInt memory address:\t" << pnh/FSKM/UiTM Perak &oneInt << "\tInteger value:\t" << oneInt << endl; cout << "Integer's twoInt memory address:\t" << &twoInt << "\tInteger value:\t" << twoInt << endl; cout << "pPointer is pointing to memory address:\t"

OUTPUT:

pPointer's memory address: 0x0012ff50 Integer's oneInt memory address: 0x0012ff48 Integer value: 77 Integer's twoInt memory address: 0x0012ff4c Integer value: 35698 pPointer is pointing to Page memory address: 2 0x0012ff4c Integer value: 35698

POINTERS CSC1 38

What it means:

The diagram above is a high level visual abstraction of how are variables stored within a computer memory. Pointer pPointer starts at memory address 0xbff43314 and takes 4 bytes. Pointer pPointer holds as a value a memory address of a short int twoInt ( 2 bytes ) which is 0xbff4331a. This address is stored as a binary data within a pointer's memory space allocation. Therefore, dereferencing a pointer with a memory address 0xbff4331a will indirectly access a value of twoInt which is in this case a positive integer 35698. TERMS: 1. Address of operator , & : is a unary operator that returns the address of its operand.

pnh/FSKM/UiTM Perak

Page 3

POINTERS CSC1 38
2. Dereferencing operator or indirection operator, * : used as a unary operator that refers to the object to which its operand ( i.e the pointer) points.

Further examples:

Example 2: #include <conio.h> #include <iostream.h> int main() { int a = 10; int* pointer = &a; cout<<"a holds "<<a<<endl; cout<<"a's address is "<<&a<<endl; cout<<"pointer holds "<<pointer<<endl; cout<<"pointer's address is "<<&pointer<<endl; cout<<"pointer points to "<<*pointer<<endl; getch(); return 0; OUTPUT:

a holds 10 a's address is 0x0012ff50 pointer holds 0x0012ff50 pointer's address is 0x0012ff4c pointer points to 10

Example 3: pnh/FSKM/UiTM Perak Page 4

POINTERS CSC1 38
#include <iostream> #include <conio> int main() { // Declare an integer variable and initialize it with 99 int myInt = 99; // Declare and initialize a pointer to zero or null pointer // int *pMark = NULL; int * pMark = 0; // Print out a value of myInt cout << myInt << endl; // Use address-of operator & to assign a memory address // of myInt to a pointer pMark = &myInt; // Dereference a pMark pointer with dereference // operator * to access a value of myInt cout << *pMark << endl; OUTPUT:

99 99

1.2 Accessing the Value at the Memory Address held by a Pointer As you could see in the example above that a pointer pMark truly holds a value memory address of an myInt. Process accessing a variable's value by a pointer is called indirection, since the value of variable is accessed indirectly. Similarly, Value of oneInt can be now indirectly accessed with a use of pPointer pointer. To do that we need to dereference a pointer with dereference operator * which needs to be placed before a pointer variable name as shown in the examples above.

pnh/FSKM/UiTM Perak

Page 5

POINTERS CSC1 38
1.3 Why do we need pointers? So far, you have been exposed to some theory and syntax behind C++ pointers. You learned how to assign a memory address of a variable to a pointer. Assigning an address to a pointer is useful for an explanation on how pointers work. However, in the real life you would under no circumstances do that. The correct question at this point would be: Why do we need pointers in C++ language if we can access and manipulate variables by just using their declaration name? The ability of C++ to access memory directly by pointers makes C++ language favorable over some other languages such as Visual Basic, C# or Java. Accessing variables directly by pointers rather than through their memory location results in increased efficiency and flexibility of written code. However, as it can be expected, increased efficiency takes its cost, because using any low-level tool such as a pointer means intensified difficulty in their implementation. The most common use of pointers includes:

Data management on the free store Accessing class member data and functions Passing variables by reference to functions

1.4 Manipulating Data with Pointers Same as accessing the value at the memory address held by pointer by indirection, the indirection can also be used to manipulate variable's value. Assigning a value to a dereferenced pointer will indirectly change a value of a variable the pointer is pointing to. The following example illustrates simple manipulation of data with pointers: #include <iostream> #include <conio> int main() { // Declare an integer variable and initialize it with 99 int myInt = 99; // Declare and initialize a pointer // the number 0 is the only number that can be directly assigned to a pointer variable int * pMark = 0; // null pointer // Print out a value of myInt cout << myInt << endl; // Use address-of operator & to assign memory address of myInt to a pointer pMark = &myInt; // Dereference a pMark pointer with dereference operator * and set new value *pMark = 11; // show indirectly a value of pMark and directly the value of myInt cout << "*pMark:\t" << *pMark << "\nmyInt:\t" << myInt << endl; getch(); return 0; pnh/FSKM/UiTM Perak Page 6 OUTPUT:

99 *pMark: 11 myInt: 11

POINTERS CSC1 38
1.5 Dynamic variables #include <iostream> #include <conio> int main() { int *ptr_a, *ptr_b; int num_c = 4, num_d = 7; ptr_a = &num_c; ptr_b = ptr_a; "\n"; ptr_b = &num_d; "\n"; *ptr_a = *ptr_b; "\n"; cout << num_c << " " << *&*&*&num_c << "\n"; getch(); return 0; } Note that "*" and "&" are in a certain sense complementary operations; "*&*&*&num_c" is simply "num_c". In the program above, the assignment statement ptr_a = &num_c; (in line 10) effectively gives an alternative name to the variable "num_c", which can now also be referred to as "*ptr_a". As we shall see, it is often convenient (in terms of memory management) to use dynamic variables in programs. These variables have no independent identifiers, and so can only be referred to by dereferenced pointer variables such as "*ptr_a" and "*ptr_b". In other words, you learned how to use pointers and to manipulate data only into memory spaces that were created using other variables , i.e the pointers manipulated data into existing memory spaces. /* LINE 19 */ /* LINE 15 */ after the assignment at line 15 this changes to: /* LINE 10 */ /* LINE 11 */ The output of this program is: 44 47 77 77 Diagramatically, the state of the program after the assignments at lines 10 and 11 is:

cout << *ptr_a << " " << *ptr_b <<

cout << *ptr_a << " " << *ptr_b <<

cout << *ptr_a << " " << *ptr_b << and after the assignment at line 19 it becomes:

pnh/FSKM/UiTM Perak

Page 7

POINTERS CSC1 38
How do we allocate and deallocate memory during program execution??? Use pointers!!! Variables that are created during program execution are called dynamic variables. Dynamic variables are "created" using the reserved word "new", and "destroyed" (thus freeing-up memory for other uses) using the reserved word "delete". Below is a program similar to the above program, which illustrates the use of these operations: #include <iostream> #include <conio> int main() { int *ptr_a, *ptr_b; ptr_a = new int; */ *ptr_a = 4; ptr_b = ptr_a; 11 */ cout << *ptr_a << " " << *ptr_b << "\n"; ptr_b = new int; 15 */ *ptr_b = 7; */ cout << *ptr_a << " " << *ptr_b << "\n"; delete ptr_a; ptr_a = ptr_b; 21 */ cout << *ptr_a << " " << *ptr_b << "\n"; delete ptr_a; */ getch(); return 0; } /* LINE 25 /* LINE /* LINE 16 /* LINE after the assignments at lines 15 and 16 the state is: /* LINE 10*/ /* LINE after the assignments in lines 9, 10 and 11 this changes to: The output of this program is: 44 47 77 The state of the program after the declarations in line 7 is:

/* LINE 7 */ /* LINE 9

and after the assignment at line 21 it becomes:

Finally, after the "delete" statement in lines 25, the program state returns to:

pnh/FSKM/UiTM Perak

In the first and last diagrams above, the pointers "ptr_a" and "ptr_b" are said to be dangling. Note that "ptr_b" is dangling at the end of the program even though it has not been explicitly included in a "delete" statement. 8 Page

POINTERS CSC1 38

If "ptr" is a dangling pointer, use of the corresponding dereferenced expression "*ptr" produces unpredictable (and sometimes disastrous) results. Unfortunately, C++ does not provide any inbuilt mechanisms to check for dangling pointers. However, safeguards can be added to a program using the special symbolic memory address "NULL". Any pointer of any data type can be set to "NULL". For example, if we planned to extend the program above and wanted to safeguard against inappropriate use of the dereferenced pointer identifiers "*ptr_a" and "*ptr_b", we could add code as follows: #include <iostream> ... ... delete ptr_a; ptr_a = 0; ptr_b = 0; ... ... if (ptr_a != 0) { *ptr_a = ... ... ... 1.6 Operations on pointer variables

The comparison is valid only between pointers that point to the same array. Under this circumstances, the following relational operators work for pointers operation. ==, !=, >, <, >=, and <= A lower array element that is those having a smaller subscript, always have a lower address than the higher array elements. Thus if ptr1 and ptr2 point to elements of the same array, the following comparison: ptr1 < ptr2 is TRUE If ptr1 points to an earlier member of the array than ptr2 does. Many arithmetic operations that can be performed with regular variables, such as multiplication and division, do not work with pointers and will generate errors in C/C+ +. The following table is a summary of pointer operations.

pnh/FSKM/UiTM Perak

Page 9

POINTERS CSC1 38

1.7 Dynamic Arrays The arrays discussed earlier are called static arrays because their size was fixed at compile time. (Hassle: maybe too big or too small,etc) . 1.7.1 The problems with fixed size arrays Declaring an array with a fixed size like int a[100000]; has two typical problems:

Exceeding maximum. Choosing a real maximum is often impossible because the programmer has no control over the size of the data sets the user is interested in. Erroneous assumptions that a maximum will never be exceeded are the source of many programming bugs. Declaring very large arrays can be extremely wasteful of memory, and if there are many such arrays, may prevent the program from running in some systems. No expansion. Using a small size may be more efficient for the typical data set, but prevents the program from running with larger data sets. If array limits are not checked, large data sets will run over the end of an array with disastrous consequences. Fixed size arrays can not expand as needed.

Alternatively, we can have arrays of which the size can be determined during execution. Hence an array created during the execution of a program is called as dynamic array. These problems can be avoided by dynamically allocating an array of the right size, or reallocating an array when it needs to expand. Both of these are done by declaring an array as a pointer and using the new operator to allocate memory, and delete to free memory that is no longer needed.
Operation 1. Assignment (=) 2. Indirection (*) Description You can assign a value to a pointer. The value should be an address with the address-of-operator (&) or from a pointer constant (array name) The indirection operator (*) gives the value stored in the pointed to location. You can use the address-of operator to find the address of a pointer, so you can use 3. Address of (&) pointers to pointers. 4. Incrementing You can add an integer to a pointer to point to a different memory location. 5. Differencing You can subtract an integer from a pointer to point to a different memory location. 6. Comparison Valid only with 2 pointers that point to the same array. Table 1: Pointer operations

1.7.2 Declare array as a pointer, allocate with new To create a variable that will point to a dynamically allocated array, declare it as a pointer to the element type. For example, pnh/FSKM/UiTM Perak Page 10

POINTERS CSC1 38
int* a = NULL; // pointer to an int, intiallly to nothing. A dynamically allocated array is declared as a pointer, and must not use the fixed array size declaration. The above declaration creates a pointer, but doesn't yet allocate any memory to it. Allocate an array with code>new When the desired size of an array is known, allocate memory for it with the new operator and save the address of that memory in the pointer. Remember: Pointers may be subscripted just as arrays are. The example below reads in a number and allocates that size array.

#include <iostream.h> #include <conio.h> int main() { int* a = NULL; // Pointer to int, initialize to nothing. int n; cout<<"enter the size of array "<<endl;// Size needed for array cin >> n; // Read in the size a = new int[n]; // Allocate n ints and save ptr in a. for (int i=0; i<n; i++) { a[i] = 0; // Initialize all elements to zero. } // Use a as a normal array cout<<"contents of the array"<<endl; for (int i=0; i<n; i++) { cout<<a[i]<<" "; } delete [] a; // When done, free memory pointed to by a. a = NULL; // Clear a to prevent using invalid memory reference. getch(); return 0;}

OUTPUT:

enter the size of array 5 contents of the array 0 0 0 0 0

Freeing memory with delete When you are finished with dynamically allocated memory, free it with the delete operator. After memory is freed, it can be reused by later new requests. Memory that your program didn't free will be freed when the program terminates. Never free memory that wasn't dynamically allocated - the results are unpredictable. pnh/FSKM/UiTM Perak Page 11

POINTERS CSC1 38
delete [] a; // Free memory allocated for the a array. a = NULL; // Be sure the deallocated memory isn't used. Use [] when deleting arrays You must specify "[]" when deleting an array, but not for a single value. It isn't possible to delete only part of an array.

#include <iostream.h> #include <iomanip.h> #include <conio.h> void fill(int **p, int rowSize, int columnSize); void print(int **p, int rowSize, int columnSize); int main() { int **board; int rows; 2D DYNAMIC ARRAYS int columns; cout<<"Line 4: Enter the number of rows and columns"<<endl; cin>>rows>>columns; cout<<endl; //create the rows of board board = new int* [rows]; //create the columns of board for (int row=0;row<rows;row++) board[row] = new int[columns]; //insert elements into board fill(board, rows, columns); cout<<"Line 11: Board:"<<endl; //output the elements of board print(board, rows, columns); getch(); return 0; } void fill(int **p, int rowSize, int columnSize) { for(int row=0;row<rowSize;row++) { cout<<"Enter "<<columnSize<<" number(s) for row "<< "number = "<<row<<": "; for (int col=0; col < columnSize; col++) cin>>p[row][col]; cout<<endl; } } void print(int **p, int rowSize, int columnSize) { for(int row=0;row<rowSize;row++) { for (int col=0; col < columnSize; col++) cout<<setw(5)<<p[row][col]; cout<<endl; pnh/FSKM/UiTM Perak Page 12 } }

POINTERS CSC1 38

Line 4: Enter the number of rows and columns 34 Enter 4 number(s) for row number = 0: 1 2 3 4 Enter 4 number(s) for row number = 1: 5 6 7 8 Enter 4 number(s) for row number = 2: 9 10 11 12 Line 11: Board: 1 2 3 4 5 6 7 8 9 10 11 12

pnh/FSKM/UiTM Perak

Page 13

S-ar putea să vă placă și