C++ Pointer | Introduction to programming

mahidazad00 7 views 20 slides May 15, 2025
Slide 1
Slide 1 of 20
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20

About This Presentation

TL09.1_IPL_Pointer 1 (1).pptx


Slide Content

Pointers Course Code: CSC1102 &1103 Dept. of Computer Science Faculty of Science and Technology Course Title: Introduction to Programming Lecturer No: 9.1 Week No: 9 Semester: Spring 2024-2025 Course Instructor: Mashiour Rahman, Associate Professor, [email protected]

Outline Pointers Pointers and Addresses Pointer Types – NULL , void , const Pointers and Arrays Pointer Arithmetic Dynamic Memory Allocation – new and delete

int x; An Integer value held within the location &x denoted by x A location of size int denoted by &x Main Memory 4 bytes ( int x ) x &x int *z; An Address value denoted by z holding a location of an int value A location of size 4 bytes ( ? ) denoted by &z Main Memory 4 bytes ( ? ) for storing memory address z &z &x The operator * here is known as Indirection/Dereference operator. ( ? ) The size of a pointer in C depends on the architecture (bit system) of the machine, not the data type it points to. On a 32-bit and a 64-bit system, all pointers typically occupy 4 and 8 bytes respectively. The Integer Value at location z denoted by *z 4 bytes ( int x ) x *z==x int x; int *z=&x; int *z, x; z = &x; or

Declaring a Pointer variable int count = 10; int * p; p = & count; & count gives the location/memory address of the variable count . Pointer variable p stores the location/memory address of the integer variable count after the execution of p = & count; We say that p "points to" count . int * p; // p points to a location that contains an integer char * q; // q points to a location that contains a character float * r; // r points to a location that contains a float Data_Type * Pointer_Variable_name Data type of the element that is stored and/or pointed to by the address value of this variable Indirection/Dereference operator Variable name as per the identifier rule.

Example: pointers // Program to illustrate pointers # include < iostream > Using namespace std ; int main ( void ){ int x = 10; cout << "x = " << x << endl ; cout << "&x = " << & x << endl ; int * z; cout << "&z = " << & z << endl ; z = & x; cout << "z = " << z << endl ; cout << "*z = " << * z << endl ; * z = 4; cout << "*z = " << * z << endl ; cout << "x = " << x << endl ; x = 6; cout << "x = " << x << endl ; cout << "*z = " << * z << endl ; return ; } OUTPUT: x = 10 &x = 0x61febc &z = 0x61feb8 z = 0x61febc *z = 10 *z = 4 x = 4 x = 6 *z = 6 Main Memory z &z= 0x61feb8 &x= 0x61febc 4 bytes ( int x ) x= 10 4 bytes ( location ) z= 0x61febc *z = x= 10 *z = x= 4 *z = x= 6

Setting pointer variables int * p; * p = 4; Severe runtime error !!! the value 4 is stored in the location to which p points. But p , being uninitialized, has a random value, so we cannot know where the 4 will be stored ! int * p; int x; p = & x; * p = 4; int * p; int * p1; int x; p1 = & x; p = p1; * p = 4; The value of a pointer in C is meaningless until it is set pointing to something ! How to set pointer values: Using the address operator Using directly assignments between pointer variables

Pointers: Types There are several special types of pointers that used or referred to in different contexts. NULL Pointer: The NULL Pointers do not point to any memory location. It represents the absence of any address. A pointer variable of any type can be assigned the NULL ( keyword ) value. This allows us to check whether the pointer is pointing to any valid memory location. Example : int * ptr = NULL , a; if ( ptr == NULL ) ptr = & a; //if(! ptr ) ptr = &a; Generic ( void ) Pointer: The generic pointers are of type void . They do not have any associated data type. They can point to any data type. May be used with explicit type cast to any type . Example : void * ptr ; int a; ptr = & a;

Pointers: Types Constant Variables: The constant variable must be initialized at the time of the declaration . The value of a constant variable cannot be re-assigned/changed anywhere in the program. Examples : // const variables char a; const char b = 'M'; // value fixed b = 'X'; // !!! INVALID !!! // pointers char c = 'M', d = 'R'; char * cP1 = & c; * cP1 = 'X'; cP1 = & d; * cP1 = 'X'; // const pointers – 3 ways char c = 'M', d = 'R'; // 1. location fixed, value can change char * const cP2 = & c; * cP2 = 'X'; //valid cP2 = &d; // !!!invalid!!! // 2. value fixed, location can change const char * cP2 = & c; cP2 = & d; //valid *cP2 = 'X'; // !!!invalid!!! // 3. both value & location fixed const char * const cP3 = & c; cP3 = &d; // !!!invalid! *cP3 = 'X'; // !!!invalid!!!

Main Memory 4 bytes ( int ) a int a[3]; One location denoted by a Three value denoted by a[0], a[1], a[2] Here, a represents the starting location of array. a[0] , a[1] , a[2] are integer variables. & a[0] , & a[1] , & a[2] are their respective locations. We can also denote a = & a[0] . In int a[3]; the array name a is a constant ( const ) pointer. A constant pointer is a pointer whose address value cannot be changed. A pointer variable int * p can be assigned with the array name a which will assign the starting location of the array to p . int a[3] = {1, 2, 3}; int * p = a; // int *p = &a[0]; p &p &a[0 ] &a[2] &a[1] a[0] a[1] a[2] Pointers and Arrays

Main Memory 4 bytes ( int ) a p &p &a[0 ] &a[2] &a[1] a[0] a[1] a[2] In int a[3]; the array name a is a constant ( const ) pointer. A constant pointer is a pointer whose address value cannot be changed. A pointer variable int * p can be assigned with the array name a which will assign the starting location of the array to p . int a[3] = {1, 2, 3}; int * p = a; // int *p = &a[0]; For any data_type * p; declaration, p+i equivalent to p+( i * sizeof ( data_type )) . For int * p; declaration, p+i equivalent to p+( i *4) . So, if p points to any element of an array, p+i points to the next i th element from p . If p points to start of array a , then by definition p points to the first element, a[0] , p+1 points to the next element, a[1] . So, p+i points to the next i th element, a[ i ] . So, if * p is any element of an array, * ( p+i ) is the next i th element from p . If * p is the start element of array a , then by definition *p is the element, a[0] , * (p+1) is the next element, a[1] . So, * ( p+i ) is the next i th element, a[ i ] . a[0]==*p a[1]==*(p+1) a[2]==*(p+2) &a[0 ]== p &a[2]==p+2 &a[1]==p+1 Pointers and Arrays – Arithmetic

For any data_type * p; declaration, p + i equivalent to p+( i * sizeof ( data_type )) . For int * p; declaration, p + i equivalent to p + ( i * 4) . Increment/decrement ( ++ or -- ) pointer p ++ or p --  pointer Add/subtract ( + or += , - or -= ) an integer to/from a pointer p ± integer  p ± integer * sizeof ( type )  pointer Pointers may be subtracted from each other p1 - p2  integer [= # of bytes] p1 - p2  integer / sizeof ( type )  integer [= # of elements] Pointer arithmetic generally performed on pointer to array Pointers Arithmetic Main Memory 4 bytes ( int ) a P1=3000 &p1 &a[0]=3000 &a[2]=3008 &a[1]=3004 a[0]==*p a[1]==*(p+1) a[2]==*(p+2) int a[3], * p1, * p2, n; p1 = a; // p1 = 3000 p1 += 2; //p1 + (2* sizeof (int))= 3000+(2*4)= 3008 p2 = a; // p2 = 3000 n = p1 – p2; // n = 2 // 3008 – 3000 = 8/ sizeof (int) = 8/4 = 2 /* from a[0] up to a[2] there are 2 integer elements, a[0] and a[1] */ P2 &p2 P1=3008 P2=3000 n n=2

int main( void ){ float M[5] = {22.5,34.8,46.8,59.1,68.3}, * p; int i ; for ( i =0; i <3; i ++) cout << " M[ " << i << " ] @ " << & M[ i ] << ": " << M[ i ] << endl ; for ( i =0, p=M; i <3; i ++, p++){ ( * p)++; //increases the value at location p cout << "\ n M [ " << i << " ] @ " << p << ": " << * p ; } p = M; cout << "\ nValue of M[0] :\n"; cout << " M[0] \t:\t" << M[0] << endl ; cout << " *M \t:\t" << * M << endl ; cout << " p[0] \t:\t" << p[0] << endl ; cout << " *p \t:\t" << * p << endl ; cout << "\ nValue of M[3] :\n"; cout << " M[3] \t:\t" << M[3] << endl ; cout << " *(M+3) \t:\t" << * (M+3) << endl ; cout << " p[3] \t:\t" << p[3] << endl ; cout << " *(p+3) \t:\t" << * (p+3) << endl ; return 0; } OUTPUT: M[0] @0x61fe9c : 22.5 M[1] @0x61fea0 : 34.8 M[2] @0x61fea4 : 46.8 M[0] @0x61fe9c : 23.5 M[1] @0x61fea0 : 35.8 M[2] @0x61fea4 : 47.8 Value of M[0] : M[0] : 23.5 *M : 23.5 p[0] : 23.5 *p : 23.5 Value of M[3] : M[3] : 59.1 *(M+3) : 59.1 p[3] : 59.1 *(p+3) : 59.1 Pointers and Arrays Not possible with M as it is constant pointer

suit[0] suit[1] suit[2] suit[3] Arrays can contain pointers Commonly used to store array of strings – char * suit [ 4 ] = { "Hearts", "Diamonds", "Clubs", "Spades" } ; 5000 – 9000 in green fonts are locations. Each element of suit points to a char * (a string) at any other independent location. Array suit does not store strings, only points to strings. Array suit has fixed size, but each string can be of any sizes. Following code will print all the strings – for ( int i=0; i< 4 ; i++) cout << suit[i] << endl ; Array of Pointers 'H' 'e' 'a' 'r' 't' 's' '\0' 'D' ' i ' 'a' 'm' 'o' 'n' 'd' 's' '\0' 'C' 'l' 'u' 'b' 's' '\0' 'S' 'p' 'a' 'd' 'e' 's' '\0' suit [ ]= 6000 suit [ 1 ] = 7000 suit [ 2 ] = 8000 suit [ 3 ] = 9000 OUTPUT: Hearts Diamonds Clubs Spades suit = 5000 5004 5008 5012

n1 = 6000 n2 = 7000 n3 = 8000 n4 = 9000 For other data types (here int as example) – int * num [ 4 ] , n1 [ 7 ] = { 1,2,3,4,5,6,7 } , n2 [ 9 ] = { 1,2,3,4,5,6,7,8,9 } , n3 [ 6 ] = { 1,2,3,4,5,6 } , n4 [ 7 ] = { 1,2,3,4,5,6,7 } ; // 5000 – 9000 in green fonts are locations. num [ ] = n1 ; num [ 1 ] = n2 ; num [ 2 ] = n3 ; num [ 3 ] = n4 ; // can be accessed as 2-D array with varying sizes of array int ArraySize [ 4 ] = { 7, 9, 6, 7 } ; //size of n1, n2, n3, n4 // Other ways to calculate size are possible (like using sizeof()) for ( int i=0; i< 4 ; i++) { cout << "num[" << i << "] = n" << i+1 << " : " ; for ( int j=0; j<ArraySize[i]; j++ ) cout << num [ i ][ j ] << " " ; // *(num[i]+j) or *(*( num+i )+j)) cout << endl ; } num[0] num[1] num[2] num[3] Array of Pointers 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 1 2 3 4 5 6 7 num [ ]= n1 = 6000 num [ 1 ]= n2 = 7000 num [ 2 ]= n3 = 8000 num [3]= n4 = 9000 OUTPUT: num[0] = n1 : 1 2 3 4 5 6 7 num[1] = n2 : 1 2 3 4 5 6 7 8 9 num[2] = n3 : 1 2 3 4 5 6 num[3] = n4 : 1 2 3 4 5 6 7 num= 5000 5004 5008 5012

Dynamic Memory Allocation The exact size of an array is unknown until the compile time, i.e., time when a compiler compiles code into an executable form. The size of array declared initially can be sometimes insufficient and sometimes more than required. What if we need a variable amount of memory that can only be determined during runtime? We may require multiple variable for a task, which may no longer required in the later part of the program. These variables are taking space until the end of the program needlessly, as memory is automatically allocated during declaration and deallocated when the program finishes execution. Dynamic memory allocation allows a program to obtain more memory space, while running or to release space when no space is required. This allows the programmer to allocate memory manually when needed and deallocate when not required. C++ has two operators new and delete that perform the task of allocating and deallocating/freeing the memory (respectively) using pointer variables . The allocation is done at runtime. For dynamically allocated memory it is programmers’ responsibility to deallocate memory when no longer needed. If programmer doesn’t deallocate memory, it causes memory leak (memory is not deallocated until program terminates).

Operators – new and delete Operators new and new[] In order to request/assign dynamic memory into a pointer variable, we use the operator new followed by a data type specifier. For array, the data type specifier is followed by the number of memory blocks required within brackets [] . It returns a pointer to the beginning of the newly allocated array. Syntax: pointer_variable = new data_type ; // for single element pointer_variable = new data_type [ total_elements ] ; // for array Operators delete and delete[] Since the necessity of dynamic memory is usually limited to specific moments within a program, once it is no longer needed it should be freed/deallocated so that the memory becomes available again for other requests of dynamic memory. This is the purpose of the operator delete . Syntax: delete pointer_variable ; // for single variable delete [] pointer_variable ; // for array In the case of a pointer_variable = NULL , delete produces no effect.

Dynamic Memory Allocation OUTPUT: # of elements: 5 Enter elements: 2 6 7 4 3 Sum = 22 Main Memory n i ptr 2 6 7 4 3 sum 5 1 2 3 4 1 2 3 4 2 8 15 19 22 // new, delete int main( void ){ int n, i , * ptr ; cout << "# of elements: " ; cin >> n; //input 5 ptr = new int[ n ] ; if ( ptr == NULL ){ // unable to allocate cout << "Error! memory not allocated." ; return ; } int *sum = new int ; cout << "Enter elements:\n" ; for ( i =0, *sum=0; i <n; ++ i ){ //input 2 6 7 4 3 cin >> ptr [ i ]; // ( ptr + i ) *sum += ptr [ i ]; // *( ptr + i ) } cout << "Sum = " << *sum; delete sum; //single memory deallocated delete [] ptr ; //array memory deallocated return ; } *sum 5

// 6000 – 9000 in green fonts are locations. int ** num; num = new int * [4]; // int *num[4]; for ( int i =0; i <4; i ++) num[ i ] = new int [5]; // int num[4][5]; cout << "For each row\ nInput 5 integers:\n"; for ( int i =0; i <4; i ++){ cout << "num[" << i << "]: "; for ( int j=0; j<5; j++ ) cin >> num[ i ][j]; //*(num[ i ]+j) or *(*( num+i )+j)) } cout << "\ nnum [4][5]:\n 0 1 2 3 4\n-------------\n"; for ( int i =0; i <4; i ++){ cout << i << "| "; for ( int j=0; j<5; j++ ) cout << num[ i ][j] << " "; //*(num[ i ]+j) or *(*( num+i )+j)) cout << endl ; } for ( int i =0; i <4; i ++) delete [] num[ i ]; //free memory of each row num[ i ] delete num; //free memory of num return ; *(num+0)=num[0] *(num+1)=num[1] *(num+2)=num[2] *(num+3)=num[3] num= 7000 7004 7008 7012 2-D Dynamic Array 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 *(num+0)=num[0]= 8000 *(num+1)=num[1]= 8020 *(num+2)=num[2]= 8040 *(num+3)=num[3]= 8060 OUTPUT: For each row Input 5 integers: num[0]: 1 2 3 4 5 num[1]: 6 7 8 9 1 num[2]: 2 3 4 5 6 num[3]: 7 8 9 1 2 num[4][5]: 0 1 2 3 4 ------------- 0| 1 2 3 4 5 1| 6 7 8 9 1 2| 2 3 4 5 6 3| 7 8 9 1 2 num &num= 6000

int ** num, r, c; cin >> r; // input 4 num = new int * [r]; // int *num[r]; for ( int i =0; i <r; i ++){ cin >> c; // input 4 2 5 3 num[ i ] = new int [c]; // int num[r][c]; } // 6000 – 9000 in green fonts are locations. for ( int i =0; i <r; i ++) delete [] num[ i ]; //free memory of each row num[ i ] delete num; //free memory of num 2-D Dynamic Array – different length of row *(num+0)=num[0] *(num+1)=num[1] *(num+2)=num[2] *(num+3)=num[3] num=7000 7004 7008 7012 1 2 3 4 6 7 2 3 4 5 6 7 8 9 *(num+0)=num[0]= 8000 *(num+1)=num[1]= 8016 *(num+2)=num[2]= 8024 *(num+3)=num[3]= 8044 num &num=6000

Consider the statement int *p; which declares a pointer p , and like any other variable this space will contain garbage (random numbers), because no statement like p = & someint ; or p = new int; has yet been encountered which would give it a value. Writing a statement int *p=2000; is syntactically correct as p will point to the 2000 th byte of the memory. But it might fail as byte 2000 might be being used by some other program or may be being used by some other data type variable of the same program. So, such initialization or assignment must be avoided unless the address provided is guaranteed to be safe. There is an important difference between these definitions: char amsg [] = "now is the time" ; /* an array */ char * pmsg = "now is the time" ; /* a pointer */ amsg is an array, just big enough to hold the sequence of characters ending with '\0' that initializes it. Individual characters within the array may be changed but amsg will always refer to the same storage. On the other hand, pmsg is a pointer, initialized to point to a string constant; the pointer may subsequently be modified to point elsewhere, but the result is undefined if you try to modify the string contents. Pointers and Initialization
Tags