270 likes | 283 Views
What’s Left in the Course. Arrays and vectors ( Chapter 8) including searching and sorting (partially Chapter 11) Recursion , scope rules , global and static variables partially Chapter 10. s truct s (7.4). Used as data aggregates for an entity can be different types of data
E N D
What’s Left in the Course • Arrays and vectors (Chapter 8) • including searching and sorting (partially Chapter 11) • Recursion, scope rules, global and static variables • partially Chapter 10
structs (7.4) • Used as data aggregates for an entity • can be different types of data • e.g. for student • id, name, GPA, address, ... • Similar to classes, but everything is public • structs can have constructors • structs can have member functions • we will not deal with constructors and member functions for structs unless they are necessary • mostly we will use structs for combining data for an entity into a single structure
Structs • Example: struct for student • First struct must be defined by giving it a name and its fields (data) struct student // student is struct name { unsigned int id; // fields of student struct string name, lastname; double gpa; }; // dont forget ; at the end • Then variables of that type are declared and used. • dot operator is used to refer fields of a struct variable student stu; stu.name = "Ali"; cout << stu.gpa; • See structdemo.cpp (not in book)
What can and can’t be done with structs • Structs can be passed to functions as parameters • use const-reference if not changing (using value parameter is syntactically OK, but not preferredduetoperformancereasons) • use reference parameter if changing • struct fields behave as variables/objects of field type • id is an integer • name is a string • Youmayread, write, use as operands in operations, etc. • However, processingtheentirestructvariable is restrictive • cannot read or write (using >> and <<) structs unless those operators are specially defined for that struct • cannot use operators between two structs unless those operators are specially defined for that struct • see 7.4.2 for operator definitions for structs, but not responsible • structs are useful mostly in vectors (arrays)
Vectors and Arrays • Arrays are collections of several elements of the same type • E.g. 100 integers, 20 strings, 125 students, 12 dates, etc. • Single name is given to the entire array • But each element is accessed separately • Any element of an array can be accessed just as quickly as any other element (this is called “random access” but do not get confused with RandGen type of randomness) • In C/C++ there is a built-in array type • We will see it, but later • Vectors are a class-based version of arrays • First we will see vectors. • We’re using the class vector • need #include<vector> • vector is the standard C++ class vector
Why do we need arrays/vectors? • Consider the following example (not in the book): • pick n random numbers between 0 and 6 and count total number of occurrences of all outcomes (0, 1, 2, 3, 4, 5, 6) • n is an input • we need 7 counters • 7 declarations • 7 initializations • 7 conditions to increment after each occurrence • 7 cout statements to display the result • Fortunately, we have shorter way: ARRAYS/VECTORS • We can use vectors to store counters for all possible outcomes of the random numbers under a single name • easier processing in loops • see next slide for the program
randStats 0 1 2 3 4 5 6 Example Previous example using vectors - see randnums.cpp int num; int k; RandGen random; vector<int> randStats(7);// vector for counters int n = PromptRange("how many random numbers",1,20000); for(k=0; k <= 6; k++) // initialize counters to zero { randStats[k] = 0; } for(k=0; k < n; k++) // pick all random numbers { num = random.RandInt(7); // between 0 and 6 randStats[num] = randStats[num]+ 1; // and increment // corresponding counter } cout << "number\t\t# of occurrences" << endl; for(k=0; k <= 6; k++) { cout << k << "\t\t" << randStats[k] << endl; }
Vector/Array basics • Vectors/Arrays are homogeneous • each item (sometimes called element) has the same type • that type must be specified at declaration • Items in a vector/array are numbered (e.g. 1st, 3rd, or 105th) • those are called index or subscript • numbering starts with 0 • we have to use the index value to refer an element in a vector/array • Example definition and use of vectors (array definition is a bit different) vector<int> ivals(10); // ivals can store 10 ints ivals[0] = 3; // 0th element becomes 3 vector<string> svals(20); // svals can store 20 strings svals[4] = "cs201"; // 4th element contains "cs201"
Vector basics • Syntax of vector declaration • vector is a class, its declaration is construction • 3 different methods vector<type> variable_name; empty vector (will see later) vector<type> variable_name (size_expression); vector with size_expressionelements in it vector<type> variable_name (size_expression, init_value); vector with all size_expression elements initialized to init_value
Vector basics • size_expression can be any expression of type integer (or cast into integer) • not necessarily a constant value (this is actually a very important flexibility as compared to built-in arrays) • examples: vector <int> letters (int('Z')-int('A') + 1); • creates a vector of 26 integer elements and name it letters cin >> num; vector <double> counters (num); • creates a vector of doubles; total number of elements is input • Index value starts with 0 and ends with size-1 • type is type of the vector elements • can be built-in types (int, double, ...) or user defined types or classes or structs (string and date are class examples; student is struct example) • classes must have default constructors to be used in vector definition as element type
Defining vector objects • Can specify # elements in a vector, optionally an initial value vector<int> counts(300); //300 ints, values not initialized vector<int> nums(200, -1); // 200 ints, all -1 vector<double> d(10, 3.14); // 10 doubles, all pi vector<string> w(10, "cs"); // 10 strings, all "cs“ vector<string> words(10); // 10 strings, all "" • If the vector type is a class, then this class must have a default constructor • Default constructor is the one without parameters • Cannot define vector<Dice> cubes(10); since Dice doesn’t have default constructor • Vectors of classes are initialized with the default constructor • that is why all words are "" (empty string) • Vectors with built-in types are not initialized (unless explicitly initialized with the second argument of vector definition)
counter letters 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 Example vector definitions vector<int> counter(9, 0); each element is an integer(all initialized to 0) 0 0 0 0 0 0 0 0 0 vector<char> letters(18); each element is a char (not initialized yet) 9 10 11 12 13 14 15 16 17 vector<Date> holidays(6); each element is a date object that contains todays date holidays 12 12 2016 12 12 2016 12 12 2016 12 12 2016 4 12 12 2016 12 12 2016 0 1 2 3 4 5
0 1 2 3 4 5 6 7 8 How to reach a single vector/array element • specify the index value within square brackets after the vector/array name var_name [index_expr] • the value of index expression must be between 0 and (vector size – 1) • Examples vector<int> nums(9); nums[5] = 102; nums[0] = nums[5]*2-1; nums[nums[5]/20-3] = 55; nums[10] = 5; // error nums 203 55 102
Passing vectors to functions as parameters • Vectors can be passed as parameters to functions • Pass by reference (if function changes the vector) void Count (vector<int> & counts); • Pass by const-reference (if no changes made). void Print(const vector<int> & counts); • Passing by value makes a copy, requires time and space, so not preferred • IMPORTANT!!!Vector size cannot be given in parameter definition. Three solutions to this problem: • the size may be passed as another parameter • the size may be fixed and known • vectorhas a member function, size, to return the size of a vector
Example • Counting letters of a file • display number of occurrences of each letter at the end • counting iscase insensitive • see letters.cpp (the one in book is a bit different)
vector as a return type • Vector can be return type of a function vector<int> Count (istream & input, int & total); • Example: modify letters.cpp such that count returns the vector (not as reference parameter) • see letters2.cpp
gpa gpa gpa id id id 1250 1251 1260 3.2 name name name lastname lastname lastname Vectors of structs 0 • We can define vectors of structs struct student { unsigned int id; string name, lastname; double gpa; }; vector<student> class(11); // a vector with 11 students class[1].gpa = 3.2; for (i = 0; i <= 10; i++) class[i].id = i + 1250; 1 10
Vectors as lists • The “vector as counters” example constructs and initializes a vector with a specific number of elements • Other uses of vector require the vector to “grow” to accommodate new elements • Consider reading words from a text file, storing them in a vector • How big should we define vector initially? What are potential problems? • When a vector is used as a list, we’ll use a different method for adding elements to the vector so that the vector can “grow”
Reading words into a vector (problematic version) vector<string> words(1000); string w; int i = 0; string filename = PromptString("enter file name: "); ifstream input(filename.c_str()); while (input >> w) { words[i]=w; i++; } cout << "read " << i << " words" << endl; • What is the problem? • there might be more than 1000 words in the file • in this case index runs out of range
Reading words into a vector (with index range control but still problematic) vector<string> words(1000); string w; int i = 0; string filename = PromptString("enter file name: "); ifstream input(filename.c_str()); while ((input >> w) && (i < 1000)) { words[i]=w; i++; } cout << "read " << i << " words" << endl; • What is the problem? • works fine if there are no more than 1000 words • but if there are more than 1000 words, the rest is not read
Reading words into a vector (no problems) • One method would be to pass over the file two times • one to find out number of words • second to read the words into array • Another method is to benefit from vector class utilities as in the following code vector<string> words; //create empty vector string w; string filename = PromptString("enter file name: "); ifstream input(filename.c_str()); while (input >> w) { words.push_back(w); //adds the next word to the vector //also increases the size if necessary } cout << "read " << words.size() << " words" << endl;
Using vector::push_back • The method push_back adds new objects to the “end” of a vector, • Internally, the vector keeps track of its capacity • If there is capacity, then there is no problem; the new item is added to the end of the vector • When the capacity is reached and push_back attempts to add a new element to the vector, then the vector automatically “grows” by adding half of the current capacity to the capacity • 0, 1, 2, 3, 4, 6, 9, 13, 19, 28, ... n+(n/2) … • If you want to use push_back mechanism, then the vector should be defined initially without specifying a size • empty vector (zero size)
Size versus Capacity • Capacity is the allocated size of the vector • Size is how many elements are in the vector so far • They are not the same concepts, but related as described in the previous slide and illustrated below vector<string> names; // size is 0, capacity is 0 names.push_back("Ali"); // size is 1, capacity is 1 names.push_back("Husnu"); // size is 2, capacity is 2 names.push_back("Ayse"); // size is 3, capacity is 3 names.push_back("Cem"); // size is 4, capacity is 4 names.push_back("Jale"); // size is 5, capacity is 6 names.push_back("Hale"); // size is 6, capacity is 6 names.push_back("Veli"); // size is 7, capacity is 9 names.push_back("Gonca"); // size is 8, capacity is 9 names.push_back("Fatma"); // size is 9, capacity is 9 names.push_back("Yesim"); //size is 10, capacity is 13
size()member function • size() member function basically returns the number of elements in the vector • When a vector is defined with no initial capacity, and push_backis used to add elements, size() member function returns the number of elements exist in the vector • This is the number of calls of push_back() if no elements are deleted • If elements deleted using pop_back(), size updated too (decremented) • If a non-empty vector is created, then the capacity and the size is set to the number of elements of the vector. This capacity is considered full, so the first push_backincreases the capacity. • What about size()in case the vector is created as a non-empty one ? • returns the size specified during declaration if no push_back() is used • returns the size specified during declaration + the number push_back()’s, if push_back() is used
Vector Processing Examples – 1 (vectorproc.cpp – not in book) • write a function that takes a vector of integers as parameter and returns the maximum of numbers in it • process all array elements – for loop from 0 to vector’s size-1 int max (const vector<int> & v) //pre: vector v is not empty //post: return max of elements in v { int i, max_so_far = INT_MIN; for (i=0; i < v.size(); i++) { if (v[i] > max_so_far) { max_so_far = v[i]; } } return max_so_far; }
Vector Processing Examples – 2 (vectorproc.cpp – not in book) • Write a function that takes a vector of integers as parameter and returns true if the vector is sorted in ascending manner, false otherwise • may not process all vector elements • In this type of rule-checking applications, a possible method is to assume that the rule is satisfied before the loop and find a counterexample in the loop bool issorted (const vector<int> & v) //post: returns true if the array is acsending sorted { bool s = true; // initially assume that array is sorted //in the function try to break this assumption int i =1; while (i < v.size() && s == true) { //check until the end of array or until a counterexample is found if (v[i-1] > v[i]) // if not sorted s = false; // counterexample is found i++; } return s; }