C++. Pointers. Part 2. Unmanaged pointers. Operations on pointers. Pointer to type void. Memory allocation. A null pointer. The operation of getting the address &




Pointers. Part 2. Unmanaged pointers. Operations on pointers. Pointer to type void. Memory allocation. Keywords NULL and nullptr. The operation of getting the address &

This topic describes how to work with unmanaged pointers. As you know, Visual C++ also supports managed pointers.

General information about the pointers, types of pointers are detailed in the topic here.


Contents


Search other websites:

1. Which operators can be used with unmanaged pointers?

Over unmanaged pointers two operators are used:

  • * – is intended for accessing a variable, which is located at the address, which is specified by the operand of this operator. This operator refers to the value of the variable, which is recorded in the pointer. This is a unary operator, in which the operand is placed on the right;
  • & – returns the memory address of the operand located on the right. This is a unary operator.

Operators * and & complement each other.

For example. A pointer named px refers to a variable x of a real type. Suppose that we have the following description:

float x;
float *px; // Pointer to a variable of real type
px = &x;   // px points to x

The value *px is the value of the variable x, which is shown by the following line

*px = 25; // x = 25.0

The value of px is the address of the variable x in the RAM.

C++ pointer variable figure

Figure 1. Pointer px points to the variable x

2. What is an indirect access operation with a pointer?

The indirect access operation is access to a variable (object) using a pointer. Using the pointer, you can access arrays of variables (objects).

The word “indirect” means that you can access the value of a variable using another variable.

3. How does the C++ compiler determine the amount of information that the pointer points to?

The amount of information processed is determined by the base type of the pointer.

Example. Let the following description be given:

double * pf;

The basic type of the pointer is double. One variable of type double occupies 8 bytes in the computer’s memory. Therefore, the C++ compiler will process 8 bytes of information when accessed by the pointer.






4. The operation of assigning pointers. Example

The value of one pointer can be assigned to another, provided that they have the same base type (they are pointers to the same data type).

If pointers point to different types of data, then the type cast operation operates. In this case, working with the pointer is unpredictable and can lead to invisible logical errors (or maybe not).

Example.

// assignment of pointers
int a = 5;         // ordinary variable
int * pi1 = &a; // Initializing the pointer with the address of variable a
int * pi2;     // pointer to int
double * pi3;   // pointer to double

pi2 = pi1;     // acceptably
//pi3 = pi1; // error! - "cannot convert from int to double"
pi3 = (double *) pi1; // it works - the type cast operation

5. Arithmetic operations on pointers. Changing the physical address of the pointer. Examples

You can perform the following arithmetic operations with pointers:

  • increment ++ and decrement operations;
  • addition + and subtraction operations.

Pointers can be used in expressions.

When changing pointer values using arithmetic operations, physical address of pointer is changed by the formula:

N * sizeof(type)

where

  • N – a constant that indicates the change (increase / decrease) in the value of the pointer;
  • type – The type of data pointed to by the pointer (the base type of the pointer);
  • sizeof(type) – an operation that determines the size of the data type.

Example 1. Changing the pointer value.

// increasing / decreasing the pointer value
int a = 5;     // ordinary variable
int * pi1 = &a; // Initializing the pointer with the address of variable a
int * pi2;     // pointer to int

pi2 = pi1;     // point to the same memory address
pi2++;         // physical address of pi2 is 4 bytes greater than the address pi1

In the above example, the physical address of pointer pi2 is more by 4 bytes from the physical address of pointer pi1. This is due to the fact that int (the basic type of pointers pi1 and pi2) is 4 bytes in size (Win32 environment).

Example 2. Changing the value of a pointer to type double.

// increasing / decreasing the pointer value
double x = 3.55;   // ordinary variable of type double
double * p1 = &x; // initializing the pointer with the address of variable a
double * p2;     // pointer to double

p2 = p1-4;   // the physical address p2 is 32 bytes smaller than the address p1
p2 = p1 + 2; // the physical address p2 is 16 bytes greater than the address p1

6. What kind of relation operations (comparisons) can be performed with pointers?

Pointers can be compared. For comparing pointers, the operations ==,>, < are used.

When comparing pointers, it is important that these pointers have some connection with each other.

For example, if pointers point to different unrelated variables, then the comparison operation does not make sense.

In the event that pointers point to variables between which there is some relationship, the result of the comparison makes sense. This can be the case where pointers point to elements of the same array.

Example. Let the array of real numbers A and 2 of the pointer be given.

// Comparison of pointers
float A[20]; // array of 20 real numbers
float *pa1, *pa2; // two pointers to "float"
bool f_res; // Result of pointers comparison

// ...
pa1 = &A[5]; // Points to the 5th element of the array
pa2 = &A[8]; // Points to the 8th element of the array

f_res = pa1==pa2; // f_res = false
f_res = pa1>pa2; // f_res = false
f_res = pa1<pa2; // f_res = true

7. What are the features of using a pointer to a void type?

C++ allows you to use a pointer to void type. The pointer to type void has its own peculiarities. This means that a pointer to type void is a universal pointer that can be set to any type of value, including zero. The keyword void gives information for the compiler that there is no data about the size of the object in memory.

To set the void pointer to a pointer of another type, you need to use the cast operation.

Example. Using a pointer to type void to access variables of different types.

// pointer to 'void' type
void * p;
int d;
float x;
char c;

d = 5;
x = 2.58f;
c = 'A';

p = (int *)&d; // p points to d
*(int *)p = 8; // d = 8

p = (float *)&x; // p points to x
*(float *)p = -8.75; // x = -8.75

p = (char *)&c; // p points to c
*(char *)p = 'r'; // c = 'r'

8. How set the pointer to zero value? Keywords NULL and nullptr. Example

There are cases when a pointer needs to be set to zero. This is necessary to set the value of the pointer to something that does not match any of the pointers that are used in the program.

In the <stdio.h> module, a NULL constant with a zero value is defined. It can be used to assign a null value to a pointer.

You can also use the nullptr pointer to set a null pointer, which is less vulnerable to misuse and performs better in most cases (see example 2).

Example. Assigning a zero value to a pointer.

#include <stdio.h>

...

// null pointer
int * p;
p = nullptr; // Works
p = NULL; // Works, the constant NULL is defined in the module <stdio.h>
p = 0;    // it works
p = 0x00; // also works

Example 2. A case where it’s better to use nullptr instead of NULL.

#include <iostream>
using namespace std;

void func(std::pair<const char*, double> pr)
{
  // ...
}

void main()
{
  // Doesn't work - compilation error
  //func(make_pair(NULL, 3.14)); // NULL => 0 => int

  // Works
  func(make_pair(nullptr, 3.14)); // nullptr => nullptr_t => const char* 
}

In the example above, a NULL pointer is converted to the number 0, which is of type int by default. And in our case, it is necessary that the type be const char*. When using the nullptr pointer, this error will not occur.

9. An example of allocating the memory by the function malloc(), which returns a pointer to the type void.

The malloc() function allocates memory for an unmanaged pointer. Function returns a void* type.

To assign to the pointer a value of the memory address allocated to the object , you must perform an explicit type cast.

Example. Using the malloc() function.

// example of allocating memory to an unmanaged pointer
int * p;
p = NULL;

// allocating the memory by the malloc() function for a pointer to an int
p = (int *)malloc(sizeof(int));

// Allocating memory using the malloc() function for a pointer to double
double * pd = NULL;
pd = (double *)malloc(sizeof(double));

10. What restrictions are imposed on the operation of taking the address &?

The following restrictions are imposed on the operation of taking the address &:

1. It is impossible to determine the address of the constants. For example, expression

pi = &0xffe800;

will generate an error.

2. It is not possible to determine the address of the value that is obtained when calculating the expression. For example, a code snippet

int *pi;
int d;

d = 8;
pi = &(d + 5); // Error, can not get the address of the expression

will result in an error.

11. Is it possible set the pointer to a physical memory address directly?

The Visual C++ compiler allows the pointer to be set a direct memory address. However, when accessing this address, a critical situation occurs with the error message:

"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

This means that an attempt was made to access the protected memory. This applies to both console applications and applications created using the Windows Forms Application template.

Example. Assignment of the physical address to the pointer.

// Assignment of the physical address to the pointer.
float *pf; // pointer to float
float f;

// ...

// assignment of the physical address of memory (random value)
pf = (float *)0xffff00; // it works

f = (float)(*pf); // error! A critical situation arises


Related topics