Tài liệu Giáo trình C++ P2 ppt

39 347 0
Tài liệu Giáo trình C++ P2 ppt

Đ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

www.gameinstitute.com Introduction to C and C++ : Week 2: Page 1 of 39 Game Institute by Stan Trujillo Week 2 Introduction to C and C++ www.gameinstitute.com Introduction to C and C++ : Week 2: Page 2 of 39 © 2001, eInstitute, Inc. You may print one copy of this document for your own personal use. You agree to destroy any worn copy prior to printing another. You may not distribute this document in paper, fax, magnetic, electronic or other telecommunications format to anyone else. This is the companion text to the www.gameinstitute.com course of the same title. With minor modifications made for print formatting, it is identical to the viewable text, but without the audio. www.gameinstitute.com Introduction to C and C++ : Week 2: Page 3 of 39 Table of Contents Lesson 2 – Data Structures 4 Complex Data Types 4 Arrays 5 Structures 11 Mixing Complex Types 12 Memory Usage 14 Pointers 15 Pointers and Functions 19 References 21 Pointer arithmetic 24 Memory Allocation 27 Automatic Variables 28 Dynamic Memory 29 Global Memory 30 The PlayerList Sample 31 Exercises 36 What’s next? 39 www.gameinstitute.com Introduction to C and C++ : Week 2: Page 4 of 39 Lesson 2 – Data Structures In Lesson 1 we used the data types that are intrinsic to C and C++, such as int, float, and char. As intrinsic types, these data types are directly supported by the language. In a sense, these are the only types of data that are supported. For game programming, all of the creepy monsters, hordes of aliens, simulated vehicles, and the virtual worlds in which these entities exist, are ultimately represented by these simple data types. Thankfully, C and C++ allow us to use the intrinsic data types to construct larger and more complex types. The intrinsic data types can be used directly, or as building blocks from which virtually any entity or system of entities can be represented. Once a complex data type has been defined, it can be used just like an intrinsic type. Variables of that type can be declared, passed to functions, saved to disk, and manipulated by assigning new values. The only difference is that the complex data structure is bigger (it occupies more memory), and it represents something that is more specific than each of its individual parts. In this lesson, in addition to learning how to create complex data structures, we’ll learn how to manage them efficiently: how to pass them to functions, and manage collections of data structures. We’ll also learn the different ways in which the memory required to represent these data types can be allocated. Complex Data Types There are two basic ways in which multiple data elements can be assembled into a larger data element. The first is to assemble a collection of homogenous types. This is called an array. An array uses a single data type as a building block, and is a new data type only because it represents two or more instances of that type. Arrays can be used to represent a collection of any data type. In Lesson 1, we used an array of the char type to represent a string. In this case each element in the array represents a character, and together the characters represent a text string. Strings are often used in games, to store player names, display in-game status information, and to display menus. Games can also use arrays of other data types. Some examples are list of scores, lists of monsters, or a list of network addresses. We’ll continue our discussion of arrays in the next section. The second method of defining a complex type is to use heterogeneous data types to create a new data type. This method allows any number of different data types to be used to define a new category of data type. This is called a structure. Unlike an array, which is formed as a collection of similar items, a structure can be used to represent entities that require multiple data types for representation. In a racing game, for example, a car might be represented as a structure that contains the make, model, weight, dimensions, fuel capacity, and handling characteristics of the vehicle. Structures are used extensively in games, and are best defined—at least in a rough form—early in the game development process. We’ll learn how to create and structures after we’ve covered arrays. If you’re familiar with the concepts behind object-oriented languages, you might be asking yourself why objects haven’t entered the picture yet. We will cover objects in detail in Lesson 3, building directly on what we cover in this lesson. By concentrating on data structures now, we’ll have less to digest when we introduce objects, because objects rely on the same data structures we’re using in this lesson. www.gameinstitute.com Introduction to C and C++ : Week 2: Page 5 of 39 Arrays C++ uses square brackets to denote an array. Declaring an array looks very much like a non-array variable declaration, but arrays require that the variable name be followed by square brackets. Typically the square bracket set contains the number of elements in the array. We can declare an array of integers like this: int playerScores[8]; This snippet declares an array of 8 integers that are collectively represented by the variable name playerScores. Each element of the playerScores array has int for a data type, and contains a value that can be inspected or modified using any operator that is appropriate for integers. Arrays use square brackets for declaration, and for accessing array elements. For declaration, the brackets contain the array size. For accessing array elements after the array has been declared, the brackets contain a numeric value called an index that indicates the desired element. Using the playerScore array declared earlier, a value can be stored in the first array element like this: playerScores[0] = 1; This assigns the first element in the array to 1. In this example we’ve used an index of zero, indicating the first element in the array. C++ uses a zero-based indexing scheme: the first element of an array is indexed as 0, not 1. This means that the last element of the array in our example has an index of 7, and not 8. This frequently leads to bugs for people with experience in Basic or Pascal which both use 1 to index the first array element. The code above demonstrates how a single array element can be assigned. To assign all of the elements in this array, we could use eight similar assignments, each with a different index, like this: playerScore[0] = 0; playerScore[1] = 0; playerScore[2] = 0; playerScore[3] = 0; playerScore[4] = 0; playerScore[5] = 0; playerScore[6] = 0; playerScore[7] = 0; Clearly, this is impractical for large arrays. Alternatively a loop can be used to iterate through the array: for (int i = 0; i < 8; i++) { playerScore[i] = 0; } Instead of a literal index, we’re using the variable i as the index, so that each element of the array is affected in turn. In this case we’re assigning each player score to zero using the assignment operator. Notice that we’re using the number 8 in the for loop as part of the terminating condition. This works only because we’re the terminating condition indicates that i must be less than 8. If we used the “less than or equal to” operator instead (<=) instead, the loop would assign nine array elements, as shown here: www.gameinstitute.com Introduction to C and C++ : Week 2: Page 6 of 39 for (int i = 0; i <= 8; i++) // out of bounds error (not detected by the compiler!) { playerScore[i] = 0; } This loop is problematic because it assigns a ninth array element. The last iteration of this loop assigns i to 8, which, because C++ arrays are indexed starting with zero, indicates the ninth element. The square bracket syntax used to indicate array elements can be used on either side of the assignment operator. This loop, for example, retrieves each element value, and displays it on the screen: for (int i = 0; i < 8; i++) { int score = playerScore[i]; cout << “player “ << i << “ has a score of “ << score << endl; } The loop above uses an integer called score to store each retrieved value, and then provides it to cout. Alternatively this temporary value can be omitted, like this: for (int i = 0; i < 8; i++) { cout << “player “ << i << “ has a score of “ << playerScore[i] << endl; } Each array element can be manipulated using the arithmetic operators. Since our example array contains player scores, a score might be incremented like this: playerScore[4] = playerScore[4] + 100; // adds 100 to the 5 th score Or, using the C++ shorthand notation: playerScore[4] += 100; // exactly the same as above Similarly, any function that accepts an int as an argument can accept an element of our array. For example, we can write a function that has this prototype: void DisplayPlayerScore( int s ); We can call like this: DisplayPlayerScore( playerScore[2] ); This function call passes the 3 rd score in the array to the DisplayPlayerScore function. Alternatively, a loop could be used to pass each score to DisplayPlayerScore, like this: for (int i = 0; i < 8; i++) { DisplayPlayerScore( playerScore[i] ); } www.gameinstitute.com Introduction to C and C++ : Week 2: Page 7 of 39 Providing an index to an array selects an array element. This array element is a variable of that type, and as such can be used in any context that is legal for that type. Attempting to pass these the entire array in the same context is illegal: DisplayPlayerScore( playerScore ); // compiler error! This won’t work because the DisplayPlayerScore, as we’ve defined it, takes an integer, and not an array of integers. In order to pass the entire array to a function, the function in question would have to accept an array instead of an integer. A function with this prototype, for example: void DisplayAllPlayerScores( int s[8] ); Would accept the entire array, like this: DisplayAllPlayerScores( playerScores ); For reasons that we’ll discuss later in this lesson, passing entire arrays to functions in this manner is best avoided in most cases. Like non-array variable declarations, a newly declared array has an undetermined state. The playerScore array used in this section, for example, contains 8 integer elements that have virtually random values. Using these values without first assigning known values will likely lead to undesirable results. Arrays can either be initialized using a loop shortly after declaration, as shown previously, or initialized when they are declared. In Lesson 1 we learned that intrinsic data types can be declared and initialized in a single statement, as shown below: int variable1= 0; float variable2 = 0.0f; Likewise, our playerScores array might be initialized like this: int scores[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; This declaration initializes each score to a known value. The first value to appear (zero) is assigned to the first array element, the second value to the second array element, and so forth. Initializing arrays requires that the declaration be followed by the assignment operator and that the initial values are enclosed in curly braces, separated by commas. All of the intrinsic data types support this notation. Here are some more examples: bool engineStates[4] = { true, true, false, true }; float fueltankStates[2] = { 100.0f, 0.0f }; The declarations above create an array of Booleans and an array of floating point values. Each array element is assigned initial values, so there’s no ambiguity about the array contents. When initial array values are provided in this fashion, there is no need to provide the array size. The previous declarations can also be written this way: bool engineStates[ ] = { true, true, false, true }; www.gameinstitute.com Introduction to C and C++ : Week 2: Page 8 of 39 float fueltankStates[ ] = { 100.0f, 0.0f }; The compiler can determine the size of the array for us by counting the number of initial values provided, so the two arrays above have 4 and 2 elements respectively. The char data type, when used in an array, is the standard format for representing text strings. As such, char arrays get some special treatment. This support takes the form of special initialization syntax, and a host of string handling functions that are provided in the standard libraries. For example, consider these two declarations, which result in two arrays with identical content. char str1[] = { 'a', 'b', 'c', 0 }; char str2[] = "abc"; The first declaration initializes each array element using the typical array initialization syntax, whereas the second uses a string literal. Notice that the first declaration, in addition to being harder to read, requires that we add a null-terminator explicitly (the zero as the last array element). Failing to do so would cause subsequent string operations to fail. In the second declaration, the compiler automatically adds a null-terminator. As a result, both of these arrays have a length of 4. Notice also that C++ requires that individual characters be enclosed in single quotations when used as literals. Of the two declarations above, the latter is preferred, due to better readability and the implicit null-termination. Not every array element must be initialized during declaration. If you wanted the first two array elements to be initialized, but didn’t care to assign values to the remainder of the array, you could write this: int scores[8] = { 100, 200 }; This declaration creates an array with 8 elements, and initializes the first two elements to 100 and 200. The remaining six elements are not explicitly initialized. Interestingly, the compiler automatically initializes any remaining array elements to zero. The presence of an array initializer list prompts the compiler to initialize the remaining the elements to zero. For example: long largeArray[64000] = { 0 }; In this example, despite the fact that only one array element is explicitly initialized, all 64,000 elements will be initialized to zero. If an array initializer list is present, array elements that are not explicitly initialized, are set to zero. In this example: long largeArray[64000] = { 1 }; The first element is assigned to 1, but the remaining 59,999 elements to be assigned a zero value. It is important to remember that array elements are not initialized unless at least one element is initialized. Here are some examples that explore the different array declaration notations: int a[10]; // all 10 array elements contain unknown values int b[10] = { 0 }; // all 10 array elements are initialized to zero int c[10] = { 100 }; // the first element is assigned to 100, the rest to zero. int d[]; // illegal (compiler error) array size or initializer list required int e[] = { 33, 44 }; // array size is 2, as determined by the initializer list char f[] = “zxy”; // creates a char array, or string, that has a length of 4 char g[] = { ‘z’, x’, ‘y’ }; // acceptable but risky (should not be treated as a string) char h[] = { ‘z’, ‘x’, ‘y’, 0 }; // safe, but not as readable as f www.gameinstitute.com Introduction to C and C++ : Week 2: Page 9 of 39 Note that if the g array is used as a string, a bug is likely due to the lack of a null-terminator. Furthermore, the size of the array is set to 3 because 3 values are provided in the initializer list, so there is no room in the array to add a terminator later without shortening the effective string length to 2. A common misconception is that strings that are initialized during declaration cannot be modified because its value was assigned at declaration. We’ll talk about conditions where this is true in Lesson 3, but in all of the declarations we’ve looked at so far, the contents of the resulting array can be modified at will. To demonstrate this fact, and write some code that manipulates an array, let’s write a sample called StringEdit. This sample displays a string, and allows the user to modify the contents of the underlying array by specifying an index. The String Edit sample looks like this: The StringEdit sample uses a char array to represent a string. The array is initialized with text that describes the array, and is displayed using cout. This string appears between the two dotted lines, as shown above. The user is then prompted for an index or one of three special values. Entering the number 44 causes the user to be prompted for an index at which a null-terminator is to be added (44 is used because it is not a valid index—the string has just 40 elements.) This has the effect of truncating the string, demonstrating the significance of the value zero when used in a string. Entering 55 prompts the user for an index where a space will be assigned to the array (we’re using cin for input, which doesn’t accept spaces as input.) Entering a valid index (0 through 38) prompts the user for a character to be placed in the array. Entering negative 1 (-1) causes the sample to terminate. A valid index is a value between zero (indicating the first array element) and 38. We prevent the user from modifying index 39 because that element is used for the null-terminator. If this element were to be reassigned, cout would display any and all characters until the value zero is encountered. This would likely involve the display of a large amount of data outside our array, and would constitute a bug. www.gameinstitute.com Introduction to C and C++ : Week 2: Page 10 of 39 The StringEdit sample is implemented using just the main function. A loop is used to repeatedly display the current state of the array, and to process user input. The main function appears here, in its entirety: int main() { char str[40] = "initial string - declared char str[40]"; while ( true ) { cout << endl; cout << " string contents " << endl; cout << str << endl; cout << " " << endl << endl; cout << "Enter index (0-38), 44 for a terminator, 55 for a space, or -1 to quit: "; int index; cin >> index; if (index == -1) return 0; if (index >= 0 && index < 39) { cout << "enter new character: "; char ch; cin >> ch; str[index] = ch; } else if (index == 44) { cout << "Enter index for terminator: "; int terminatorIndex; cin >> terminatorIndex; if (terminatorIndex >=0 && terminatorIndex < 39) str[terminatorIndex] = 0; else cout << "Invalid index for terminator" << endl; } else if (index == 55) { cout << "Enter index for space: "; int spaceIndex; cin >> spaceIndex; if (spaceIndex >=0 && spaceIndex < 39) str[spaceIndex] = ' '; else cout << "Invalid index for space " << endl; } else cout << "invalid index" << endl; }; return 0; } [...]... share variables between functions References Both C and C++ support pointers, so programmers that learned C first are usually comfortable with pointers, and tend to use them liberally As a result, even now that they are using C++, these programmers tend to use pointers in situations where references are more appropriate References are specific to C++, and, although they can’t do everything that pointers... names be prefaced in this fashion, but is a common practice among C++ programmers.) The new pointer, as it appears above, is un-initialized; its value is unknown, and therefore should not be used before it is assigned to a safe value For this reason, pointers are often declared like this: www.gameinstitute.com Introduction to C and C++ : Week 2: Page 16 of 39 int* pVar = 0; This initializes pVar to... can display memory addresses contained within pointers, like this: cout . Stan Trujillo Week 2 Introduction to C and C++ www.gameinstitute.com Introduction to C and C++ : Week 2: Page 2 of 39 © 2001, eInstitute,. Introduction to C and C++ : Week 2: Page 4 of 39 Lesson 2 – Data Structures In Lesson 1 we used the data types that are intrinsic to C and C++, such as int,

Ngày đăng: 19/01/2014, 02:20

Từ khóa liên quan

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

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

Tài liệu liên quan