1.07k likes | 1.24k Views
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
E N D
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