C++ programming pointer declaration and basic use

  • 2020-05-07 20:13:20
  • OfStack

Declare the pointer with the following sequence.


[storage-class-specifiers] [cv-qualifiers] type-specifiers 
[ms-modifier] declarator ;

Any valid pointer declarator can be used with declarator. The syntax for simple pointer declarators is as follows:


* [cv-qualifiers] identifier [= expression]

1. Declaration specifier:
Optional storage class specifier.
Optional const or volatile keywords applied to the type of object to point to.
Type specifier: the type name that represents the type of the object to point to.
2. Declaration:
Optional Microsoft special modifier.

* operator.
Optional const or volatile keywords applied to the pointer itself.
Identifier.
Optional initializer.
The declaration of a pointer to a function is similar to the following:


(* [cv-qualifiers] identifier )( argument-list ) [cv-qualifers]
[exception specification] [= expression];

For pointer arrays, the syntax is as follows:


* identifier [ [ constant-expression ] ]

However, pointer declarators can be more complex.
Multiple declarators and their initializers may appear simultaneously in one declaration in a preceding comma-separated list of declarators.
A simple example of a pointer declaration is as follows:


char *pch;

The previous declaration specifies that pch points to an object of type char.
A more complex example is


static unsigned int * const ptr;

The previous declaration specifies that ptr is a constant pointer to an object of type unsigned int (with a static storage duration).
The next example shows how to declare and initialize multiple Pointers:


static int *p = &i, *q = &j;

In the previous example, the Pointers p and q both point to objects of type int and initialize to the addresses of i and j, respectively. The storage class specifier static applies to both Pointers.


// pointer.cpp
// compile with: /EHsc
#include <iostream>
int main() {
 int i = 1, j = 2; // local variables on the stack
 int *p;

 // a pointer may be assigned to "point to" the value of
 // another variable using the & (address of) operator
 p = & j; 

 // since j was on the stack, this address will be somewhere
 // on the stack. Pointers are printed in hex format using
 // %p and conventionally marked with 0x. 
 printf_s("0x%p\n", p);

 // The * (indirection operator) can be read as "the value
 // pointed to by".
 // Since p is pointing to j, this should print "2"
 printf_s("0x%p %d\n", p, *p);

 // changing j will change the result of the indirection
 // operator on p.
 j = 7;
 printf_s("0x%p %d\n", p, *p );

 // The value of j can also be changed through the pointer
 // by making an assignment to the dereferenced pointer
 *p = 10;
 printf_s("j is %d\n", j); // j is now 10

 // allocate memory on the heap for an integer,
 // initialize to 5
 p = new int(5);

 // print the pointer and the object pointed to
 // the address will be somewhere on the heap
 printf_s("0x%p %d\n", p, *p);

 // free the memory pointed to by p
 delete p;

 // At this point, dereferencing p with *p would trigger
 // a runtime access violation.

 // Pointer arithmetic may be done with an array declared
 // on the stack or allocated on the heap with new.
 // The increment operator takes into account the size 
 // of the objects pointed to.
 p = new int[5];
 for (i = 0; i < 5; i++, p++) {
 *p = i * 10;
 printf_s("0x%p %d\n", p, *p);
 }

 // A common expression seen is dereferencing in combination
 // with increment or decrement operators, as shown here.
 // The indirection operator * takes precedence over the 
 // increment operator ++. 
 // These are particularly useful in manipulating char arrays.
 char s1[4] = "cat";
 char s2[4] = "dog";
 char* p1 = s1;
 char* p2 = s2;

 // the following is a string copy operation
 while (*p1++ = *p2++);

 // s2 was copied into s1, so now they are both equal to "dog"
 printf_s("%s %s", s1, s2);
}

Output:


0x0012FEC8
0x0012FEC8 2
0x0012FEC8 7
j is 10
0x00320850 5
0x00320850 0
0x00320854 10
0x00320858 20
0x0032085C 30
0x00320860 40
dog dog

Another example shows how to use Pointers in data structures; The linked list is used in this example.


// pointer_linkedlist.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

struct NewNode {
 NewNode() : node(0){}
 int i;
 NewNode * node;
};

