830 likes | 947 Vues
Dive into the fundamentals of C++ programming as applied to game development. This boot camp covers essential topics like memory management, including stack and heap segments, and global and text segments. Gain insights into variable storage, types, and how to prevent common linker errors. We’ll explore practical examples, coding structures, and handling character types for text. Perfect for beginners looking to grasp the core concepts of C++ before tackling game technologies. Follow along with hands-on exercises and learn to set up your development environment efficiently.
E N D
CSE 380 – Computer Game ProgrammingC++ Boot Camp BioShock by 2K Games, 2007
Looking for a good reference? http://www.cplusplus.com/doc/tutorial/introduction/
What is memory? • Think of it as a giant array • How do we assign data to/get data from memory? • memory addresses • i.e. indices into memory array • addresses are typically byte addressable 0xffffffff Stack Segment Heap Segment 0x10000000 Global Segment Text Segment 0x00000000
What goes in each memory segment? • Stack Segment • local variables (includes arguments) • Heap Segment • instance variables • Global Segment • data that is known at compile time • Ex: String Literals like “Hello” • global variables (only one of each) • Text Segment • program instructions Stack Segment Heap Segment Global Segment Text Segment
Why do we care about this? • This is important to understand proper data manipulation • Be careful where you put your data! • Data put on the stack disappears when the method returns!
Why are we here? • To prevent C & C++ from becoming the obstacle to learning to build game technologies • What will we cover? • Text • Arrays & structs • Pointers Call by Value vs Call by Reference • Objects & classes • Inheritance
Some reasons why C++ can be painful • Multiple flavors • Each platform has its own compiler • each has its own ways of doing things • For VS2010, you’ll make 2 types of source files: • .h : header files • .cpp : c++ source files
Let’s Start With a VS2010 Tutorial • Go to the class schedule page • For Wed., you’ll see a VS 2010 tutorial • Open that page and follow along
Make the BankFramework Project • Win32 Project • Visual C++ • “CSE380_Cpp_BootCamp” Solution • Put project in solution dir • Make it a static library project
Windows Dev. File Types • Source Code: • Header files (.h) • Source files (.cpp) • Built Files: • Static Libraries (.lib) • Execuitable Apps (.exe) • Dynamic Link Libraries (.dll)
Stuff we won’t touch • VS 2010-generated files: • VS 2010 Solution Files (.sln) • Solution Database/settings files (.ncb & .sdf) • VS 2010 Project Files (.vcxproj) • Object Files (.obj) • Precompiled Header Files (.pch) • Lots of other junk
Project Directory Structure • Note, this is my own style: • SolutionDir • Apps (where our own .exe files go) • /ProjectName/ProjectName.exe • Common (where our own .lib files go) • ProjectName.lib • ProjectName • ProjectName.vcxproj • /ProjectNameSourceCode/…cpp & .h • Temp (Intermediate Dir)
VS 2010 Macros • $(SolutionDir) • $(ProjectDir) • $(ProjectName) • $(Configuration) • $(IntDir) • $(OutDir) • $(TargetName) • $(TargetExt)
Why do linker errors happen? • 1. A header file says a method is available, but it’s never defined • may be spelled incorrectly, maybe scoped incorrectly, or not scoped at all • 2. VS 2010 doesn’t know where to look for a .lib file • 3. VS 2010 doesn’t know which .lib file to link to
Setup Directory Structure • Select Output Location • Select a Temp Directory • Group VS2010-generated source files • Add a Source directory to your project • Add a Filter • Add Account and Bank Classes
What’s a wchar_t? • A C++ type • It stores wide characters • Why not use char? • might not accommodate Unicode • in truth, windows uses wchar_t • they have their own similar type WCHAR • so we’ll use wchar_t for all text
And for strings of text? • We’ll use wstring • What’s that? • String of wide characters • And for num-text and text-num conversions? • we’ll use wstringstream • Look at BankConsoleApp
Exercise • Change the program such that it asks the user for data regarding the new Account • Owner and initial balance • Add the new account to the bank • Note, the bank accepts Account pointers. Ex: Account *a = new Account(ownerWstring, 1000);
Arrays • In C++, you can put an array on the stack void method() { int stackNums[5]; … • global region: int globalNums[5]; void method() {… • or the heap: int *heapNums = new int[5];
#include "stdafx.h" #include <string> using std::wstring; #include <iostream> using namespace std; #include <sstream> int _tmain() { int counter = 0; while (counter < 10000) { wstring text; std::wstringstream wss; wss << counter; text.append(L"Counter: "); text.append(wss.str()); text.append(L"\t"); wcout << text; wstring *textPointer = new wstring(); textPointer->append(L"Counter: "); textPointer->append(wss.str()); textPointer->append(L"\n"); wcout << (*textPointer); _sleep(1); counter++; } } Make a new Win32 Console Project • Run the program • Also, open the task manager (CTRL – ALT – DEL) • Is there a memory leak?
Ever used C? • Java inherited much from C • similar primitives (not entirely the same) • similar conditional statements • similar loops • But lots is different • pointers • structs • C memory management • and much more
What is a computer’s memory? • A sequential group of storage cells • typically a cell is a byte • Each cell has an address (a number) • In C as in Java • some cells contain data • some cells contain references to other memory addresses • memory addresses are typically 4 bytes
Pointers • In Java, what do object variables store? • memory addresses • this makes them pointers • what do they point to? • object data on the heap • In C, you can have either: • a pointer to a struct/array/primitive OR • the actual struct/array/primitive
* • * is a C operator used for 2 purposes: • To declare a variable as a pointer. Ex: int *myIntPointer; • right now, myIntPointer points to a random address • trying to use before initialization results in a segmentation fault or bus error • To dereference an existing pointer variable. Huh? • means to get what’s at the address the pointer stores
& • A C operator used for getting the address of a variable • This would produce an address similar to what’s stored by a pointer
Think of it this way • When you compile a C program, instructions are added for properly running your program • One thing these instructions do is manipulate declared variables • Every declared variable is stored at a memory location • So the question is what’s there? • for a regular int, just a number • for an int*, a memory address of an int
Example, what output will we get? int num = 5; int *pNum = # num = 7; printf("num = %d\npNum = %d\n", num, *pNum); if (&num == pNum) printf("true\n"); else printf("false\n"); OUTPUT: num = 7 pNum = 7 true
So who cares? • Why do we need pointers? What good are they? • In C, pointers can be used to multiple advantages: • call-by-reference methods • dynamic arrays • dynamic memory allocation using pointer arithmetic • Data at the end of a pointer can be filled in later
Call-by-value • In Java, when you pass an argument to a method, you are actually passing a copy of that argument • this is called call-by-value • Ex: public static void main(String[] args) { int x = 5; junk(x); System.out.println("x is " + x); } public void junk(int argument) { argument++; } OUTPUT: x is 5
C also has call-by-reference • We can pass the adddress of a variable. So? • We can directly change the original variable • Ex: void junk(int cbv, int *cbr); int main() { int x = 5; int y = 6; junk(x, &y); printf("x is %d\ny is %d\n", x, y); } void junk(int cbv, int *cbr) { cbv++; (*cbr)++; } OUTPUT: x is 5 y is 7
Is it still call by value? • Some might say it’s still technically call-by-value • we are passing a copy of the address • So, assigning an address to the pointer would not change the original pointer
What’s the output and why? void junk(int *test); int main() { int x = 5; junk(&x); printf("x is %d\n", x); } void junk(int *test) { int num = 10; test = # } OUTPUT: x is 5
What’s dynamic memory allocation? • In Java when objects are constructed based on decisions made at runtime • In C, when structs and arrays are constructed based on decisions made at runtime • For dynamic structs & arrays, we can use pointers
First things first, what’s a struct? • Like a record in Pascal • A single construct that can store multiple variables • sounds like an object BUT • does not have methods
Declaring a struct type & struct variables • To declare a struct type: struct Point { int x; int y; }; • To declare a struct variable: struct Point p1; • To reference data in a struct, use ‘.’ operator, just like an object: p1.x = 5;
struct Point { int x; int y; }; void changePoint(struct Point p); int main() { struct Point p1; p1.x = 100; p1.y = 200; changePoint(p1); printf("p1.x is %d\np1.y is %d\n", p1.x, p1.y); } void changePoint(struct Point p) { p.x *= 5; p.y *= 4; } OUTPUT: p1.x is 100 p1.y is 200 We just changed p, a copy of p1, but not p1
struct Point { int x; int y; }; void changePoint(struct Point p); int main() { struct Point p1; p1.x = 100; p1.y = 200; changePoint(&p1); printf("p1.x is %d\np1.y is %d\n", p1.x, p1.y); } void changePoint(struct Point *p) { (*p).x *= 5; (*p).y *= 4; } OUTPUT: p1.x is 500 p1.y is 800 We just changed p, and so changed p1
BTW, where is p1 in memory? int main() { struct Point p1; p1.x = 100; p1.y = 200; changePoint(&p1); printf("p1.x is %d\np1.y is %d\n", p1.x, p1.y); } IN THE main method STACK FRAME!
struct Point { int x; int y; }; void changePoint(struct Point p); int main() { struct Point *p1 = makePoint(); printf("p1.x is %d\np1.y is %d\n", (*p1).x, (*p1).y); } struct Point* makePoint() { struct Point p1; p1.x = 100; p2.y = 200; return &p1; } What happens? DISASTER! WHY? When makePoint ends, p1 gets popped from the stack
How can we fix this? • Declare a struct pointer variable • When you want to make one on the heap, use malloc • What’s malloc? • a method for dynamic memory allocation • you give it a size • it gives you that many bytes of continuous memory cells • it returns you the address of the first byte in the block
Note, always free what you malloc • C has no garbage collector • If you malloc something, when you’re done with it you need to free it • Why? • if you don’t the memory will not be recycled • this is called a memory leak • Who cares? • you should if you want your program to run efficiently • What’s free? • a method that releases the memory block argument
struct Point { int x; int y; }; void changePoint(struct Point p); int main() { struct Point *p1 = makePoint(); printf("p1.x is %d\np1.y is %d\n", p1->x, p1->y); } struct Point* makePoint() { struct Point *p1; p1 = malloc(sizeof(struct Point)); (*p1).x = 100; (*p2).y = 200; return p1; } NOW IT WORKS
-> • Used to dereference data in a pointer to a struct or array. Ex: struct Point { int x; int y; }; int main() { int pointBytes = sizeof(struct Point); struct Point *p = malloc(pointBytes); p->x = 10; p->y = 20; printf("x is %d\ny is %d\n", p->x, p->y); free(p); }
What if we don’t free? struct Point *p; int pointSize = sizeof(struct Point); int i; for (i = 0; i < 10000; i++) { p = malloc(pointSize); p->x = i % 1000; p->y = i % 500; printf("p->x is %d\tp->y is %d\n", p->x, p->y); } Memory Leak! (that’s a bad thing) • note, by the time this loop ends, your program will be using up 8 bytes * 10000 = 80000 bytes of memory for one p variable • where’d I get 8 bytes from?
What if we don’t free? struct Point *p; int pointSize = sizeof(struct Point); int i; for (i = 0; i < 10000; i++) { p = malloc(pointSize); p->x = i % 1000; p->y = i % 500; printf("p->x is %d\tp->y is %d\n", p->x, p->y); free(p); } No memory leak now What if we were to use p->x now? dangling reference (that’s bad) it might still be there, it might not (segmentation fault error possible)
We can dynamically construct arrays too • With malloc, we can request continuous blocks of memory right? • So a * will point to the front of the block • That can be the first index in an array • What can we put into arrays? • primitives • pointers to primitives (other arrays of primitives) • structs • pointers to structs
char* as an array char *text; text = malloc(sizeof(char) * 4); int i; for (i = 0; i < 3; i++) text[i] = (char)(65 + i); text[3] = '\0'; printf("text is %s\n", text); Output: text is ABC
Pointers to Pointers (for 2D arrays) char **text2; text2 = malloc(sizeof(char*) * 2); text2[0] = malloc(sizeof(char) * 4); for(i = 0; i < 3; i++) text2[0][i] = (char)(i + 65); text2[0][3] = '\0'; printf("text2[0] is %s\n", text2[0]); text2[1] = malloc(sizeof(char) * 6); for(i = 0; i < 5; i++) text2[1][i] = (char)(i + 68); text2[0][5] = '\0'; printf("text2[1] is %s\n", text2[1]);
Array of structs struct Point *points; int numPoints = 5; points = malloc(sizeof(struct Point) * numPoints); int i; srand(time(NULL)); for (i = 0; i < numPoints; i++) { points[i].x = rand() % 1000; points[i].y = rand() % 1000; printf("points[%d] = (%d,%d)\n", i, points[i].x, points[i].y); } bash-2.05$ ./StructArraysTester points[0] = (597,209) points[1] = (41,800) points[2] = (464,96) points[3] = (59,892) points[4] = (418,231)