A program can store information in the computer's main memory in two main ways. The first one uses global and local variables, including arrays, structures, and classes. In the case of global and static local variables, the storage location of information is fixed for the duration of the program execution. In the case of local variables, memory is allocated on the stack. Although Borland C++ handles these variables very efficiently, using them requires the programmer to know in advance the amount of memory that will be required during program execution.

The second way to store information is to use the Borland C++ dynamic memory allocation system. In this method, memory for storing information is allocated from the free memory area as needed and returned back, i.e. released when it is no longer needed. The free memory area lies between the memory area where the program resides and the stack. This area is called the heap and is used for requests for dynamic memory allocation.

The advantage of using dynamic memory is that the same memory can be used to store different information during program execution. Since memory is allocated for a specific purpose and freed when its use is complete, it is possible to use the same memory at another time for other purposes in another part of the program. Another advantage of dynamic memory allocation is the ability to create linked lists, binary trees, and other dynamic data structures with it.

The core of C's dynamic memory allocation is the malloc() and free() functions, which are part of the standard library. Each time a memory allocation request is made by the malloc() function, a portion of the available free memory is allocated. Whenever this memory is freed using the free() function, this memory is returned back to the system.

The C++ language defines two dynamic memory allocation operators, new and delete.

The ANSI C standard defines only four dynamic memory allocation functions: calloc(), malloc(), free(), and realloc(). However, Borland C++ contains several other dynamic memory allocation features. When compiling code for the modern 32-bit memory model, the memory is flat and only the four standard memory allocation functions are typically used.

The ANSI C standard specifies that the header information needed for dynamic memory allocation is contained in the stdlib.h file. However, Borland C++ allows you to use the stdlib.h or alloc.h header files. We use the stdlib.h header file here as it provides portability. Some other dynamic memory allocation functions require the alloc.h, malloc.h, or dos.h header files. Pay special attention to which header file is needed to use each function.

We discovered the possibilities of dynamic memory allocation. What does it mean? This means that with dynamic memory allocation, memory is reserved not at the compilation stage, but at the program execution stage. And this gives us the opportunity to allocate memory more efficiently, mainly for arrays. FROM dynamic selection memory, we do not need to pre-set the size of the array, especially since it is not always known what size the array should have. Next, let's look at how you can allocate memory.

Memory allocation in C (malloc function)

The malloc() function is defined in header file stdlib.h , it is used to initialize pointers with the required amount of memory. Memory is allocated from the sector random access memory available to any programs running on that machine. The argument is the number of bytes of memory to be allocated, the function returns a pointer to the allocated block in memory. The malloc() function works just like any other function, nothing new.

Because different types data has different memory requirements, we somehow have to learn how to get the size in bytes for the data different type. For example, we need a piece of memory for an array of values ​​of type int - this is one size of memory, and if we need to allocate memory for an array of the same size, but already of type char - this is a different size. Therefore, you need to somehow calculate the size of the memory. This can be done with the sizeof() operation, which takes an expression and returns its size. For example, sizeof(int) will return the number of bytes needed to store an int value. Consider an example:

#include int *ptrVar = malloc(sizeof(int));

In this example, in line 3 the pointer ptrVar is assigned the address of a piece of memory, the size of which corresponds to the data type int . Automatically, this area of ​​memory becomes inaccessible to other programs. And this means that after the allocated memory becomes unnecessary, it must be explicitly freed. If the memory is not explicitly freed, then at the end of the program, the memory will not be freed for operating system, this is called a memory leak. You can also determine the size of the allocated memory that needs to be allocated by passing a null pointer, here is an example:

int *ptrVar = malloc(sizeof(*ptrVar));

What's going on here? The sizeof(*ptrVar) operation will estimate the size of the memory area pointed to by the pointer. Since ptrVar is a pointer to a piece of memory of type int , sizeof() will return the size of an integer. That is, in fact, according to the first part of the definition of the pointer, the size for the second part is calculated. So why do we need it? This may be necessary if you suddenly need to change the definition of a pointer, int , for example, to float and then, we do not need to change the data type in two parts of the pointer definition. It will be enough that we change the first part:

Float *ptrVar = malloc(sizeof(*ptrVar));

As you can see, in such a record there is one very forte, we should not call the malloc() function using sizeof(float) . Instead, we passed a pointer to the float type to malloc() , in which case the size of the allocated memory will be automatically determined by itself!

This is especially useful if you need to allocate memory far from the pointer definition:

Float *ptrVar; /* . . . one hundred lines of code */ . . . ptrVar = malloc(sizeof(*ptrVar));

If you used the memory allocation construct with the sizeof() operation, then you would have to find the pointer definition in the code, look at its data type, and only then you would be able to correctly allocate memory.

Deallocation of allocated memory

Freeing memory is done with the free() function. Here is an example:

Free(ptrVar);

After freeing the memory, it is good practice to reset the pointer to zero, i.e. set *ptrVar = 0 . If you assign 0 to a pointer, the pointer becomes null, in other words, it no longer points anywhere. Always after freeing memory, assign 0 to the pointer, otherwise, even after freeing memory, the pointer still points to it, which means you can accidentally harm other programs that may use this memory, but you don’t even know anything about it you will know and you will think that the program works correctly.

P.S.: Anyone who is fond of video editing may be interested in this Windows 7 video editor. The video editor is called Movavi, maybe someone is already familiar with it or even worked with it. With this program in Russian, you can easily add video from the camera, improve the quality and overlay beautiful videos effects.

Static memory is allocated even before the start of the program, at the stage of compilation and assembly. Static variables have a fixed address, which is known before the program starts and does not change during its operation. Static variables are created and initialized before entry into main function at which program execution begins.

There are two types of static variables:

  • global variables are variables defined outside functions, in the description of which the word static is missing. Usually descriptions global variables that include the word extern are moved to header files (h-files). The word extern means that the variable is declared but not created at this point in the program. Definitions global variables, i.e. descriptions without the word extern are placed in implementation files (c-files or cpp-files). Example: the global variable maxind is declared twice:
    • in h-file with the line

      extern int maxind;

      this declaration reports the presence of such a variable, but does not create this variable!
    • in cpp file with the line

      int maxind = 1000;

      this description creates variable maxind and assigns it an initial value of 1000 . Note that the language standard does not require the mandatory assignment of initial values ​​to global variables, but, nevertheless, it is always better to do this, otherwise the variable will contain an unpredictable value (garbage, as programmers say). It is good style to initialize all global variables when they are defined.
    Global variables are so named because they are available anywhere in the program in all of its files. Therefore, global variable names must be long enough to avoid accidental names of two different variables. For example, the names x or n for a global variable are not appropriate;
  • static variables are variables whose description contains the word static . As a rule, static variables are declared outside functions. Such static variables are like global variables in every way, with one exception: the scope of a static variable is limited to the single file within which it is defined - and, moreover, it can only be used after it has been declared, i.e. below in the text. For this reason, declarations of static variables are usually placed at the beginning of the file. Unlike global variables, static variables never are not described in h-files (extern and static modifiers conflict with each other). Tip: use static variables if you want them to be available only to the functions described inside the same file. If possible, do not use global variables in such situations, this will avoid name conflicts when implementing large projects consisting of hundreds of files.
    • A static variable can also be declared inside a function, although usually no one does this. The variable is not located on the stack, but in static memory, i.e. it cannot be used in recursion, and its value is preserved between different inputs to the function. The scope of such a variable is limited to the body of the function in which it is defined. Otherwise, it is similar to a static or global variable. notice, that keyword static in C is used for two different purposes:
      • as an indication of the type of memory: the variable is located in static memory, not on the stack;
      • as a way to limit the scope of a variable within a single file (in the case of a variable declaration outside a function).
  • The word static can also appear in the header of a function. However, it is used only to limit the scope of the function name to a single file. Example:

    static int gcd(int x, int y); // Function prototype. . . static int gcd(int x, int y) ( // Implementation. . . )

    Tip: use static modifier in the header of the function, if it is known that the function will be called only within one file. The word static must be present both in the description of the function prototype and in the function header when it is implemented.

Stack or local memory

Local or stack variables are variables declared inside a function. The memory for such variables is allocated in the hardware stack, see section 2.3.2. Memory is allocated when a function or block is entered and is freed when the function or block is exited. In this case, the capture and release of memory occur almost instantly, because. the computer only modifies the register containing the address of the top of the stack.

Local variables can be used in recursion because when the function is re-entered, a new set of local variables is created on the stack, and the previous set is not destroyed. For the same reason, local variables are safe when using threads in parallel programming (see section 2.6.2). Programmers call this property of a function reentrancy, from English. re-enter able - the ability to re-enter. This is a very important quality in terms of program reliability and safety! A program that works with static variables does not have this property, so to protect static variables, you have to use synchronization mechanisms(see 2.6.2), and the program logic becomes much more complicated. You should always avoid using global and static variables if you can get by with local ones.

The disadvantages of local variables are an extension of their advantages. Local variables are created when a function enters and disappear when it exits, so they cannot be used as data shared between multiple functions. In addition, the size of the hardware stack is not infinite, the stack can overflow at one fine moment (for example, during deep recursion), which will lead to a catastrophic termination of the program. Therefore, local variables should not be large. In particular, large arrays cannot be used as local variables.

Dynamic memory or heap

In addition to static and stack memory, there is also an almost unlimited resource of memory, which is called dynamic, or heap(heap ). The program can capture areas of dynamic memory of the desired size. After use, the previously captured section of dynamic memory should be freed.

Space allocated for dynamic memory virtual memory process between static memory and the stack. (The virtual memory mechanism was discussed in Section 2.6.) Typically, the stack is located at higher virtual memory addresses and grows in the direction of decreasing addresses (see Section 2.3). The program and constant data are placed in lower addresses, static variables are located above. The space above static variables and below the stack is occupied by dynamic memory:

address memory content

program code and data,

protected from change

...

static variables

programs

dynamic memory

max. address (2 32 -4)

stack

The dynamic memory structure is automatically maintained by the C or C++ runtime system. The heap consists of captured and free segments, each preceded by a segment descriptor. When executing a memory grab request, the executing system searches for a free segment of sufficient size and grabs a segment of the required length in it. When a memory segment is released, it is marked as free; if necessary, several consecutive free segments are combined.

The C language uses the standard malloc and free functions to acquire and deallocate dynamic memory; their prototypes are described in the standard header file "stdlib.h". (The name malloc is short for memory allocate- "memory capture".) The prototypes of these functions look like this:

void *malloc(size_t n); // Grab a piece of memory // n bytes in size void free(void *p); // Free the area // of memory with address p

Here n is the size of the captured area in bytes, size_t is the name of one of the integer types that define maximum size captured area. The size_t type is specified in the standard header file " stdlib.h " using the typedef statement (see p. 117). This ensures that the text of the C program is independent of the architecture used. On a 32-bit architecture, size_t is defined as an unsigned integer:

typedef unsigned int size_t;

The malloc function returns the address of the captured memory area, or zero on failure (when there is no large enough free area). The free function releases a piece of memory at the given address. A pointer is used to set the address. general type void* . After calling the malloc function, it must be cast to a pointer to a concrete type using the cast operation, see Section 3.4.11. For example, the following example grabs a 4000-byte heap and assigns its address to a pointer to an array of 1000 integers:

int*a; // Pointer to an array of integers. . . a = (int *) malloc(1000 * sizeof(int));

The expression in the malloc function argument is 4000 because the size of the integer sizeof(int) is four bytes. To convert a pointer, use the cast operation (int *) from a generic type pointer to a pointer to an integer.

Example: printing the first n prime numbers

Let's look at an example that uses dynamic memory capture. You need to enter an integer n and print the first n primes. (A prime number is a number that has no non-trivial divisors.) We use the following algorithm: we sequentially check all odd numbers, starting with three (we consider two separately). We divide the next number by all prime numbers found at the previous steps of the algorithm and not exceeding the square root of the number being checked. If it is not divisible by any of these prime numbers, then it is itself prime; it is printed and added to the array of found primes.

Since the required number of primes n is not known before the program starts, it is not possible to create an array to store them in static memory. The way out is to grab space for an array in dynamic memory already after entering the number n . Here is the full text of the program:

#include #include #include int main() ( int n; // Required number of primes int k; // Current number of found primes int *a; // Pointer to array of found primes int p; // Next number to check int r; // Integer part square root of p int i; // Index of a prime divisor bool prime; // Prime prime printf("Enter number of primes: "); scanf("%d", &n); if (n<= 0) // Некорректное значение =>return 1; // exit with an error code // Capture memory for an array of primes a = (int *) malloc(n * sizeof(int)); a = 2; k = 1; // Add a 2 to the array printf("%d ", a); // and print it p = 3; while (k< n) { // Проверяем число p на простоту r = (int)(// Целая часть корня sqrt((double) p) + 0.001); i = 0; prime = true; while (i < k && a[i] <= r) { if (p % a[i] == 0) { // p делится на a[i] prime = false; // =>p is not prime, break; // exit the loop ) ++i; // To the next prime divisor ) if (prime) ( // If you find a prime number, a[k] = p; // then add it to the array ++k; // Increase the number of primes printf("%d ", p ); // Print a prime number if (k % 5 == 0) ( // Switch to newline printf("\n"); // after every five numbers ) ) p += 2; // To the next odd number ) if (k % 5 != 0) ( printf("\n"); // Translate string ) // Free dynamic memory free(a); return 0; )

An example of how this program works:

Enter the number of simple: 50 2 3 5 7 11 13 13 19 29 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 167 173 179 181 191 193 197 197 197 197 197 197 197 197 197 197 197 197 197 197 199 211 223 227 229

C++ new and delete operators

The C++ language uses the new and delete operators to acquire and deallocate dynamic memory. They are part of the C++ language, unlike the malloc and free functions that are part of the C standard library.

Let T be some C or C++ type, p be a pointer to an object of type T . Then, to capture memory with a size of one element of type T, the new operator is used:

T*p; p = new T;

For example, to capture eight bytes under real number fragment is used of type double

double *p; p = new double;

When using new , unlike malloc , you do not need to cast a pointer from void* to the desired type: the new operator returns a pointer to the type written after the word new . Compare two equivalent snippets in C and C++.

    stores global variables and constants;

    size is determined at compile time.

    stack

    stores local variables, function arguments and intermediate values ​​of calculations;

    the size is determined when the program is launched (usually 4 MB is allocated).

    Heap

    dynamically allocated memory;

    The OS allocates memory in chunks (as needed).

Dynamically allocated memory should be used if we do not know in advance (at the time of writing the program) how much memory we need (for example, the size of the array depends on what the user enters while the program is running) and when working with large amounts of data.

Dynamic memory, also called the "heap", is explicitly allocated at the request of a program from operating system resources and is controlled by a pointer. It is not automatically initialized and must be explicitly freed. Unlike static and automatic memory, dynamic memory is practically unlimited (limited only by the size of RAM) and can change while the program is running.

Working with dynamic memory in s

To work with dynamic memory in the C language, the following functions are used: malloc, calloc, free, realloc. Let's consider them in more detail.

    Allocation (memory grab) : void *malloc(size_t size);

As input parameter the function takes the size of the memory to be allocated. The return value is a pointer to a heap-allocated chunk of memory. If the OS was unable to allocate memory (for example, there was not enough memory), then malloc returns 0.

    After you finish working with dynamically allocated memory, you need to free it. For this purpose, it is used free function, which returns memory under OS control: void free(void *ptr);

If dynamic memory is not freed before the end of the program, then it is freed automatically when the program ends. However, it is a sign of good programming style to explicitly deallocate unneeded memory.

Example:// memory allocation for 1,000 int elements

int * p = (int *) malloc(1000*sizeof(int));

if (p==NULL) out<< "\n память не выделена";

free(p); // return memory to the heap

2. Allocation (capture of memory): void *calloc(size_t nmemb, size_t size);

The function works similarly to malloc, but differs in syntax (instead of the size of the allocated memory, you need to specify the number of elements and the size of one element) and in that the allocated memory will be reset to zero. For example, after executing int * p = (int *) calloc(1000, sizeof(int)) p will point to the beginning of an int array of 1000 elements initialized to zero.

3. Changing the memory size: void *realloc(void *ptr, size_t size);

The function changes the size of the allocated memory (pointed to by ptr, derived from call malloc, calloc or realloc). If the size specified in the parameter size greater than the one allocated under the pointer ptr, then it is checked whether it is possible to allocate the missing memory cells in a row with those already allocated. If there is not enough space, then a new piece of memory is allocated with the size size and pointer data ptr are copied to the beginning of the new section.

During the execution of the program, a section of dynamic memory is available wherever a pointer is available that addresses this section. Thus, the following three variants of working with dynamic memory allocated in some block (for example, in the body of a non-main function) are possible.

    A pointer (to a dynamic memory area) is defined as a local automatic memory object. In this case, the allocated memory will not be available when exiting the pointer localization block, and must be freed before exiting the block.

( int* p= (int *) calloc(n, sizeof(int))

free(p); // free dyn. memory

    The pointer is defined as a local static storage object. Dynamic memory allocated once in a block is available through a pointer each time the block is re-entered. Memory should be freed only when it is no longer in use.

(static int* p = (int *) calloc(n, sizeof(int));

p= (int *) calloc(n, sizeof(int));

f(50); //highlight din. memory to be freed

f1(100); //highlight din. memory (first access)

f1(100); // work with din. memory

f1(0); // free dyn. memory

    The pointer is a global object with respect to the block. Dynamic memory is available in all blocks where the pointer is "visible". Memory should be freed only when it is no longer used.

int*pG; //working pointer for din. memory (global variable)

void init(int size)

for (i=0; i< size; i++) //цикл ввода чисел

( printf("x[%d]=",i);

scanf("%d", &pG[i]);

int sum (int size)

for (i=0; i< size; i++) //цикл суммирования

// memory allocation

pG= (int *) calloc(n, sizeof(int));

// work with dynamic memory

printf(\ns=%d\n",sum(n));

free (pG); pG=NULL; // deallocate memory

Working with dynamic memory in C++

C++ has its own mechanism for allocating and freeing memory - these are functions new and delete. Usage example new: int * p = new int; // allocation of memory for 1000 e-ths I.e. when using the function new no need to cast a pointer and no need to use sizeof(). Freeing a selection with new memory is handled by the following call: delete p; If you need to allocate memory for one element, then you can use int * q = new int; or int * q = new int(10); // the allocated int will be initialized with the value 10 in this case the deletion will look like this: delete q;

C++ supports three basic types allocation(or more "distributions") memory, two of which we are already familiar with:

Static memory allocation holds for and variables. Memory is allocated once, at the start of the program, and is retained throughout the entire program.

Automatic Memory Allocation is performed for and . Memory is allocated when the block containing these variables is entered and removed when it is exited.

Dynamic memory allocation is the topic of this lesson.

Dynamic allocation of variables

Both static and automatic memory allocation have two properties in common:

How does dynamic memory allocation work?

Your computer has memory (maybe a lot of it) that is available for use by programs. When you run a program, your operating system loads that program into some part of that memory. And this memory used by your program is divided into several parts, each of which performs a specific task. One part contains your code, the other is used to perform normal operations (tracking called functions, creating and destroying global and local variables, etc.). We will talk about it later. However, most of the available memory is simply there waiting for allocation requests from programs.

When you dynamically allocate memory, you are asking the operating system to reserve some of that memory for your program to use. If the OS can fulfill this request, then the address of that memory is returned back to your program. From now on, your program will be able to use this memory as it wishes. When you have already done everything that was necessary with this memory, then it needs to be returned back to the operating system, for distribution among other requests.

Unlike static or automatic memory allocation, the program itself is responsible for requesting and returning dynamically allocated memory.

Freeing up memory

When you dynamically allocate a variable, you can also initialize it with or uniform initialization (in C++11):

int *ptr1 = new int(7); // use direct initialization int *ptr2 = new int ( 8 ); // use uniform initialization

When everything that was needed has already been done with a dynamically allocated variable, you need to explicitly tell C++ to free this memory. For variables, this is done with operator delete:

// Assume ptr has already been allocated with new delete ptr; // return the memory pointed to by ptr back to the operating system ptr = 0; // make ptr null (use nullptr instead of 0 in C++11)

The delete operator doesn't actually delete anything. It simply returns the memory that was previously allocated back to the operating system. The operating system can then reassign that memory to another application (or to the same one again).

Although it may seem that we are removing variable but it's not! The pointer variable still has the same scope as before and can be assigned a new value just like any other variable.

Note that deleting a pointer that does not point to dynamically allocated memory can lead to problems.

hanging pointers

C++ makes no guarantees about what happens to the contents of the freed memory or to the value of the pointer being deleted. In most cases, the memory returned to the operating system will contain the same values ​​that it had before release, and the pointer will continue to point to only the already freed (deleted) memory.

A pointer that points to freed memory is called hanging pointer. Dereferencing or deleting a dangling pointer will produce unexpected results. Consider the following program:

#include int main() ( int *ptr = new int; *ptr = 8; // put the value in the allocated memory location delete ptr; // return the memory back to the operating system. ptr is now a dangling pointer std::cout<< *ptr; // разыменование висячего указателя приведёт к неожиданным результатам delete ptr; // попытка освободить память снова приведёт к неожиданным результатам также return 0; }

#include

int main()

int * ptr = new int ; // dynamically allocate an integer variable

* ptr = 8 ; // put the value in the allocated memory location

delete ptr ; // return the memory back to the operating system. ptr is now a dangling pointer

std::cout<< * ptr ; // dereferencing a dangling pointer will lead to unexpected results

delete ptr ; // trying to free memory again will lead to unexpected results as well

return 0 ;

In the program above, the value 8, which was previously assigned to a dynamic variable, may or may not still be there after it is freed. It is also possible that the freed memory may already have been allocated to another application (or for the operating system's own use), and attempting to access it will cause the operating system to automatically terminate your program.

The process of freeing memory can also lead to the creation several hanging pointers. Consider the following example:

#include int main() ( int *ptr = new int; // dynamically allocate an integer variable int *otherPtr = ptr; // otherPtr now points to the same allocated memory as ptr delete ptr; // return the memory back to the operating system ptr and otherPtr are now dangling pointers ptr = 0; // ptr is now nullptr // However, otherPtr is still a dangling pointer! return 0; )

#include

int main()

int * ptr = new int ; // dynamically allocate an integer variable

int * otherPtr = ptr ; // otherPtr now points to the same allocated memory as ptr

delete ptr ; // return the memory back to the operating system. ptr and otherPtr are now dangling pointers

ptr = 0 ; // ptr is now nullptr

// However, otherPtr is still a dangling pointer!

return 0 ;

First, try to avoid situations where multiple pointers point to the same piece of allocated memory. If this is not possible, then clarify which pointer of all "owns" the memory (and is responsible for deleting it), and which pointers simply access it.

Secondly, when you delete a pointer, and if it doesn't exit immediately after deletion, then it must be made null, i.e. assign the value 0 (or in C++11). By "out of scope immediately after deletion" I mean that you delete the pointer at the very end of the block in which it is declared.

Rule: Set deleted pointers to 0 (or nullptr in C++11) unless they go out of scope immediately upon deletion.

new operator

When memory is requested from the operating system, in rare cases it may not be available (i.e., it may not be available).

By default, if the new operator did not work, the memory was not allocated, then a exception bad_alloc. If this exception is handled incorrectly (which it will be, since we haven't looked at exceptions and handling them yet), then the program will simply abort (crash) with an unhandled exception error.

In many cases, the process of throwing an exception with new (as well as crashing the program) is undesirable, so there is an alternative form of new that returns a null pointer if memory cannot be allocated. You just need to add std::nothrow constant between the new keyword and the data type:

int *value = new (std::nothrow) int; // pointer value will become null if dynamic allocation of an integer variable fails

In the example above, if new does not return a pointer with dynamically allocated memory, then a null pointer will be returned.

Dereferencing it is also not recommended, as this will lead to unexpected results (most likely, to a crash in the program). Therefore, the best practice is to check all requests for memory allocation, to ensure that these requests are executed successfully and the memory is allocated:

int *value = new (std::nothrow) int; // request to allocate dynamic memory for an integer value if (!value) // handle the case when new returns null (i.e. no memory is allocated) ( // Handling this case std::cout<< "Could not allocate memory"; }

Since non-allocation of memory by the new operator is extremely rare, programmers usually forget to do this check!

Null pointers and dynamic memory allocation

Null pointers (pointers with value 0 or nullptr) are especially useful in dynamic memory allocation. Their presence, as it were, tells us: "No memory has been allocated to this pointer." And this, in turn, can be used to perform conditional memory allocation:

// If ptr has not been allocated memory yet, then allocate it if (!ptr) ptr = new int;

Removing the null pointer does not affect anything. So the following is not necessary:

if (ptr) delete ptr;

if (ptr)

delete ptr ;

Instead, you can just write:

delete ptr ;

If ptr is non-null, then the dynamically allocated variable will be removed. If the pointer value is null, then nothing will happen.

Memory leak

Dynamically allocated memory has no scope, i.e. it remains allocated until it is explicitly freed, or until your program terminates its execution (and the operating system flushes all memory buffers itself). However, the pointers used to store dynamically allocated memory addresses follow the rules of normal variable scoping. This mismatch can cause interesting behavior. For example:

void doSomething() ( int *ptr = new int; )