Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Pointers


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
9 replies to this topic

#1 Crusable   Members   -  Reputation: 594

Like
0Likes
Like

Posted 19 February 2012 - 02:06 PM

Hello,

I have been learning some c++ and realized that i have no freaking idea what a pointer is. I read through the book and i still dont quite understand. First it says you should use a referance rather than a poninter, so why use pointers than. and second, could someone please send me to mabye a video, book, or try explaining pointers to me in the noobiest fashion.

thanks for all your help :)

Sponsor:

#2 fastcall22   Crossbones+   -  Reputation: 5259

Like
-2Likes
Like

Posted 19 February 2012 - 02:18 PM

Using a pointer, you can describe the concept of "which object" at runtime. To access the object pointed to by a pointer, use the dereference operator (*), and use the address-of operator (&) on an object to make it "pointable":

int a = 3;
int b = 4;

// ptr is a pointer-to-an-int that doesn't yet point to an object
int* ptr = 0;

// make ptr point to either a or b (determined at runtime)
if ( rand() % 2 == 1 )
    ptr = &a;
else
    ptr = &b;

// modify the integer pointed to by ptr, which is either a or b
*ptr = 5;

// the output will either be
// 3 5
// or
// 5 4
cout << a << ' ' << b << endl;

A reference is an alias for an object -- and in most cases can be treated as a constant pointer (as in, the pointer cannot point to a different object) that cannot be null.

The code above using references can look something like this with similar output:
int a = 3;
int b = 4;

// a reference must be initialized when it is defined and cannot be reseated (see C++ faq lite link below)
int& ref = (rand()&1) ? a : b;
ref = 5;

cout << a << ' ' << b << endl;

There's also a turotial at cplusplus.com and a section about references on C++ FAQ Lite.

EDIT:
Washu has a point; I've edited my post to be less confusing. (And to save face.)

Edited by fastcall22, 19 February 2012 - 05:34 PM.

QWxsIHRvYXN0LXRvYXN0aW5nIHRvYXN0ZXJzIGNhbiB0b2FzdCB0b2FzdGVkIHRvYXN0LCBhbHRob3Vn aCByZS10b2FzdGluZyB0b2FzdGVkIHRvYXN0IGlzIGdlbmVyYWxseSBub3QgcmVjb21tZW5kZWQgYnkg dGhlIG1hbnVmYWN0dXJlcnMgb2YgdG9hc3QtdG9hc3RpbmcgdG9hc3RlcnMuLi4=

#3 blackbook   Members   -  Reputation: 110

Like
0Likes
Like

Posted 19 February 2012 - 02:20 PM

I dont know C++ howver I know they are in C#.

Surely a search of "Pointers in C++" will yield the webpage though.

#4 Memories are Better   Prime Members   -  Reputation: 769

Like
0Likes
Like

Posted 19 February 2012 - 02:22 PM

When I was learning about pointers in C I often had this thought of variables or whatever the pointer was pointing to being houses which would require a lot of effort to move and a pointer being some guy on skates with a stick where you would order him to go point at an 'address' then bring him back, naturally this would be faster than bringing the house (address) back and forth.

Pointers have many uses, I sadly didnt read too much into C++ to care much for them, especially when references popped up, from what I believe it is much cheaper to use a pointer to get information (or change) than the actual object, however when to use them instead of references, that I dont know

#5 BSt   Members   -  Reputation: 102

Like
-2Likes
Like

Posted 19 February 2012 - 03:17 PM

Posted Image
Numbers on the right side of picture are memory addresses.

int b = 15; // Object
int * a = NULL; //Pointer

a = &b; //We use (&) to get address of (a) object.

Try to output in console: &b, b, &a, a, *a.

{...}
(( I am learning English. ))

#6 Washu   Senior Moderators   -  Reputation: 6644

Like
-1Likes
Like

Posted 19 February 2012 - 03:31 PM

A pointer is an unsigned integer (32-bits or 64-bits), that literally holds an address of memory.

No. Just no. Pointers are not integers, and don't ever mistake the conceptual machinations of imagining memory addresses as numbers to mean that they are simply "integers". They aren't. Heck on some machines they aren't even a single "integer", hello segmentation. This misconception is why so many people fail this quiz. The links were good though.

It should help you, pointer "stores" a address to another object. It is faster. Also, We use them to create a new objects using (new).

A pointer simply describes an object whose value provides a reference to an object of the referenced type. Its not "faster", that doesn't even make sense. Faster than WHAT?

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
ScapeCode - Blog | SlimDX


#7 BSt   Members   -  Reputation: 102

Like
0Likes
Like

Posted 19 February 2012 - 03:40 PM

A pointer is an unsigned integer (32-bits or 64-bits), that literally holds an address of memory.

No. Just no. Pointers are not integers, and don't ever mistake the conceptual machinations of imagining memory addresses as numbers to mean that they are simply "integers". They aren't. Heck on some machines they aren't even a single "integer", hello segmentation. This misconception is why so many people fail this quiz. The links were good though.

It should help you, pointer "stores" a address to another object. It is faster. Also, We use them to create a new objects using (new).

A pointer simply describes an object whose value provides a reference to an object of the referenced type. Its not "faster", that doesn't even make sense. Faster than WHAT?

Fast than hell... I meant, useful in functions, powerful etc.Maybe I overcoloured using this word.
(( I am learning English. ))

#8 Destri   Members   -  Reputation: 100

Like
0Likes
Like

Posted 19 February 2012 - 04:18 PM

A pointer holds a memory address. You can expand that analogy into meaning that the pointer is like an arrow that points you to where you can find something.

If you know how classes work, say you're modeling a kind of store:
Spoiler


#9 SimonForsman   Crossbones+   -  Reputation: 6703

Like
0Likes
Like

Posted 19 February 2012 - 06:24 PM

Hello,

I have been learning some c++ and realized that i have no freaking idea what a pointer is. I read through the book and i still dont quite understand. First it says you should use a referance rather than a poninter, so why use pointers than. and second, could someone please send me to mabye a video, book, or try explaining pointers to me in the noobiest fashion.

thanks for all your help Posted Image


Simply put, a pointer variable is a variable that points at another variable or object.
a reference variable is a variable that holds a reference to another object.

They are similar but with a few important differences:

1) You can directly manipulate pointers or reassign them.

2) References always point to an object and cannot be reassigned once created, pointers can be null or point to complete garbage (unallocated or deallocated memory for example).

Thus references are far harder to screw up with, as you have to initialize the reference when it is created it is fairly tricky to get a reference to an invalid object (It can be done by for example having a heap allocated object that takes a reference variable in its constructor but that requires that you use a pointer for the heap allocated object anyway).

Thus since references are pretty darn difficult to mess up with they should be prefered unless you need to use a pointer. (If you don't use pointers at all then i can't think of a way to mess up references either (If there is a way to mess it up anyway i'm sure someone will point it out :) ))

in C++11 you also have unique_ptr , shared_ptr and weak_ptr which are preferable to raw pointers in most situations. (usually unique_ptr should be prefered but there are situations where shared_ptr and weak_ptr can help).

The only time when raw pointers are necessary is when:
1) You need to do pointer arithmetics.
2) There is a significant performance overhead if using smart pointers. (unique_ptr shouldn't have any overhead and the overhead you get with shared and weak pointers is pretty irrelevant unless you abuse them)
I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

#10 rip-off   Moderators   -  Reputation: 9557

Like
1Likes
Like

Posted 20 February 2012 - 06:27 AM

I believe the question is better answered by demonstrating what pointers do.

There are a couple of common reasons to use pointers:
  • Optional semantics
  • Pass without copy
  • Write to a object outside the current scope
  • Create an object that must exist outside its current scope
  • Variable length data
Let us look at each in turn.

Optional semantics


The first is simple. We have a function, and one or more parameters are "optional", that is the function has meaningful behaviour even if the parameter is omitted. Let us imagine you want to write a function that turns a string into an integer. Sometimes, when the string is not an integer, you want to report that as a critical error. Other times, you are happy enough to go with a default - you want to pass that in and have it returned.

One way to write that is to have two implementations, one with a parameter indicating the default:
int tryParseInt(std::string string) {
	std::stringstream stream(string);
	int result;
	if(stream >> std::ws && stream >> result && stream >> std::ws && stream.eof()) {
		return result;
	}
	throw std::runtime_error("Failed to parse " + string + " as integer");
}


int tryParseInt(std::string string, int defaultValue) {
	std::stringstream stream(string);
	int result;
	if(stream >> std::ws && stream >> result && stream >> std::ws && stream.eof()) {
		return result;
	}
	return defaultValue;
}
Now, we have duplicated the essential logic here.

Another way of implementing this is to have the logic written once, and use a pointer parameter for the "defaultValue". If the pointer is null, then there is no default and we throw an exception.

namespace {
	int tryParseInt(std::string string, int *defaultValue) {

		std::stringstream stream(string);
		int result;
		if(stream >> std::ws && stream >> result && stream >> std::ws && stream.eof()) {
		   return result;
	   }

	   if(defaultValue) {
		   return *defaultValue;
	   }
	   throw std::runtime_error("Failed to parse " + string + " as integer");
	}
}

int tryParseInt(std::string string) {
	return tryParseInt(string, nullptr);
}


int tryParseInt(std::string string, int defaultValue) {
	return tryParseInt(string, &defaultValue);
}
Now we only have one function which needs to worry about how to parse strings, and it is configurable in how it deals with errors. Here I have presented it as a hidden helper function. I'm not necessarily advocating this as the most appropriate solution here, I'm just trying to give a simple example of an "optional" parameter.

This idea of optionality can also apply to member variables. Consider a simple Guard Ogre class. If it has seen a Player, it must chase them. If it has not, then it must walk around search for a Player, or some other edible morsel. One implementation is to treat the currently chased player as an optional member. We can again use a pointer to indicate this.

We might write:
class OgreGuard {
public:
	void update() {
		if(!player) {
			player = trySeePlayer();
		}

		if(player) {
			chase(*player);
		} else {
			searchForPlayer();
		}
	}

private:
	// ...
	Player *target;
};
Again, there are other solutions.

In all cases, we are relying on the null pointer to provide a special value that can be tested for to indicate the presence of a value.

Pass without copy


Let us imagine we have a lot of data in our program - a container with millions of elements for example. A simple example might be searching this container for a given element, returning the index on success and a negative value on failure.

A naive implementation might copy the elements into the function, and then do a linear search on the copy:
int searchCopy(std::vector<int> v, int value) {
	for(int i = 0 ; i < v.length() ; ++i) {
		if(v[i] == value) {
			return i;
		}
	}
	return -1;
}

An alternative to passing a copy is somehow allow the function to see the original data. We can do this with a pointer or reference:

int searchPointer(const std::vector<int> *v, int value) {
   if(!v) {
	   // TODO: what to do if passed NULL?
   }

	for(int i = 0 ; i < v->length() ; ++i) {
		if((*v)[i] == value) {
			return i;
		}
	}
	return -1;
}


int searchRef(const std::vector<int> &v, int value) {
	for(int i = 0 ; i < v.length() ; ++i) {
		if(v[i] == value) {
			return i;
		}
	}
	return -1;
}
Note that the searchRef looks almost identical to the searchCopy, with the added bonus that it avoids copying. Sweet! Also note that searchPointer has a corner case: how should it handle being passed NULL?

Finally, note that by using "const" the compiler will warn us if we accidentally try to change the vector. We will see why this is a problem below.

Write to a object outside the current scope


Now imagine we want to reverse strings. Like in the above case, the string might be very long. Again, the naive implementation might return a freshly reversed string:
std::string reverse(const std::string &input) {
	std::string result;
	for(int i = input.size() - 1 ; i >= 0 ; --i) {
		resut.push_back(input[i]);
	}
	return result;
}
However, we often don't care about the original order of the data, we just want it reversed. The naive implementation forces us to have both the original data and the reversed copy in memory, at least during the sorting process.

One approach is to instead reverse the data "in place". That is, instead of returning a fresh, sorted container, we simply re-arrange the elements in the original data. We can do this with a pointer or reference:

void reverseRef(std::string &string) {
	int length = string.size();
	for(int i = 0 ; i < length / 2 ; ++i) {
		std::swap(string[i], string[length - i - 1]);
	}
}


void reversePointer(std::string *string) {
	if(!string) {
		return;
	}

	int length = string->size();
	for(int i = 0 ; i < length / 2 ; ++i) {
		std::swap((*string)[i], (*string)[length - i - 1]);
	}
}
Again, we note that using a pointer here is uglier and introduces a special case where the input is NULL.

Note that this approach retains flexibility, because if the caller does care about the original order, they can always make a copy themselves and ask our function to sort this new copy in place:
int main() {
	std::string original = readFile("reallyBigFile.txt");
	std::string copy = original;
	reverseRef(copy);
	// Use reversed copy...
}

Create an object that must exist outside its current scope


In C++, any automatically allocated objects exist in a given scope. For function local objects, once the function ends they are destroyed. We can only copy them out of the function. Sometimes, a copy isn't sufficient. Some objects are not copyable (e.g. file streams, sockets, in fact most OS level resources have no intuitive copy semantics). What would a copy of std::cin be? In other cases object "identity" is important, as distinct from the object's values. In these cases, we can use new to allocate memory and create an object for us. This memory exists in a separate space to the automatic allocations, which means that when the function returns this memory is still valid. We receive a pointer to this memory.

We can return this pointer to calling functions, or possibly pass this pointer into a function which stores it (e.g. push_back the pointer into a vector). Conversely, if we do not store or return the pointer, we must de-allocate it, because when we return from the function the memory will not be cleaned up automatically.

Variable length data


Imagine you want to read data from a file, or the console, but you don't know how much there is in advance. Also, you do not have access to the standard library for some reason (yes, it is contrived =P).

Again, the naive approach is to use a "really big" array, and hope that you never are asked to read more data than that.
int main() {
	const int MAX = 1000; // Surely enough???
	int array[MAX];

	int index = 0;
	while(std::cin) {
		if(index == MAX) {
		   std::cerr << "Sorry bud, out of luck. This program supports up to " << MAX << " numbers.\n";
		   return 1;
		}

		if(std::cin >> array[index]) {
			++index;
		}
	}

	// Use the data
}
We can trivially see that if we enter 1001 numbers into this program, it cannot handle it.

However, another approach is to dynamically allocate the variable length data:

int main() {
	int allocated = 1000;
	int *data = new int[allocated];

	int index = 0;
	while(std::cin) {
		if(index == allocated) {
			int more = allocated * 2;
			int *pointer = new int[more];
			std::copy(data, data + allocated, pointer);
			std::swap(data, pointer);
			delete [] pointer;
			allocated = more;
		}

		if(std::cin >> data[index]) {
			++index;
		}
	}

	// Use the data
}
This is bascially what std::string and std::vector do under the hood.

 
Some of these are advanced concepts, and you might not have come across them yet.

Please note I have not tested any of the above code, it is just for illustration.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS