C++ Programming/Operators/Pointers
Contents |
Pointers, Operator * [edit]
The * operator is used when declaring pointer types but it is also used to get the variable pointed to by a pointer.
Pointers are important data types due to special characteristics. They may be used to indicate a variable without actually creating a variable of that type. They can be a difficult concept to understand, some special effort should be spent on understanding the power they give to programmers.
Pointers have a very descriptive name. Pointers variables only store memory addresses, usually the addresses of other variables. Essentially, they point to another variable memory location, a reserved location on the computer memory. You can use a pointer to pass the location of a variable to a function, this enables the function's pointer to use the variable space, so that it can retrieve or modify its data. You can even have pointers to pointers, and pointers to pointers to pointers and so on and so forth.
Declaring [edit]
Pointers are declared by adding a * before the variable name in the declaration, as in the following example:
int* x; // pointer to int. int * y; // pointer to int. (legal, but rarely used) int *z; // pointer to int. int*i; // pointer to int. (legal, but rarely used)
Watch out, though, because the * associates to the following declaration only:
int* i, j; // CAUTION! i is pointer to int, j is int. int *i, *j; // i and j are both pointer to int.
You can also have multiple pointers chained together, as in the following example:
int **i; // Pointer to pointer to int. int ***i; // Pointer to pointer to pointer to int (rarely used).
Assigning values [edit]
Everyone gets confused about pointers as assigning values to pointers may be a bit tricky but if you know the basic you can proceed more easily. By carefully going through the examples rather than a simple description, try to understand the points as they are presented to you.
- Assigning values to pointers (non-char type)
double vValue = 25.0;// declares and initializes a vValue as type double double* pValue = &vValue; cout << *pValue << endl;
The second statement uses "&" the reference operator and "*" to tell the compiler this is a pointer variable and assign vValue variable's address to it. In the last statement, it outputs the value from the vValue variable by de-referencing the pointer using the "*" operator.
- Assigning values to pointers (char type)
char pArray[20] = {"Name1"}; char* pValue(pArray);// or 0 in old compilers, nullptr is a part of C++0X pValue = "Value1"; cout << pValue << endl ;// this will return the Value1;
So as mentioned early, a pointer is a variable which stores the address of another variable, as you need to initialize an array because you can not directly assign values to it. You will need to use pointers directly or a pointer to array in a mixed context, to use pointers alone, examine the next example.
char* pValue("String1"); pValue = "String2"; cout << pValue << endl ;
Remember you can't leave the pointer alone or initialize it as nullptr cause it will case an error. The compiler thinks it is as a memory address holder variable since you didn't point to anything and will try to assign values to it, that will cause an error since it does not point to anywhere.
Dereferencing [edit]
This is the * operator. It is used to get the variable pointed to by a pointer. It is also used when declaring pointer types.
When you have a pointer, you need some way to access the memory that it points to. When it is put in front of a pointer, it gives the variable pointed to. This is an lvalue, so you can assign values to it, or even initialize a reference from it.
#include <iostream> int main() { int i; int * p = &i; i = 3; std::cout<<*p<<std::endl; // prints "3" return 0; }
Since the result of an & operator is a pointer, *&i is valid, though it has absolutely no effect.
Now, when you combine the * operator with classes, you may notice a problem. It has lower precedence than .! See the example:
struct A { int num; }; A a; int i; A * p; p = &a; a.num = 2; i = *p.num; // Error! "p" isn't a class, so you can't use "." i = (*p).num;
The error happens because the compiler looks at p.num first ("." has higher precedence than "*") and because p does not have a member named num the compiler gives you an error. Using grouping symbols to change the precedence gets around this problem.
It would be very time-consuming to have to write (*p).num a lot, especially when you have a lot of classes. Imagine writing (*(*(*(*MyPointer).Member).SubMember).Value).WhatIWant! As a result, a special operator, ->, exists. Instead of (*p).num, you can write p->num, which is completely identical for all purposes. Now you can write MyPointer->Member->SubMember->Value->WhatIWant. It's a lot easier on the brain!
Null pointer [edit]
The null pointer is a special status of pointers. It means that the pointer points to absolutely nothing. It is an error to attempt to dereference (using the * or -> operators) a null pointer. A null pointer can be referred to using the constant zero, as in the following example:
int i; int *p; p = 0; //Null pointer. p = &i; //Not the null pointer.
Note that you can't assign a pointer to an integer, even if it's zero. It has to be the constant. The following code is an error:
int i = 0; int *p = i; //Error: 0 only evaluates to null if it's a pointer
There is an old macro, defined in the standard library, derived from the C language that inconsistently has evolved into #define NULL ((void *)0), this makes NULL, always equal to a null pointer value (essentially, 0).
Since a null pointer is 0, it will always compare to 0. Like an integer, if you use it in a true/false expression, it will return false if it is the null pointer, and true if it's anything else:
#include <iostream> void IsNull (int * p) { if (p) std::cout<<"Pointer is not NULL"<<std::endl; else std::cout<<"Pointer is NULL"<<std::endl; } int main() { int * p; int i; p = NULL; IsNull(p); p = &i; IsNull(&i); IsNull(p); IsNull(NULL); return 0; }
This program will output that the pointer is NULL, then that it isn't NULL twice, then again that it is.
Pointers and multi-dimensional arrays [edit]
- Pointers and Multi-Dimensional non-Char Arrays
This is tricky part and might be hard but relatively than next part we are going to talk about ,first of all you need to know at least how to use Two Dimensional Arrays /Assign Values to Arrays / Return Values from Arrays ,since this is reserved for Pointer I am not going to mention about Arrays separately but when Arrays needed it will mixed up with pointer
- The main objects are
- Assign Values to Multi Dimensional Pointers
- How to use Pointers with Multi Dimensional Arrays
- Return Values
- Initialize Pointers and Arrays
- How to Arrange Values in them
- Assign Values to Multi Dimensional Pointers.
In non-Char Type you need to involve arrays with Pointers cause since Pointers treat char* type to in special way and other type to another way like only refer the address or get the address and get the value by indirect method.
If you declare it like this way:
double (*pDVal)[2] = {{1,2},{1,2}};
It will probably generate an error! Because pointers used in non-Char type only directly, in char types refer the address of another variable by assigning a variable first then you can get its(that assigned variable)value by indirect way.!
double ArrayVal[5][5] = { {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, }; double(*pArray)[5] = ArrayVal; *(*(pArray+0)+0) = 10; *(*(pArray+0)+1) = 20; *(*(pArray+0)+2) = 30; *(*(pArray+0)+3) = 40; *(*(pArray+0)+4) = 50; *(*(pArray+1)+0) = 60; *(*(pArray+1)+1) = 70; *(*(pArray+1)+2) = 80; *(*(pArray+1)+3) = 90; *(*(pArray+1)+4) = 100; *(*(pArray+2)+0) = 110; *(*(pArray+2)+1) = 120; *(*(pArray+2)+2) = 130; *(*(pArray+2)+3) = 140; *(*(pArray+2)+4) = 150; *(*(pArray+3)+0) = 160; *(*(pArray+3)+1) = 170; *(*(pArray+3)+2) = 180; *(*(pArray+3)+3) = 190; *(*(pArray+3)+4) = 200; *(*(pArray+4)+0) = 210; *(*(pArray+4)+1) = 220; *(*(pArray+4)+2) = 230; *(*(pArray+4)+3) = 240; *(*(pArray+4)+4) = 250;
There is another way instead
*(*(pArray+0)+0)
it's
*(pArray[0]+0)
You can use one of them to assign value to Array through the pointer to return values you can use either the appropriate Array or Pointer.
- Pointers and multi-dimensional char arrays
This is bit hard and even hard to remember so I suggest keep practice until you get the spirit Pointers only.! You can't use Pointers + Multi Dimensional Arrays with Char Type. Only for non-char type.
- Multi-dimensional pointer with char type
char* pVar[5] = { "Name1" , "Name2" , "Name3", "Name4", "Name5" } pVar[0] = "XName01"; cout << pVar[0] << endl ; //this will return the XName01 instead Name1 which was replaced with Name1.
in here the 5 means of the first statement is the number of rows (there are no columns need to be specified in pointer it's only in Arrays) the next statement assigns another string to position 0 which is the position of first place of first statement. finally return the answer
- Dynamic memory allocation
In your system memory each memory block got an address so whenever you compile the code at the beginning all variable reserve some space in the memory but in Dynamic Memory Allocation it only reserve when it needed it means at execution time of that statement this allocates memory in your free space area(unused space) so it means if there is no space or no contiguous blocks then the compiler will generate and error message
- Dynamic memory allocation and pointer non-char type
This is same as assign non-char 1 dimensional Array to Pointer
double* pVal = new double[5]; //or double* pVal = new double; // this line leaves out the necessary memory allocation *(pVal+0) = 10; *(pVal+1) = 20; *(pVal+2) = 30; *(pVal+3) = 40; *(pVal+4) = 50; cout << *(pVal+0) << endl;
The first statement's Lside(left side) declares an variable and Rside request a space for double type variable and allocate it in free space area in your memory. So next and so fourth you can see it increases the integer value that means *(pVal+0) pVal -> if this uses alone it will return the address corresponding to first memory block. (that used to store the 10) and 0 means move 0 block ahead but it's 0 it means don't move stay in current memory block, and you use () parenthesis cause + < * < () consider the priority so you need to use parenthesis avoid to calculating the * fist
- is called INDIRECT Operator which DE-REFERENCE THE Pointer and return the value corresponding to the memory block.
(Memory Block Address+steps)
- -> De-reference.
- Dynamic memory allocation and pointer char type
char* pVal = new char; pVal = "Name1"; cout << pVal << endl; delete pVal; //this will delete the allocated space pVal = nullptr //null the pointer
You can see this is the same as static memory declaration, in static declaration it goes:
char* pVal("Name1");
- Dynamic memory allocation and pointer non-char array type
double (*pVal2)[2]= new double[2][2]; //this will add 2x2 memory blocks to type double pointer *(*(pVal2+0)+0) = 10; *(*(pVal2+0)+1) = 10; *(*(pVal2+0)+2) = 10; *(*(pVal2+0)+3) = 10; *(*(pVal2+0)+4) = 10; *(*(pVal2+1)+0) = 10; *(*(pVal2+1)+1) = 10; *(*(pVal2+1)+2) = 10; *(*(pVal2+1)+3) = 10; *(*(pVal2+1)+4) = 10;
delete [] pVal; //it doesn't matter the dimension you only need to mention [] pVal = nullptr
Pointers to classes [edit]
Indirection operator -> [edit]
This pointer indirection operator is used to access a member of a class pointer.
Member dereferencing operator .* [edit]
This pointer-to-member dereferencing operator is used to access the variable associated with a specific class instance, given an appropriate pointer.
Member indirection operator ->* [edit]
This pointer-to-member indirection operator is used to access the variable associated with a class instance pointed to by one pointer, given another pointer-to-member that's appropriate.
Pointers to functions [edit]
When used to point to functions, pointers can be exceptionally powerful. A call can be made to a function anywhere in the program, knowing only what kinds of parameters it takes. Pointers to functions are used several times in the standard library, and provide a powerful system for other libraries which need to adapt to any sort of user code. This case is examined more in depth in the Functions Section of this book.