C++ Fundamentals Question
#1
Posted 28 June 2005 - 08:08 AM
Variables are declared by setting them by type and name, then given values by assignment.
variable_type variable_name;
varable_name = value;
I understand this process very well, having grown up casually programming.
In C++, you can use the ampersand to look not at the variable, but at the memory address on the stack where the variable exists. To do this, most fundamental examples teach you to use pointers, which are variables that point to other variables.
variable_type variable_name;
variable_type *point_to_variable;
point_to_variable = &variable_name;
The only thing I don't understand is: why? Why use a pointer to a variable? Why not just modify the variable itself? Why point to a spot in memory and read what is on the stack, rather than dealing directly with the variables themselves?
This is one aspect of programming I've never really understood. When I get into actually doing the graphical side of programming, I'm going to more-or-less use triangles. A triangle is built by using a matrix of verticies: [ x1, y1, z1, x2, y2, z2, x3, y3, z3 ]. When these get moved around, rotated, and so forth - shouldn't I just be modifying the values themselves?
If anyone can provide a practical example and/or basic reasoning, I would greatly appreciate it. It is difficult for me to work without context and examples.
Many thanks,
-Kryogen
#2
Posted 28 June 2005 - 09:53 AM
Anyways, why are pointers used? Good question, here are some reasons:
1)Efficiency
Saves memory, runs faster, since it does not have to copy data (IE, function parameters)
2)Pointers can be used for strings, arrays, etc...
Ever use myArray[100] or something similar?
Try doing *(myArray+50) and see what comes up :-)!
myArray is essentially a pointer to the first block of memory where the data is stored, so the "+50" is essentially giving you the 50th index. Same thing for strings. Also, how would you pass on an array as a function parameter like a normal variable? You can't really, you have to use pointers. If you don't know how many elements will be in an array at compile-time, and need data from runtime (say, a value input by the user), how do you think you would do it?
3)Function parameters
Given:
void function(int data)
{ data+=5;
}
And the following:
int blob(0);
function(blob);
cout << blob;
What answer do you think you will recieve? It should display 0. To make it display 5, you could call "function(&blob);" instead, and modify the function appropriately for pointers.
So, there you have it, pointers are good for you =)
[Edit: Typo]
#3
Posted 28 June 2005 - 04:14 PM
In addition to this, pointers are useful for creating certain kinds of data structures. Consider the following:
struct MyStruct
{
int some_data;
MyStruct *next;
};
This allows you to have a single instance of MyStruct, which contains a pointer to another instance, which points to another one, and so forth (the last one has its pointer set to NULL). You have to use a pointer here; you can't just have a variable of type MyStruct inside MyStruct, because it would cause an infinite recursion.This data structure is called a linked list. It is similiar to an array in that they are both a (potentially large) list of pieces of data of the same type - but linked lists are more flexible because they can grow and shrink at run-time, and items can be inserted/removed very easily. (Compare this to an array - to grow or shrink it, you'd have to reallocate the memory and copy it all over to the new place every time you wanted to change the size!)
Linked lists are not the only data structures that can be created with pointers - you can also do more exotic things such as trees, graphs, tables, whatever you can imagine.
#4
Posted 28 June 2005 - 09:43 PM
Actually you brought up my next question. During my studies, this whle "new" thing. I don't get it.
int *blah = new int;
Why?
Doesn't "int blah;" work just as good?
From what I understand, it creates a pointer to a new integer value on the stack. But, during a function call, if the variable is created locally, wouldn't it be dynamic anyway? As in be constructed when it beings, and torn down when the function ends?
Regards,
-Kryogen
#5
Posted 28 June 2005 - 10:34 PM
there is less memory wasted this way in case some images are really small and you will never run into the problem that an image is actually too big and blows your image buffer.
of course there is a downside to this. variables on the stack have a well defined lifetime. once the function they were declared in returns they get poped off the stack and are gone. with dynamic memory you need to free that memory yourself, which as you can imagine is often forgotten.
void foo(){
// after this ptr points to an array of 100 integer elements
int* ptr = new int[100];
// ...do some stuff...
// here the function returns and the pointer gets poped off the stack
// but not the data it pointed to so if you didn't delete the data between here
// and it's allocation the pointer will be lost and there is no way you can free
// the memory. if foo is called in a loop bad things are going to happen !
}
#6
Posted 29 June 2005 - 02:21 AM
#7
Posted 29 June 2005 - 08:27 AM
Being a complete and total newbie, I can only halfway understand what you guys are talking about. I'm going to be going through my 7-in-1 C++ For Dummies book (almost done with the first of the seven books) and through http://www.cplusplus.com tutorials. Hopefully I will then be able to understand what you guys mean in a little more light.
I apologize for asking such mundane, elementary questions. We all have to start somewhere. :) That being said, again, I really appreciate the help.
--
Again, I ask... why not use variables directly, rather than point to their memory location?
Case in point one - I need to modify the value of something.
void add_one(int* ptr) { return ptr++; }
This I understand and can see the value of using a pointer. You want to modify the variables themselves being sent to the function from where the call came from.
int main() { int x(0); add_one(x); cout << x; return 0; }
In this case "x" actually gets incremented by one, rather than staying zero.
But this is the only example I can think of where it has any use. Break it down for me like this...
Let's say you have a structure for an RPG character. Your character has a certain constitution rating. You boot up the game and load your saved game, and during that process your characters statistics load.
Are you not just loading the character into some sort of global object that is persistant throughout the lifecycle of the game itself?
Why not just access the variables in the structure directly?
If NPCs need to be loaded who also have structures, wouldn't you have to load them all at once anyway, so long as they were in the same "zone" or map as you were?
In your tree reference, wouldn't you have to load every tree simultaneously, regardless of placement on the map or if they are in your current clipping plane/view?
In these cases, it to me, makes more sense to load everything statically into memory. I don't understand dynamic loading of structures (objects one can see visually, like a tree or an NPC). Then again, I'm ignorant, so...
:)
-Kryogen
#8
Posted 29 June 2005 - 08:32 AM
So in other words, you have a data structure you are loading for object "Tree". You load the tree object, complete with all the verticies necessary for rendering the tree properly. I think what you mean is that instead of having each tree load it's own object into memory, you simply say "me? Oh I'm that tree over there. No need to load new information, just replicate that data there.".
Does this not still consume memory when you create a new object to be rendered?
#9
Posted 29 June 2005 - 01:35 PM
You want to load a model from a file, to render it in your game.
You have code which loads 3ds files, and use it to load your various models.
However, when you are loading a file, you don't know how many verticies (or texture coordinates or whatnot) there will be. So, the only way to go around this is to dynamically allocate an array at run time.
So, you ask, why not use Verticies[number_of_verticies_here]? Well, you want the same code to be able to load all 3ds files, and not just one example, no? Also, arrays like Vertex[100] are statically allocated, so you cannot have something like this:
-Read Number_of_verticies from file car.3ds
float bob[Number_of_vertices];
This is because the compiler needs to _know_ what the size of arrays/strings are if they are static.
Another thing about pointers is that they are fast. When you pass on a regular variable as a function parameter, the computer actually copies the variable into a new segment of memory as a local variable, not to mention that all changes to it are lost. My previous post details several other useful reasons for using pointers, as well as more information on arrays.
I hope this clears things up a bit.
#10
Posted 29 June 2005 - 04:02 PM
#11
Posted 30 June 2005 - 04:20 PM
Let's use strings instead! Assume CString is a class wrapper for strings.
Class CString; ... something like that...
CString myString = "Here is a fairly short"; // All is good so far.
Now let's say we want to append "string." to myString. Without pointers we have:
CString append(CString first, CString second) {
return first + second; // Assume + overload is already implemented.
}
// Then we make the call later like so:
myString = append(myString, CString("string."));
Ok. There is nothing technically wrong with this code. How many copies of strings were made? Well, since we passed all of the parameters by value, and returned by value, the compiler makes copies every time the data moves into the function or back.
Summary of unique strings created by the above code:
myString -> "This is a short"
first -> "This is a short"
CString -> "string."
second -> "string."
implicit return value -> "This is a short string."
returned copy -> "This is a short string."
myString assigned -> "This is a short string."
Lots of duplicates here. Additionally, myString was not directly changed, instead its old value was thrown away, and another copy was made.
For short strings, this may be the easiest implementation. Let's pretend that each string is a book instead... about 64MB or so. Now myString is huge! So, even appending the words, "The end!" to the string is going to require about 64*5 or 320MB of data - most of it being copied for no reason.
Let's revisit the append function. This time we make it a member of CString and use pointers instead:
CString* CString::append(CString* val) {
mString += val->mString;
return this; // This is a trick for passing the function as an argument.
}
// And later the call...
CString theend("The End!");
myString.append(&theend);
Now assuming CString is a good implementation, we only copy theend to the end of the string pointed to by myString. The string in myString is *never* copied anywhere. So if it is 64MB, we don't really use any more memory - or make any more copies. (STL has an implementation of string that works pretty well).
Hope this is straightforward.
#12
Posted 01 July 2005 - 02:37 AM
The jist I am getting is that, basically, using pointers that point to a variable already on the stack saves a lot of memory. If you pass by value (string1,2,3, or integer1,2,3) the function creates its own local copies / values and that takes up memory. Now in the example of a string, I can understand easily the example you gave (although the actual code I haven't gotten familiar with yet, but I will be).
Not to beat the thread to death, but I do have another question, unrelated to thee above information: Header wrappers.
The dummies book glosses over the subject, and I haven't found much online to help me either (even on cplusplus.com). It has something to do with having the include files loaded multiple times and causing problems. Anyone care to give me a little bit better explaination than the book?
If not, we can let the thread die. :)
Appreciated.
-Kryogen
#13
Posted 01 July 2005 - 03:48 AM
As for your question about header wrappers, that is fairly simple. Suppose that you had a header called "vec3.h" defining a class called "vec3" (a three-dimensional vector). Now suppose you have two more headers, "class1.h" and "class2.h", defining class1 and class2. Both of these classes include a member variable of type vec3, so you must include vec3.h in each header file:
// vec3.h
struct vec3 { float x, y, z };
// class1.h
#include "vec3.h"
class class1 {
vec3 foo;
// other stuff
};
// class2.h
#include "vec3.h"
class class2 {
vec3 bar;
// other stuff
};
Now what happens when you include both class1.h and class2.h into the same source file? The compiler sees the definition of vec3 twice - once when class1.h is included (and thus includes vec3.h), and once when class2.h is included (and thus includes vec3.h again). This causes a "duplicate definition" error.
There are various ways to solve this. For instance, you could make a rule that header files cannot include other header files. However, then anytime you wanted to include class1.h or class2.h in a source file, you would have to remember to also include vec3.h. If you have a lot of classes, this is a pain - you have to remember to include all the right files, and you have to do so in the right order.
Another way to solve the duplicate-definition problem is to use header wrappers. Basically, you use the preprocessor to ensure that if a header is included more than once, the second and later inclusions do not do anything.
The standard pattern for a header wrapper is:
// myheader.h #ifndef MYHEADER_H #define MYHEADER_H // normal header code goes here #endif
How does this work? Well, when the preprocessor is working on a source file, suppose it sees #include "myheader.h" for the first time, so it begins to process myheader.h. The #ifndef asks the preprocessor whether there is a symbol called "MYHEADER_H" defined. There is not, so the #ifndef evaluates true ("if not defined"). The first thing that happens is that "#define MYHEADER_H". Then all the normal header code is included.
Now suppose the preprocessor sees #include "myheader.h" a second time. Now, MYHEADER_H is defined, so when we hit the #ifndef, it evaluates false and jumps directly down to the #endif. All the header code is skipped; thus, no duplicate-definition errors occur.
Each header file uses a different symbol (usually the filename, with the .h changed to _H). Each source file is processed separately, so including a header in one source file doesn't cause it to be ignored in another source file.
Hope this answers your question - and feel free to post anymore you may have.
#14
Posted 01 July 2005 - 03:56 AM
Basically, it's a good idea to have something like:
#ifndef _INCLUDE_FILE_
#define _INCLUDE_FILE_
//here be something
#endif //_INCLUDE_FILE_
To wrap your include files, to make sure the stuff isn't defined multiple times (a big no-no). For example, try defining the same variable name twice, and you'll end up with some errors! Of course, the _INCLUDE_FILE_ name can be whatever name you want it to be (you will most likely want it to be different for each include file), although you'll likely want to keep some sort of convention for all your header files. The preprocessors are the stuff denoted by "#". Basically, these are all evaluated at compile-time, instead of at run-time.
If you're running MSVC, you can give something like the following a try (It will only include/read the file once during build):
#ifdef _MSC_VER
#if _MSC_VER > 1000
#pragma once
#endif
#endif
I hope this is what you were referring to. Preprocessors are really useful =)
Anyways, that must have been a pretty bad chopped up answer. Whatever, it's 1:00 AM and I have a midterm today ^^
[Edit: Reed beat me to it, with an even better explanation :-) ]
#15
Posted 01 July 2005 - 07:18 AM
Sorry to take up all your programming time with mundane questions. But I guess it's good to have a refresher every now and again for people to read. Not to mention help a noob. :)
Owe you guys.
-Zach
#16
Posted 08 July 2005 - 07:33 AM
I read the wiki @ http://www.devmaster.net/wiki/Languages_su...ting_games_with before I asked the question, like always, trying to do my homework before making a fool out of myself. Nevertheless, I was looking for some personal opinions here: Which do you prefer, and which is a better choice for starting from scratch and learning from the ground up? Does C# have better support through the DirectX SDK? Does it have better Windows platform support natively?
When I found out C# was free, and since it is the "new" thing, I figured since I'm still doing the fundamentals I might as well see about using it if it is a more powerful language.
Hope to hear from some of "y'all" (as we say in the south) soon.
-Kryogen
#17
Posted 08 July 2005 - 07:54 AM
opinions differ here as to what is the better way of learning programming. some people think that starting out with a lot of abstraction is good for focusing on algorithmic techniques first, without distracting you with language quirks. these people will tell you that you can always descend down to the system as you need to and will advise you to learn c at a later stage.
on the other end you will find those who believe that you need to start out with a very simple language syntax instead of abstraction. the arguement being that the closer you are to the machine when you start out the better you will understand how you computer really works, thus making you a better programmer.
both arguements have their merits and i've come to believe that it's largely a matter of personal preference. some people might be comfotable with starting at the abstract end and others might enjoy really working with the machine, neglecting object oriented programming, etc. at first.
#18
Posted 08 July 2005 - 05:29 PM
In my experience, C# and C++ really have different uses. Microsoft wishes all C++ programmers would migrate to C#, but it isn't going to happen for a while since each tool is suited to different tasks.
If I was asked to make a physics engine, or to work directly with opengl or directx, C++ is my preferred language - I really don't want to mess with the overhead, hassle, and occassionally limited interaction provided by C# - at least not for big projects.
On the other hand, if I need a quick set of testing tools with GUI, C# is wonderful and chops the time it would take using C++ by well over 50%! The C# environment has some really friendly RAD tools (for building windows, dialogs, buttons, etc). For C++, you either have to code everything by hand (takes a while and requires win32 knowledge) or you have to use MFC (let's hear a collective groan of dispair).
Your mileage may differ.
#19
Posted 21 July 2005 - 03:46 AM
#20
Posted 21 July 2005 - 05:08 AM
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users












