CSC 211 Intermediate Programming Arrays & Pointers 1
Definition An array a consecutive group of memory locations that all have the same name and the same type. To create an array we use a declaration statement. It should indicate three things: The type of the value to be stored in each element The name of the array The number of elements in the array Examples: int c[12] ; int b[100], x[27] ; 2
The general form for declaring an array is: typename arrayname[arraysize] ; The expression arraysize, which is the number of elements, must be a constant, or a constant variable, or a constant expression. Constant variables must be initialized when they are declared and can not be modified thereafter. Using constant variables to specify the array size makes program more scalable. 3
Discussions If there are fewer initializer than elements in the array, the remaining elements are automatically initialized to zero. int n[10] = { 0 } ; explicitly initializes the first element to zero and implicitly initializes the remaining nine elements to zero. Automatic arrays are not implicitly initialized to zero. The programmer must at least initialize the first element to zero for the remaining elements to be automatically zeroed. The following array declaration int n[5] = {32, 27, 64, 18, 95, 14} ; would cause a syntax error because there are 6 initilizers and only 5 array elements. If the array size is omitted from a declaration with an initializer list, the number of elements in the array will be the number of elements in the initializer list. int n[ ] = { 1, 2, 3, 4, 5 } ; 4
Static Arrays and Local Static Variables Arrays that are declared static are initialized when the program is loaded. If a static array is not explicitly initialized by the programmer, that array is initialized to zero by the compiler. A static local variable in a function definition exists for the duration of the program but is only visible in the function body. 5
Passing Arrays to Functions To pass an array argument to a function, specify the name of the array without any brackets. The array size is normally pass as well so the function can process the specific number of elements in the array. C++ automatically passes arrays to functions using simulated call-byreference. The name of the array is the address of the first element of the array. Because the starting address is passed, the called function knows precisely where the array is stored. Therefore, when the called function modifies array elements in its function body, it is modifying the actual elements of the array in their original location. Although entire array are passed call-by-reference, individual array elements are passed call-by-value exactly as simple variables are. The function s parameter list must specify that an array will be received. For example void modifyarray ( int b[ ], int arraysize ) ; The size of the array is not required between the brackets. If it is included, the compiler will ignore it. The function prototype in this case is void modifyarray ( int [ ], int ) ; 6
Pointer Expressions and Pointer Arithmetic vptr = v ; location vptr = &v[0] ; 3000 3004 3008 3012 3016 v[0] v[1] v[2] v[3] v[4]. Pointer variable vptr Fig. 1. The array v and a pointer vptr that points to v. 7
Example vptr += 2 ; would produce 3008 (3000 + 2 * 4) assuming an integer is stored in 4 bytes of memory. In the array v, vptr would now point to v[2]. If vptr has been incremented to 3016, which points to v[4], the statement vptr -= 4 ; would set vptr back to 3000 at the beginning of the array. ++vptr ; vptr++ ; increments the pointer to point to the next location of the array. Each of the statements --vptr ; vptr-- ; decrements the pointer to point to the previous element of the array. 8
Example cont d Pointer variables may be subtracted from one another. For example, if vptr contains the location 3000, and v2ptr contains the address 3008, the statement x = v2ptr - vptr would assign to x the number of array elements from vptr to v2ptr, in this case 2. A pointer can be assigned to another pointer if both pointers are of the same type. Otherwise, a cast operator must be used to convert the value of the pointer on the right of the assignment to the pointer type on the left of the assignment. 9
The Relationship Between Pointers and Arrays Assume that integer array b[5] and integer pointer variable bptr have been declared. bptr = b ; This is equavalent to bptr = &b[0] ; Array element b[3] can alternatively be referenced with the pointer expression *( bptr + 3 ) ; The 3 in the above expression is the offset to the pointer. This notation is called a pointer/offset notation. The parentheses are necessary because the precedence of * is higher than the precedence of +. The address &b[3] can be written with the pointer expression bptr + 3. 10
The Relationship Between Pointers and Arrays cont d The array itself can be treated as a pointer and used in pointer arithmetic. For example, the expression *( b + 3) also refers to the array element b[3]. Pointers can be subscripted exactly as arrays can. For example, the expression bptr[1] refers to the array element b[1]. This expression is referred to as pointer/subscript notation. An array name is a constant pointer: it always points to the beginning of the array. Thus, the expression b += 3 is invalid because it attempts to modify the value of the array name with pointer arithmetic. 11
// Using subscripting and pointer notations with arrays #include <iostream.h> int main() { int b[] = { 10, 20, 30, 40 }; int *bptr = b; // set bptr to point to array b cout << "Array b printed with:\n" << "Array subscript notation\n"; for ( int i = 0; i < 4; i++ ) cout << "b[" << i << "] = " << b[ i ] << '\n'; cout << "\npointer/offset notation where\n" << "the pointer is the array name\n"; for ( int offset = 0; offset < 4; offset++ ) cout << "*(b + " << offset << ") = " << *( b + offset ) << '\n'; cout << "\npointer subscript notation\n"; for ( i = 0; i < 4; i++ ) cout << "bptr[" << i << "] = " << bptr[ i ] << '\n'; cout << "\npointer/offset notation\n"; for ( offset = 0; offset < 4; offset++ ) cout << "*(bptr + " << offset << ") = " << *( bptr + offset ) << '\n'; return 0; } 12
Output Array b printed with: Array subscript notation b[0] = 10 b[1] = 20 b[2] = 30 b[3] = 40 Pointer/offset notation where The pointer is the array name *( b + 0 ) = 10 *( b + 1 ) = 20 *( b + 2 ) = 30 *( b + 3 ) = 40 Pointer subscript notation bptr[0] = 10 bptr[1] = 20 bptr[2] = 30 bptr[3] = 40 Pointer/offset notation *( bptr + 0 ) = 10 *( bptr + 1 ) = 20 *( bptr + 2 ) = 30 *( bptr + 3 ) = 40 13
Allocating Memory With new Example: int *y = new int ; or int *y ; *y = 10 ; y = new int ; *y = 10 ; or int *y = new int[10] ; The general form is typename pointer_name = new typename ; typename pointer_name = new typename[intexpression] ; 14
Example #include <iostream> using namespace std ; int main( 0 { int *pi = new int ; // allocate space for an int *pi = 1001 ; // store a value there cout << int ; cout << value = << *pi << : location = << pi << \n ; double *pd = new double ; // allocate space for for a double *pd = 10000001.0 ; // store a double there cout << double ; 15
Example cont d cout << value = << *pd << : location = << pd << \n ; cout << size of pi = << sizeof pi ; cout << : size of *pi = << sizeof *pi << \n ; cout << size of pd = << sizeof pd ; cout << : size of *pd = << sizeof *pd << \n ; return 0 ; } Output int value = 1001 : location == 007B0A60 double value = 1e+007 : location = 007B0CD0 size of pi = 4 : size of *pi = 4 size of pd = 4 : size of *pd = 8 16
Discussions int *intptr ; char *namestr ; intptr = new int ; namestr = new char[6] ; // creates a variable of type int and stores // its address into intptr // creates a 6-element char array and stores the // base address of the array into namestr The new operator does two things: it creates an uninitialized variable (or array) of designated type; it returns a pointer to this variable (or the base address of an array). A dynamic variable is unnamed and cannot be directly addressed. It must be indirectly addressed through the pointer returned by the new operator. 17
Delete operator The built-in operator delete is used to destroy a dynamic variable. The delete operator has two forms, one for deleting a single variable, the other for deleting an array: delete Pointer ; // Delete the variable pointed to by Pointer delete [ ] pointer ; The delete operation does not delete the pointer; it deletes the pointed-to-variable. Applying delete to the NULL pointer has no effect. The delete operator must only be applied to a pointer value that was obtained from the new operator. delete intptr ; // returns the variable pointed to by intptr to the free store. // The value of intptr is then undefined delete [ ] namestr ; // Returns the array pointed to by namestr to the free // store. The value of namestr is then undefined. 18
Memory Leak Remember that a major reason for using dynamic data is to economize on memory space. It is counterproductive to keep dynamic variables when they are no longer needed a situation known as a memory leak. If this is done too often, you may run out of memory. Example: int *ptr1 = new int ; // create a dynamic variable int *ptr2 = new int ; // create a dynamic variable *ptr2 = 44 ; // assign a value to a dynamic variable *ptr1 = *ptr2 ; // copy one dynamic variable to another ptr1 = ptr2 ; // copy one pointer to another delete ptr2 ; // destroy a dynamic variable 19
Inaccessible Object & Dangling Pointer Inaccessible Object: A Dynamic variable on the free store without any pointer pointing to it. Dangling Pointer: A pointer that points to a variable that has been deallocated. #include <stddef.h>.... int *ptr1 = new int ; int *ptr2 = new int ; *ptr2 = 44 ; *ptr1 = *ptr2 ; delete ptr1 ; ptr1 = ptr2 ; delete ptr2 ; ptr1 = NULL ; // For NULL // Avoid an inaccessible object // Avoid a dangling pointer 20