Arrays and Pointers
E N D
Presentation Transcript
Arrays and Pointers Joe Meehean
Arrays • What if we want to store multiple items? • e.g., points scored for each of the 16 regular season Packer games • e.g., miles traveled each day on a 3 day journey • Arrays • store a collection of items of the same data type • items are stored in a specific order • individual items are not named • referenced by position in array (1st item, 2nd item, etc…) • arrays are fixed size, they cannot grow or shrink • C++ arrays do not store the size of the array
Arrays • Compound data type: type name[dimension] • type: specifies data type of items stored in array • name is the name of the array variable • dimension: determines size of the array (# of elements) • e.g., int array[10]; • e.g., char alphabet[26]; • e.g., float student_gpas[15]; • dimension must be a constant unsigned expression • defined at compile time • e.g., int array[10]; • constant variables are allowed (more on this later)
Arrays • Explicitly initializing arrays • comma separated list of values for items in array • enclosed in curly braces • e.g., int a[3] = {5, 6, 7} • e.g., int a[] = {5, 6, 7} • If array items are not initialized at creation • and the data type is a built-in (e.g., int, float, char, etc…) • and the array is defined outside of a function,then elements are initialized to 0 • and the array is defined inside of a function,then elements are left unitialized
Arrays • What happens when you create an array • allocates a contiguous block of memory • enough to store dimension items • initializes the memory odds 0 // outside of a function int odds[5]; 0 0 0 0
Arrays • Accessing array elements • Uses [] operator • Index starts at 0 • for an array of 10 elements • indices range from 0 to 9 odds 0 0 int odds[5]; … // prints 1st element cout << odds[0] << endl; // prints 5th element cout << odds[4] << endl; 0 1 0 2 0 3 0 4
Arrays • Assigning array elements • Also uses [] operator • Index also starts at 0 odds 1 0 int odds[5]; … // assigns 1st element odds[0] = 1; // assigns 5th element odds[4] = 9; 0 1 0 2 0 3 9 4
Arrays • Accessing and assigning array elements using variables • index variable should a size_t type • treat it like an unsigned integer odds int odds[5]; // assign odd numbers size_t index; for(index = 0; index < 5; index++){ odds[index] = index * 2 + 1; } // prints all of the elements for(index = 0; index < 5; index++){ cout << odds[index] << endl; } 1 0 3 1 5 2 7 3 9 4
Arrays • Illegal operations • using the copy operation: int array1(array2) • or the assignment operation: array1 = array2 • Dangerous operations, but legal • arrays won’t prevent you from accessing memory outside of what you allocated • accesses or modifies other variables that are stored near it • really bad news • e.g., int odds[5]; cout << odds[-1] << endl; cout << odds[5] << endl;
Arrays int counter = 15; int odds[5]; int other = 12 counter: 15 1 odds 0 3 1 5 2 7 3 9 4 other: 12
Arrays int counter = 15; int odds[5]; int other = 12 odds[-1] = -1; odds[5] = 11; counter: -1 1 odds 0 3 1 5 2 7 3 9 4 other: 11
Arrays int odds[5]; … // prints all of the elements size_t index; for(index = 0; index < 5; index++){ cout << odds[index] << endl; } • Problems with this code • Readability • what is 5? what does 5 mean? • magic number • Maintainability • what if we need to keep the first 10 odds • 80% of 5’s in code refer to odds array size, others do not • how can we tell which is which
Arrays int MAX_ODDS = 5; int odds[MAX_ODDS]; … // prints all of the elements size_t index; for(index = 0; index < MAX_ODDS; index++){ cout << odds[index] << endl; } • replace 5 with variable name MAX_ODDS • increases readability • easy to change size of odds array • problem: dimension must be a constant literal • e.g., 5, 18, 98 • or it must be a constant variable
Constant Variables • Use the const keyword • makes the variable constant • assigned its value during compilation • cannot be changed after its initialization • e.g., constint MAX_ODDS = 5; int odds[MAX_ODDS]; • Trying to overwrite MAX_ODDS now results in compiler error • e.g., MAX_ODDS = 15; // compiler error
PRACTICE!!! • Create two arrays of size 10 • fill the 1st with the 1st 10 odd numbers • fill the 2nd with the 1st 10 even numbers • Write a function to print the contents of an integer array • the function should take the array as a parameter • Write a function to copy the values from one array to another
Aliasing • An alias is another name for the same object • two variables names are attached to the same data • Aliasing is really important in C++ • and many other programming languages • well see why when we cover Objects • C++ does aliasing in two ways • references • pointers
References • References are aliases that “refer” to other variables • its just another name for an object • Compound type • type defined in terms of another type • e.g., arrays are compound types • Reference is a compound type • type &variable; • e.g., int &foo; • should be read from right to left:“foo is a reference to an int”
References • Initializing a reference • References must be initialized at declaration • Must be initialized using object of the same type • cannot be initialized using a literal • After initialization a reference is forever bound to that object • cannot rebind to another object intval = 7; int &refVal = val; // GOOD int &refVal2; // ERROR int &refVal3 = 11; // ERROR double dval = 2.1; int &refVal3 = dval; // ERROR
References • All operations on a reference are performed on the underlying object 7 val intval = 7; int &refVal = val; refVal 9 val refVal = 9; refVal 10 val val++; refVal
References • References to constants • cannot change the underlying data • can refer to a const object or even literals • created using const keyword constintval = 7; constint &refVal = val; // GOOD int &refVal2 = val; // ERROR constint &refVal3 = 11; // GOOD constint &refVal4 = 12 * 57 + 1; // GOOD
References • As parameters of a function • nonreference parameters are copied using the corresponding function arguments • the original arguments cannot be changed 7 arg1 int arg1 = 7; int arg2 = 15; swap(arg1, arg2); void swap(int parm1, int parm2) { inttmp = parm1; parm1 = parm2; parm2 = tmp; } 15 arg2
References • As parameters of a function • nonreference parameters are copied using the corresponding function arguments • the original arguments cannot be changed 7 arg1 int arg1 = 7; int arg2 = 15; swap(arg1, arg2); void swap(int parm1, int parm2) { inttmp = parm1; parm1 = parm2; parm2 = tmp; } 15 arg2 7 parm1 15 parm2
References • As parameters of a function • nonreference parameters are copied using the corresponding function arguments • the original arguments cannot be changed 7 arg1 int arg1 = 7; int arg2 = 15; swap(arg1, arg2); void swap(int parm1, int parm2) { inttmp = parm1; parm1 = parm2; parm2 = tmp; } 15 arg2 7 15 parm1 15 7 parm2
References • As parameters of a function • nonreference parameters are copied using the corresponding function arguments • the original arguments cannot be changed 7 arg1 int arg1 = 7; int arg2 = 15; swap(arg1, arg2); void swap(int parm1, int parm2) { inttmp = parm1; parm1 = parm2; parm2 = tmp; } 15 arg2
References • As parameters of a function • reference parameters only copy the reference,not the actual data • binds parameters to argument’s data 7 arg1 int arg1 = 7; int arg2 = 15; swap(arg1, arg2); void swap(int& parm1,int& parm2) { inttmp = parm1; parm1 = parm2; parm2 = tmp; } 15 arg2
References • As parameters of a function • reference parameters only copy the reference,not the actual data • binds parameters to argument’s data parm1 7 arg1 int arg1 = 7; int arg2 = 15; swap(arg1, arg2); void swap(int& parm1,int& parm2) { inttmp = parm1; parm1 = parm2; parm2 = tmp; } 15 arg2 parm2
References • As parameters of a function • reference parameters only copy the reference,not the actual data • binds parameters to argument’s data parm1 7 15 arg1 int arg1 = 7; int arg2 = 15; swap(arg1, arg2); void swap(int& parm1,int& parm2) { inttmp = parm1; parm1 = parm2; parm2 = tmp; } 15 7 arg2 parm2
References • As parameters of a function • reference parameters only copy the reference,not the actual data • binds parameters to argument’s data 7 15 arg1 int arg1 = 7; int arg2 = 15; swap(arg1, arg2); void swap(int& parm1,int& parm2) { inttmp = parm1; parm1 = parm2; parm2 = tmp; } 15 7 arg2
References • Passing references avoids expensive copies • Adds new problems that data may be changed • maybe we want to be sure it won’t be • or want to use literals without copying • Pass const references boolisNegative(int& parm1) { return (parm1 < 0 ); } intval = -7; isNegative(val); // OK isNegative(-15); // WON’T COMPILE
References • Passing references avoids expensive copies • Adds new problems that data may be changed • maybe we want to be sure it won’t be • or want to use literals without copying • Pass const references boolisNegative(constint& parm1) { return (parm1 < 0 ); } intval = -7; isNegative(val); // OK isNegative(-15); // OK
References • Returning nonreferences • the return value (object) is copied • e.g., add 1 to absolute value -4 arg intarg = -4; abs(arg)++; cout << arg << endl; int abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; }
References • Returning nonreferences • the return value (object) is copied • e.g., add 1 to absolute value -4 arg intarg = -4; abs(arg)++; cout << arg << endl; int abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; } parm
References • Returning nonreferences • the return value (object) is copied • e.g., add 1 to absolute value -4 4 arg intarg = -4; abs(arg)++; cout << arg << endl; int abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; } parm
References • Returning nonreferences • the return value (object) is copied • e.g., add 1 to absolute value -4 4 arg intarg = -4; abs(arg)++; cout << arg << endl; int abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; } 4 tmp
References • Returning nonreferences • the return value (object) is copied • e.g., add 1 to absolute value -4 4 arg intarg = -4; abs(arg)++; cout << arg << endl; int abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; } 4 5 tmp
References • Returning nonreferences • the return value (object) is copied • e.g., add 1 to absolute value 4 arg intarg = -4; abs(arg)++; cout << arg << endl; int abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; }
References • Returning a reference • the object itself is returned • returned reference can be assigned new data or updated -4 arg intarg = -4; abs(arg)++; cout << arg << endl; int& abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; } parm
References • Returning a reference • the object itself is returned • returned reference can be assigned new data or updated -4 4 arg intarg = -4; abs(arg)++; cout << arg << endl; int& abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; } parm
References • Returning a reference • the object itself is returned • returned reference can be assigned new data or updated -4 4 arg intarg = -4; abs(arg)++; cout << arg << endl; int& abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; } tmp
References • Returning a reference • the object itself is returned • returned reference can be assigned new data or updated 4 5 arg intarg = -4; abs(arg)++; cout << arg << endl; int& abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; } tmp
References • Returning a reference • the object itself is returned • returned reference can be assigned new data or updated 5 arg intarg = -4; abs(arg)++; cout << arg << endl; int& abs(int& parm){ if( parm < 0 ){ parm = parm * -1; } return parm; }
References • Returning a reference • never return a reference a local object int arg1 = 2; int arg2 = 5; int sum = add(arg1, arg2); int& add( int& parm1, int& parm2){ intval = parm1 + parm2; return val; } 2 arg1 5 arg2
References • Returning a reference • never return a reference a local object parm1 int arg1 = 2; int arg2 = 5; int sum = add(arg1, arg2); int& add( int& parm1, int& parm2){ intval = parm1 + parm2; return val; } 2 arg1 5 arg2 parm2
References • Returning a reference • never return a reference a local object parm2 int arg1 = 2; int arg2 = 5; int sum = add(arg1, arg2); int& add( int& parm1, int& parm2){ intval = parm1 + parm2; return val; } 2 arg1 5 arg2 parm2 7 val
References • Returning a reference • never return a reference a local object int arg1 = 2; int arg2 = 5; int sum = add(arg1, arg2); int& add( int& parm1, int& parm2){ intval = parm1 + parm2; return val; } 2 arg1 5 arg2 7 val tmp
References • Returning a reference • never return a reference a local object int arg1 = 2; int arg2 = 5; int sum = add(arg1, arg2); int& add( int& parm1, int& parm2){ intval = parm1 + parm2; return val; } 2 arg1 5 arg2 7 val sum
Pointers • Pointers are aliases that “point” to other variables • its just another name for an object • Pointer is a compound type • type *variable; • e.g., int*foo; • should be read from right to left:“foo is a pointer to an int”
Pointers • Alternate (dangerous) way to define pointers • type* variable; • e.g., int* foo; • dangerous: int* pval1, pval2; • pval1 is a pointer to an int • pval2 is an int • properly: int *pval1, *pval2;
Pointers • Pointers store the address of the object they alias • this gives us lots of power • more power than references • also more rope • We need to be able to get the address of objects • use the address-of operator & • e.g., the integer pointer pval is assigned the address of valintval = 7;int *pval = &val; • can use & on any value that can be on the left-side of an assignment • called lvalues • e.g., variables but not literals