Beginning Visual C plus plus phần 3 potx

123 224 0
Beginning Visual C plus plus phần 3 potx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

You could use a for loop here if you also wanted to record the index position of the maximum element as well as its value(for example: double max = 0; int index = 0; for (int i = 0 ; i < sample->Length ; i++) if(max < samples[i]) { max = samples[i]; index = i; } Sorting One-Dimensional Arrays The Array class in the System namespace defines a Sort() function that sorts the elements of a one- dimensional array so that they are in ascending order. To sort an array you just pass the array handle to the Sort() function. Here’s an example: array<int>^ samples = { 27, 3, 54, 11, 18, 2, 16}; Array::Sort(samples); // Sort the array elements for each(int value in samples) // Output the array elements Console::Write(L”{0, 8}”, value); Console::WriteLine(); The call to the Sort() function rearranges the values of the elements in the samples array so they are in ascending sequence. The result of executing this code fragment is: 2 3 11 16 18 27 54 You can also sort a range of elements in an array by supplying two more arguments to the Sort() func- tion specifying the index for the first element of those to be sorted and the number of elements to be sorted. For example: array<int>^ samples = { 27, 3, 54, 11, 18, 2, 16}; Array::Sort(samples, 2, 3); // Sort elements 2 to 4 This statement sorts the three elements in the samples array that begin at index position 2. After execut- ing these statements, the elements in the array will have the values: 27 3 11 18 54 2 16 The are several other versions of the Sort() function that you can find if you consult the documentation but I’ll introduce one other that is particularly useful. This version presumes you have two arrays that are associated so that the elements in the first array represent keys to the corresponding elements in the second array. For example, you might store names of people in one array and the weights of the individ- uals in a second array. The Sort() function sorts the array of names in ascending sequence and also rearrange the elements of the weights array so the weights still match the appropriate person. Let’s try it in an example. 205 Arrays, Strings, and Pointers 07_571974 ch04.qxp 1/20/06 11:46 PM Page 205 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Try It Out Sorting Two Associated Arrays This example creates an array of names and stores the weights of each person in the corresponding ele- ment of a second array. It then sorts both arrays in a single operation. Here’s the code: // Ex4_13.cpp : main project file. // Sorting an array of keys(the names) and an array of objects(the weights) #include “stdafx.h” using namespace System; int main(array<System::String ^> ^args) { array<String^>^ names = { “Jill”, “Ted”, “Mary”, “Eve”, “Bill”, “Al”}; array<int>^ weights = { 103, 168, 128, 115, 180, 176}; Array::Sort( names,weights); // Sort the arrays for each(String^ name in names) // Output the names Console::Write(L”{0, 10}”, name); Console::WriteLine(); for each(int weight in weights) // Output the weights Console::Write(L”{0, 10}”, weight); Console::WriteLine(); return 0; } The output from this program is: Al Bill Eve Jill Mary Ted 176 180 115 103 128 168 Press any key to continue . . . How It Works The values in the weights array correspond to the weight of the person at the same index position in the names array. The Sort() function you call here sorts both arrays using the first array argument(names in this instance(to determine the order of both arrays. You can see from that output that after sorting every- one still has his or her correct weight recorded in the corresponding element of the weights array. Searching One-Dimensional Arrays The Array class also provides functions that search the elements of a one-dimensional array. Versions of the BinarySearch() function uses a binary search algorithm to find the index position of a given ele- ment in the entire array, or from a given range of elements. The binary search algorithm requires that the elements are ordered if it is to work, so you need to sort the elements before searching an array. 206 Chapter 4 07_571974 ch04.qxp 1/20/06 11:46 PM Page 206 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Here’s how you could search an entire array: array<int>^ values = { 23, 45, 68, 94, 123, 127, 150, 203, 299}; int toBeFound = 127; int position = Array::BinarySearch(values, toBeFound); if(position<0) Console::WriteLine(L”{0} was not found.”, toBeFound); else Console::WriteLine(L”{0} was found at index position {1}.”, toBeFound, position); The value to be found is stored in the toBeFound variable. The first argument to the BinarySearch() function is the handle of the array to be searched and the second argument specifies what you are look- ing for. The result of the search is returned by the BinarySearch() function as a value of type int. If the second argument to the function is found in the array specified by the first argument, its index posi- tion is returned; otherwise a negative integer is returned. Thus you must test the value returned to deter- mine whether or not the search target was found. Because the values in the values array are already in ascending sequence there is no need to sort the array before searching it. This code fragment would pro- duce the output: 127 was found at index position 5. To search a given range of elements in an array you use a version of the BinarySearch() function that accepts four arguments. The first argument is the handle of the array to be searched, the second argu- ment is the index position of the element where the search should start, the third argument is the num- ber of elements to be searched, and the fourth argument is what you are looking for. Here’s how you might use that: array<int>^ values = { 23, 45, 68, 94, 123, 127, 150, 203, 299}; int toBeFound = 127; int position = Array::BinarySearch(values, 3, 6, toBeFound); This searches the values array from the fourth array element through to the last. As with the previous version of BinarySearch(), the function returns the index position found or a negative integer if the search fails. Let’s try a searching example. Try It Out Searching Arrays This is a variation on the previous example with a search operation added: // Ex4_14.cpp : main project file. // Searching an array #include “stdafx.h” using namespace System; int main(array<System::String ^> ^args) { 207 Arrays, Strings, and Pointers 07_571974 ch04.qxp 1/20/06 11:46 PM Page 207 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com array<String^>^ names = { “Jill”, “Ted”, “Mary”, “Eve”, “Bill”, “Al”, “Ned”, “Zoe”, “Dan”, “Jean”}; array<int>^ weights = { 103, 168, 128, 115, 180, 176, 209, 98, 190, 130 }; array<String^>^ toBeFound = {“Bill”, “Eve”, “Al”, “Fred”}; Array::Sort( names, weights); // Sort the arrays int result = 0; // Stores search result for each(String^ name in toBeFound) // Search to find weights { result = Array::BinarySearch(names, name); // Search names array if(result<0) // Check the result Console::WriteLine(L”{0} was not found.”, name); else Console::WriteLine(L”{0} weighs {1} lbs.”, name, weights[result]); } return 0; } This program produces the output: Bill weighs 180 lbs. Eve weighs 115 lbs. Al weighs 176 lbs. Fred was not found. Press any key to continue . . . How It Works You create two associated arrays(an array of names and an array of corresponding weights in pounds. You also create the toBeFound array that contains the names of the people for whom you’d like to know their weights. You sort the names and weights arrays using the names array to determine the order. You then search the names array for each name in the toBeFound array in a for each loop. The loop variable, name, is assigned each of the names in the toBeFound array in turn. Within the loop, you search for the current name with the statement: result = Array::BinarySearch(names, name); // Search names array This returns the index of the element from names that contain name or a negative integer if the name is not found. You then test the result and produce the output in the if statement: if(result<0) // Check the result Console::WriteLine(L”{0} was not found.”, name); else Console::WriteLine(L”{0} weighs {1} lbs.”, name, weights[result]); Because the ordering of the weights array was determined by the ordering of the names array, you are able to index the weights array with result, the index position in the names array where name was found. You can see from the output that “Fred” was not found in the names array. 208 Chapter 4 07_571974 ch04.qxp 1/20/06 11:46 PM Page 208 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com When the binary search operation fails, the value returned is not just any old negative value. It is in fact the bitwise complement of the index position of the first element that is greater than the object you are searching for, or the bitwise complement of the Length property of the array if no element is greater than the object sought. Knowing this you can use the BinarySearch() function to work out where you should insert a new object in an array and still maintain the order of the elements. Suppose you wanted to insert “Fred” in the names array. You can find the index position where it should be inserted with these statements: array<String^>^ names = { “Jill”, “Ted”, “Mary”, “Eve”, “Bill”, “Al”, “Ned”, “Zoe”, “Dan”, “Jean”}; Array::Sort(names); // Sort the array String^ name = L”Fred”; int position = Array::BinarySearch(names, name); if(position<0) // If it is negative position = ~position; // flip the bits to get the insert index If the result of the search is negative, flipping all the bits gives you the index position of where the new name should be inserted. If the result is positive, the new name is identical to the name at this position, so you can use the result as the new position directly. You can now copy the names array into a new array that has one more element and use the position value to insert name at the appropriate place: array<String^>^ newNames = gcnew array<String^>(names->Length+1); // Copy elements from names to newNames for(int i = 0 ; i<position ; i++) newNames[i] = names[i]; newNames[position] = name; // Copy the new element if(position<names->Length) // If any elements remain in names for(int i = position ; i<names->Length ; i++) newNames[i+1] = names[i]; // copy them to newNames This creates a new array with a length one greater than the old array. You then copy all the elements from the old to the new up to index position position-1. You then copy the new name followed by the remaining elements from the old array. To discard the old array, you would just write: names = nullptr; Multidimensional Arrays You can create arrays that have two or more dimensions; the maximum number of dimensions an array can have is 32, which should accommodate most situations. You specify the number of dimensions that your array has between the angled brackets immediately following the element type and separated from it by a comma. The dimension of an array is 1 by default, which is why you did not need to specify up to now. Here’s how you can create a two-dimensional array of integer elements: array<int, 2>^ values = gcnew array<int, 2>(4, 5); 209 Arrays, Strings, and Pointers 07_571974 ch04.qxp 1/20/06 11:46 PM Page 209 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com This statement creates a two-dimensional array with four rows and five columns so it has a total of 20 elements. To access an element of a multidimensional array you specify a set of index values, one for each dimension; these are place between square brackets separated by commas following the array name. Here’s how you could set values for the elements of a two-dimensional array of integers: int nrows = 4; int ncols = 5; array<int, 2>^ values = gcnew array<int, 2>(nrows, ncols); for(int i = 0 ; i<nrows ; i++) for(int j = 0 ; j<ncols ; j++) values[i,j] = (i+1)*(j+1); The nested loop iterates over all the elements of the array. The outer loop iterates over the rows and the inner loop iterates over every element in the current row. As you see, each element is set to a value that is given by the expression (i+1)*(j+1) so elements in the first row will be set to 1,2,3,4,5, elements in the second row will be 2,4,6,8,10, and so on through to the last row which will be 4,6,12,16,20. I’m sure you will have noticed that the notation for accessing an element of a two-dimensional array here is different from the notation used for native C++ arrays. This is no accident. A C++/CLI array is not an array of arrays like a native C++ array it is a true two-dimensional array. You cannot use a single index with two-dimensional C++/CLI array, because this has no meaning; the array is a two-dimensional array of elements, not an array of arrays. As I said earlier, the dimensionality of an array is referred to as its rank, so the rank of the values array in the previous fragment is 2. Of course you can also define C++/CLI arrays of rank 3 or more, up to an array of rank 32. In contrast, native C++ arrays are actually always of rank 1 because native C++ arrays of two or more dimensions are really arrays of arrays. As you’ll see later, you can also define arrays of arrays in C++/CLI. Let’s put a multidimensional array to use in an example. Try It Out Using a Multidimensional Array This CLR console example creates a 12x12 multiplication table in a two-dimensional array: // Ex4_15.cpp : main project file. // Using a two-dimensional array #include “stdafx.h” using namespace System; int main(array<System::String ^> ^args) { const int SIZE = 12; array<int, 2>^ products = gcnew array<int, 2>(SIZE,SIZE); for (int i = 0 ; i < SIZE ; i++) for(int j = 0 ; j < SIZE ; j++) products[i,j] = (i+1)*(j+1); Console::WriteLine(L”Here is the {0} times table:”, SIZE); // Write horizontal divider line 210 Chapter 4 07_571974 ch04.qxp 1/20/06 11:46 PM Page 210 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com for(int i = 0 ; i <= SIZE ; i++) Console::Write(L”_____”); Console::WriteLine(); // Write newline // Write top line of table Console::Write(L” |”); for(int i = 1 ; i <= SIZE ; i++) Console::Write(L”{0,3} |”, i); Console::WriteLine(); // Write newline // Write horizontal divider line with verticals for(int i = 0 ; i <= SIZE ; i++) Console::Write(L”____|”); Console::WriteLine(); // Write newline // Write remaining lines for(int i = 0 ; i<SIZE ; i++) { Console::Write(L”{0,3} |”, i+1); for(int j = 0 ; j<SIZE ; j++) Console::Write(L”{0,3} |”, products[i,j]); Console::WriteLine(); // Write newline } // Write horizontal divider line for(int i = 0 ; i <= SIZE ; i++) Console::Write(L”_____”); Console::WriteLine(); // Write newline return 0; } This example should produce the following output: Here is the 12 times table: _________________________________________________________________ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ____|____|____|____|____|____|____|____|____|____|____|____|____| 1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 2 | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 3 | 3 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 4 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 44 | 48 | 5 | 5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 6 | 6 | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 | 60 | 66 | 72 | 7 | 7 | 14 | 21 | 28 | 35 | 42 | 49 | 56 | 63 | 70 | 77 | 84 | 8 | 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 88 | 96 | 9 | 9 | 18 | 27 | 36 | 45 | 54 | 63 | 72 | 81 | 90 | 99 |108 | 10 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 |100 |110 |120 | 11 | 11 | 22 | 33 | 44 | 55 | 66 | 77 | 88 | 99 |110 |121 |132 | 12 | 12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 |108 |120 |132 |144 | _________________________________________________________________ Press any key to continue . . . 211 Arrays, Strings, and Pointers 07_571974 ch04.qxp 1/20/06 11:46 PM Page 211 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com How It Works It looks like a lot of code, but most of it is concerned with making the output pretty. You create the two- dimensional array with the following statements: const int SIZE = 12; array<int, 2>^ products = gcnew array<int, 2>(SIZE,SIZE); The first line defines a constant integer value that specifies the number of elements in each array dimen- sion. The second line defines an array of rank 2 that has 12 rows of 12 elements. This array stores the products in the 12x12 table. You set the values of the elements in the products array in a nested loop: for (int i = 0 ; i < SIZE ; i++) for(int j = 0 ; j < SIZE ; j++) products[i,j] = (i+1)*(j+1); The outer loop iterates over the rows, and the inner loop iterates over the columns. The value of each element is the product of the row and column index values after they are incremented by 1. The rest of the code in main() is concerned solely with generating output. After writing the initial table heading, you create a row of bars to mark the top of the table like this: for(int i = 0 ; i <= SIZE ; i++) Console::Write(L”_____”); Console::WriteLine(); // Write newline Each iteration of the loop writes five horizontal bar characters. Note that the upper limit for the loop is inclusive, so you write 13 sets of five bars to allow for the row labels in the table plus the 12 columns. Next you write the row of column labels for the table with another loop: // Write top line of table Console::Write(L” |”); for(int i = 1 ; i <= SIZE ; i++) Console::Write(L”{0,3} |”, i); Console::WriteLine(); // Write newline You have to write the space over the row label position separately because that is a special case with no output value. Each of the column labels is written in the loop. You then write a newline character ready for the row outputs that follow. The row outputs are written in a nested loop: for(int i = 0 ; i<SIZE ; i++) { Console::Write(L”{0,3} |”, i+1); for(int j = 0 ; j<SIZE ; j++) Console::Write(L”{0,3} |”, products[i,j]); Console::WriteLine(); // Write newline } 212 Chapter 4 07_571974 ch04.qxp 1/20/06 11:46 PM Page 212 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com The outer loop iterates over the rows and the code inside the outer loop writes a complete row, including the row label on the left. The inner loop writes the values from the products array that correspond to the ith row, with the values separated by vertical bars. The remaining code writes more horizontal bars to finish off the bottom of the table. Arrays of Arrays Array elements can be of any type so you can create arrays where the elements are tracking handles that reference arrays. This gives you the possibility of creating so-called jagged arrays because each handle referencing an array can have a different number of elements. This is most easily understood by looking at an example. Suppose you want to store the names of children in a class grouped by the grade they scored, where there are five classifications corresponding to grades A, B, C, D, and E. You could first cre- ate an array of five elements where each element stores an array of names. Here’s the statement that will do that: array< array< String^ >^ >^ grades = gcnew array< array< String^ >^ >(5); Don’t let all the hats confuse you(it’s simpler than it looks. The array variable, grades, is a handle of type array<type>^. Each element in the array is also a handle to an array, so the type of the array elements is of the same form( array<type>^ so this has to go between the angled brackets in the original array type specification, which results in array< array<type>^ >^. The elements stored in the arrays are also handles to String objects so you must replace type in the last expression by String^; thus you end up with the array type being array< array< String^ >^ >^. With the array of arrays worked out, you can now create the arrays of names. Here’s an example of what that might look like: grades[0] = gcnew array<String^>{“Louise”, “Jack”}; // Grade A grades[1] = gcnew array<String^>{“Bill”, “Mary”, “Ben”, “Joan”}; // Grade B grades[2] = gcnew array<String^>{“Jill”, “Will”, “Phil”}; // Grade C grades[3] = gcnew array<String^>{“Ned”, “Fred”, “Ted”, “Jed”, “Ed”}; // Grade D grades[4] = gcnew array<String^>{“Dan”, “Ann”}; // Grade E The expression grades[n] accesses the nth element is the grades array and of course this is a handle to an array of String^ handles in each case. Thus each of the five statements creates an array of String object handles and stores the address in one of the elements of the grades array. As you see, the arrays of strings vary in length, so clearly you can manage a set of arrays with arbitrary lengths in this way. You could create and initialize the whole array of arrays in a single statement: array< array< String^ >^ >^ grades = gcnew array< array< String^ >^ > { gcnew array<String^>{“Louise”, “Jack”}, // Grade A gcnew array<String^>{“Bill”, “Mary”, “Ben”, “Joan”}, // Grade B gcnew array<String^>{“Jill”, “Will”, “Phil”}, // Grade C gcnew array<String^>{“Ned”, “Fred”, “Ted”, “Jed”, “Ed”}, // Grade D gcnew array<String^>{“Dan”, “Ann”} // Grade E }; The initial values for the elements are between the braces. 213 Arrays, Strings, and Pointers 07_571974 ch04.qxp 1/20/06 11:46 PM Page 213 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Let’s put this in a working example that demonstrates how you can process arrays of arrays. Try It Out Using an Array of Arrays Create a CLR console program project and modify it as follows: // Ex4_16.cpp : main project file. // Using an array of arrays #include “stdafx.h” using namespace System; int main(array<System::String ^> ^args) { array< array< String^ >^ >^ grades = gcnew array< array< String^ >^ > { gcnew array<String^>{“Louise”, “Jack”}, // Grade A gcnew array<String^>{“Bill”, “Mary”, “Ben”, “Joan”}, // Grade B gcnew array<String^>{“Jill”, “Will”, “Phil”}, // Grade C gcnew array<String^>{“Ned”, “Fred”, “Ted”, “Jed”, “Ed”}, // Grade D gcnew array<String^>{“Dan”, “Ann”} // Grade E }; wchar_t gradeLetter = ‘A’; for each(array< String^ >^ grade in grades) { Console::WriteLine(“Students with Grade {0}:”, gradeLetter++); for each( String^ student in grade) Console::Write(“{0,12}”,student); // Output the current name Console::WriteLine(); // Write a newline } return 0; } This example produces the following output: Students with Grade A: Louise Jack Students with Grade B: Bill Mary Ben Joan Students with Grade C: Jill Will Phil Students with Grade D: Ned Fred Ted Jed Ed Students with Grade E: Dan Ann Press any key to continue . . . 214 Chapter 4 07_571974 ch04.qxp 1/20/06 11:46 PM Page 214 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... fragment produces the same output Because LastIndexOf() searches backwards, the starting index is the last character in the string, which is words->Length-1 When an occurrence of word is found, you must now decrement index by 1 so that the next backward search starts at the character preceding the current occurrence of word If word occurs right at the beginning of words(at index position 0 — decrementing... second statement creates a new String object on the heap from the indicators array by passing the array to the String class constructor A class constructor is a function that will create a class object when it is called You’ll learn more about constructors when you get into defining your own classes Tracking References A tracking reference provides a similar capability to a native C+ + reference in that it... on the CLR heap You can create tracking references to value types on the stack and to handles in the garbage-collected heap; the tracking references themselves are always created on the stack A tracking reference is automatically updated if the object referenced is moved by the garbage collector You define a tracking reference using the % operator For example, here’s how you could create a tracking... punctuation characters Unregistered Version - http://www.simpopdf.com Merge and Split that were found, and indicators will contain ‘^’ characters at the positions in sentence where such characters were found The output is produced by the statements: Console::WriteLine(L”There are {0} punctuation characters in the string:”, count); Console::WriteLine(L”\n{0}\n{1}” sentence, gcnew String(indicators)); The second... A character of type char is treated as a numerical value so you get the character code value joined to the string The wchar_t character is of the same type as the characters in the String object (type Char) so the character is appended to the string Don’t forget that String objects are immutable; once created, they cannot be changed This means that all operations that apparently modify String objects... class type that is defined in the System namespace represents a string in C+ +/CLI(in fact a string consists of Unicode characters To be more precise it represents a string consisting of a sequence of characters of type System::Char You get a huge amount of powerful functionality with String class objects so it makes string processing very easy Let’s start at the beginning with string creation You can... you have a string literal containing 8-bit characters, but the compiler ensures it is converted to a wide-character string You can access individual characters in a string by using a subscript just like an array, and the first character in the string has an index value of 0 Here’s how you could output the third character in the string saying: Console::WriteLine(“The third character in the string is {0}”,... for punctuation characters: // Ex4_18.cpp : main project file // Searching for punctuation #include “stdafx.h” using namespace System; int main(array ^args) { array^ punctuation = {L’”’, L’\’’, L’.’, L’,’, L’:’, L’;’, L’!’, L’?’}; String^ sentence = L”\”It’s chilly in here\”, the boy’s mother said coldly.”; // Create array of space characters same length as sentence 2 23 Chapter... array^ indicators = gcnew array(sentence->Length){L’ ‘}; Simpo int index = 0; // Index of character found int count = 0; // Count of punctuation characters PDF Merge and Split Unregistered Version - http://www.simpopdf.com while((index = sentence->IndexOfAny(punctuation, index)) >= 0) { indicators[index] = L’^’; // Set marker ++index; // Increment to next character ++count; // Increase... with each team member taking responsibility for a tightly specified piece of the program, with a well-defined functional interface to the rest of the code Structure of a Function As you have seen when writing the function main(), a function consists of a function header that identifies the function, followed by the body of the function between curly braces containing the executable code for the function . namespace represents a string in C+ +/CLI(in fact a string consists of Unicode characters. To be more precise it represents a string consisting of a sequence of characters of type System::Char operation is a new string containing: Many deck hands make light work. You can also replace all occurrences of a given character in a string with another character or all occur- rences of a given substring. decrement index by 1 so that the next backward search starts at the character preceding the current occurrence of word. If word occurs right at the beginning of words(at index position 0 —decrementing

Ngày đăng: 12/08/2014, 10:21

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan