• Pointer usage?
    21 replies, posted
  • Ok guys so now that I'm quite good at c#, I want to learn c++ and, as far as I can see it's quite easy for me to learn because I know c# already and they both are quite similar, BUT: Now I understand what pointers are, they are basically the memory address of a variable, right? But I just don't get what purpose they serve? Why not just access the variable itself directy? Why do it through a pointer? So I haven't read that much tutorials and books about c++ but that is a question that really is a worry to me... So uhm, could you guys tell me the purpose of pointers since I am used to c# and never really used pointers before. Oh and, I haven't coded a single c++ program, I'm just wondering... And please don't flame me if that question sounds noobish to all you l33t c++ coders ;)
  • [QUOTE=s0ul0r;16803426]Why not just access the variable itself directy? Why do it through a pointer[/QUOTE] 1. Duplicates eat valuable memory. [cpp]struct FSCKING_HUGE { int OMGWTF[100000000]; } void LOL(struct FSCKING_HUGE ASDF) { prinf("%d\n", ASDF.OMGWTF[0]); } [/cpp] LOL() will create a duplicate FSCKING_HUGE struct on the stack, which is a complete waste of precious resources. 2. Sometimes you need to modify the original value from a function with a different scope. [cpp] void swap(int* a, int* b) { int tmp; tmp = *a; *a = *b; *b = tmp; } [/cpp] It is impossible to implement this function without pointers. If you want to modify both "a" and "b", you must have their memory addresses. 3. You can't build advanced data structures without pointers. This is the big one. If you ever get really serious about programming, you'll be implementing trees, heaps, graphs, etc. practically non-stop. There's also some funky tricks you can do with pointer casting and arrays, but that's mostly C-style antics.
  • Pointers are used when you create objects on the heap (i.e. with "new") rather than on the stack (i.e. local variables within a function). You put things on the heap when you need them to last longer than the scope they're created in, since local variables are destroyed when they go out of scope. For example: [cpp] class MyClass { ... }; MyClass *createOne() { MyClass foo; // This instance is on the stack and will be destroyed when createOne() returns MyClass *bar = new MyClass(); // This instance is on the heap and exists until you delete it return bar; } int main() { MyClass *obj = createOne(); // This points to the actual object created above, not a copy // (Do stuff using obj here...) delete obj; // Destroy the object now that we're done with it } [/cpp] The heap is also used when you want to create an array whose size isn't known until runtime. Since the size of an object (struct or class) is fixed at compile time, any variable-sized data held by an object has to be allocated separately. For example, if you create a std::string, it'll contain an internal pointer to a char[] that it allocates with new() and deletes in its destructor. In C, pointers are also used for passing function parameters by reference, and that can be done in C++ too, but C++ has a better way of doing that (using references).
  • When you pass variables to a function in C or C++ (unless you explicitly use C++ references), it copies that value. This is true for structs and classes as well. Say we wanted to change a variable from another function: [cpp] #include <iostream> void foo(int var) { var = 1; } int main() { int a = 0; foo(a); std::cout << a << std::endl; return 0; } [/cpp] This will print "0" because when you pass "a" to the "foo" function, the value is copied, so the original variable "a" is left unchanged. This is the same as in C#, except for classes, they are passed by reference implicitly in C#. To achieve the wanted behaviour in C#, you'd use the "ref" or "out" keywords. In C++, you can use a pointer to achieve this: [cpp] #include <iostream> void foo(int *var) //Receive a pointer to an int { *var = 1; //Dereference pointer and set value to 1 } int main() { int a = 0; foo(&a); //pass address of a to foo std::cout << a << std::endl; return 0; } [/cpp] But the preferred C++ way is to use references (In C, you don't have these): [cpp] #include <iostream> void foo(int& var) //Receive a reference to an int { var = 1; //Set value referenced by var to 1 } int main() { int a = 0; foo(a); //pass a std::cout << a << std::endl; return 0; } [/cpp] References are better because they allow for a nicer, seamless syntax and they are a lot safer than pointers. References have a lot of restrictions on them (which is a good thing), so sometimes your only bet is to use a pointer. The general rule is; use pointers whenever you can't do it with references. There is a lot more to pointers than this, but this is the typical case. For classes and structs you also want to use pointers or references to make them work like you'd expect in C# (see above posts for more on this). [QUOTE=Wyzard;16803662]The heap is also used when you want to create an array whose size isn't known until runtime.[/QUOTE] In C99, you can create variable size arrays on the stack.
  • [QUOTE=jA_cOp;16803783]In C99, you can create variable size arrays on the stack.[/QUOTE] I thought about mentioning that, but wanted to keep my response relatively simple since it's a beginner question. You're right, though, so to fill in the details: variable-length arrays are part of C99, but not C++98; compilers may support them but it's a non-standard extension until C++0x is finalized. They can only be used for arrays that are local variables within a function, not member variables in a struct or class, and they can't be reallocated (e.g. to change their size).
  • instantiating things of variable size on the stack is discouraged. It doesn't inherently check for stack overflows, and it is a good way to trigger exceptions in your code.
  • Thanks guys, that helped me to understand pointers way better, and jA_cOp, your example really gave me an idea what they are used for, f.e. to modify variables directly in the memory when that would be impossible without pointers. :v:
  • Without pointers you can't have linked lists or trees or graphs or really [I]any[/I] cool and useful data structure.
  • Kind of a bump, but I have a quick question. In C, if you want to pass a string to a function and have the string be modified and returned without the return statement would you use a double pointer? I know char* is the same as char[], so you would pass a char** right? So something like this: [cpp] void modify(char** c, char** d) { *c = strcat(c, "a"); *d = strcat(d, "b"); } [/cpp]
  • [QUOTE=PvtCupcakes;16863734]I know char* is the same as char[][/QUOTE] It's not. Maybe I'm stupid - Why can't you do this? [cpp] void modify(char* c) { c = strcat(c, "a"); } [/cpp] Am I not understanding your question properly? I hardly even use C strings.
  • [QUOTE=gparent;16865230]It's not. Maybe I'm stupid - Why can't you do this? [cpp] void modify(char* c) { c = strcat(c, "a"); } [/cpp] Am I not understanding your question properly? I hardly even use C strings.[/QUOTE] Since char* can be used for strings, it's basically the same as char[]. So if I wanted to modify the memory allocated to the array, I think I'd have to use a pointer to the array, thus char**. I'm not sure though. :v:
  • char* [i]can[/i] be a pointer to an array. A pointer can be a pointer to anything, a int* could point to a 256 byte block of memory containing anything. The type of the pointer is only meaningful when dereferencing it.
  • Okay, let's drop the issue of char* being completely different from char[] for now. EDIT: Okay I get what you mean. If what you want to do is modify what a pointer *points to* from another scope, then you pass a pointer to pointer (because the pointer will be passed by value). Otherwise, this will happen: [cpp] void modifyPointedTo(int* ptr) { ptr = (int*) malloc(sizeof(int)); } int main() { int* iPtr; modifyPointedTo(iPtr); *iPtr = 0; } [/cpp] ptr gets passed by value, you assign to the copy of iPtr, memory gets leaked, and your pointer is still uninitialized.
  • [QUOTE=PvtCupcakes;16863734]In C, if you want to pass a string to a function and have the string be modified and returned without the return statement would you use a double pointer? I know char* is the same as char[], so you would pass a char** right? So something like this: [cpp] void modify(char** c, char** d) { *c = strcat(c, "a"); *d = strcat(d, "b"); } [/cpp][/QUOTE] Indeed that is what you'd do, except you don't pass a pointer-to-pointer to the strcat function. [QUOTE=PvtCupcakes;16865385]Since char* can be used for strings, it's basically the same as char[]. So if I wanted to modify the memory allocated to the array, I think I'd have to use a pointer to the array, thus char**. I'm not sure though. :v:[/QUOTE] A pointer to an array is written char* array[], while a pointer-to-pointer is written as char**. As arrays can be implicitly cast to pointers, it usually means your code will work the same either way, but you can't dereference an array (without indexing, which can be misleading if it's really just a pointer-to-pointer) without making a pointer out of it first (at which point receiving char** in your function makes more sense). Neither can you reassign arrays, as they are constant.
  • [QUOTE=PvtCupcakes;16865385]Since char* can be used for strings, it's basically the same as char[]. So if I wanted to modify the memory allocated to the array, I think I'd have to use a pointer to the array, thus char**. I'm not sure though. :v:[/QUOTE] That's actually because you only have a dword to push parameters on a stack to a function, so I'm guessing only primitives are really passed by value.
  • [QUOTE=HubmaN;16870910]That's actually because you only have a dword to push parameters on a stack to a function, so I'm guessing only primitives are really passed by value.[/QUOTE] Everything but arrays is passed by value in C, including structs. (And you can allocate more memory on the stack than the processor word size simply by incrementing the stack pointer. If push was the only way to allocate memory on the stack, you'd have some real nasty code for array and struct allocations.)
  • [QUOTE=jA_cOp;16876038]Everything but arrays is passed by value in C, including structs. (And you can allocate more memory on the stack than the processor word size simply by incrementing the stack pointer. If push was the only way to allocate memory on the stack, you'd have some real nasty code for array and struct allocations.)[/QUOTE] Oh, thanks. Explains why some people use pusha and popa instead of doing it manually, I suppose...
  • Now that we're on the topic of pointers, could someone please explain how I would derefence a pointer that is member of a struct? Like so [cpp] struct a { char *b; };[/cpp]
  • [QUOTE=gparent;16879707]The same way you dereference anything else. *(a.b)[/QUOTE] Ah, cool. This would explain the ridiculous amounts of pointer and value errors in my code. Thank you.
  • There's a lot of things you don't need in any language, but when it comes down to pointers I try to make things as clear as possible when giving examples. EDIT: And honestly I always look up * precedence, it drives me nuts.