void WalkList(NewNode * ptr) {
 if (ptr != 0) {
 int i = 1;
 while (ptr->node != 0 ) {
  cout << "node " << i++ << " = " << ptr->i << endl;
  ptr = ptr->node;
 }
 cout << "node " << i++ << " = " << ptr->i << endl;
 }
}

void AddNode(NewNode ** ptr) {
 NewNode * walker = 0;
 NewNode * MyNewNode = new NewNode;
 cout << "enter a number: " << endl;
 cin >> MyNewNode->i;

 if (*ptr == 0)
 *ptr = MyNewNode;
 else {
 walker = *ptr;
 while (walker->node != 0)
  walker = walker->node;

 walker->node = MyNewNode;
 }
}

int main() {
 char ans = ' ';
 NewNode * ptr = 0;
 do {
 cout << "a (add node) d (display list) q (quit)" << endl;
 cin >> ans;
 switch (ans) {
 case 'a':
  AddNode(&ptr);
  break;
 case 'd':
  WalkList(ptr);
  break;
 }
 } while (ans != 'q');
}

Output:


* [cv-qualifiers] identifier [= expression]
0

fixed and variable pointer

The const and volatile keywords are used to change how Pointers are processed. The const keyword specifies that the pointer cannot be modified after initialization. The pointer is then protected against modification.
The volatile keyword specifies that the value associated with the followed name can be modified by actions other than those in the user application. Therefore, the volatile keyword is useful for declaring objects in Shared memory that can be accessed by more than one process or global data regions used to communicate with interrupt service routines.
If a name is declared as volatile, the compiler reloads the value in memory each time the program accesses the name. This significantly reduces the number of optimizations possible. However, this is the only way to guarantee predictable program performance when the state of an object can change unexpectedly.
To declare a pointer to an object as const or volatile, use the following declaration:


* [cv-qualifiers] identifier [= expression]
1

To declare the value of the pointer (the actual address stored in the pointer) as const or volatile, use the following declaration:


* [cv-qualifiers] identifier [= expression]
2

The C++ language prevents assignments to objects or Pointers declared as const from being allowed to change. Such assignments violate the intent of the original declaration by removing the information used to declare an object or pointer. Please consider the following statement:


const char cch = 'A';
char ch = 'B';

Assuming that two objects were previously declared (const char cch of type char and ch of type char), the following declaration/initialization will be valid:


* [cv-qualifiers] identifier [= expression]
4

There is an error in the following declaration/initialization.


* [cv-qualifiers] identifier [= expression]
5

The pch2 declaration declares that a pointer can be used to modify a constant object, so it is not allowed to be used. The declaration for pch3 specifies that pointer is a constant, not an object; This declaration is not allowed for the same reason that pch2 is not allowed.
The following eight assignments show assignments made with Pointers and changes to previously declared pointer values. Now, assume that the initialization of pch1 through pch8 is correct.


* [cv-qualifiers] identifier [= expression]
6

Pointers declared as volatile or a combination of const and volatile follow the same rules.
Pointers to const objects are commonly used in function declarations, as follows:


* [cv-qualifiers] identifier [= expression]
7

The previous statement declares the function strcpy_s, where two of the three arguments are type Pointers to char. Since the arguments are passed by reference rather than by value, the function is free to modify strDestination and strSource if strSource is not declared as const. Declaring strSource as const assures the caller that the called function cannot change strSource.
Pay attention to
Since there is a standard conversion from typename * to const typename *, it is legal to pass parameters of type char * to strcpy_s. But not the other way round; There is no implicit conversion to remove the const feature from an object or pointer.
An const pointer of a given type can be assigned to a pointer of the same type. However, Pointers of type other than const cannot be assigned to const Pointers. The following code shows correct and incorrect assignments:


// const_pointer.cpp
int *const cpObject = 0;
int *pObject;

int main() {
pObject = cpObject;
cpObject = pObject;  // C3892
}

The following example shows how to declare an object as const when there is a pointer to a pointer to an object.


* [cv-qualifiers] identifier [= expression]
9


Related articles: