Contents E Structures, s and Dynamic Memory Allocation... E-2 E.1 C s Dynamic Memory Allocation Functions... E-2 E.1.1 A conceptual view of memory usage... E-2 E.1.2 malloc() and free()... E-2 E.1.3 Create a simple List... E-4 E.1.4 Insert one record into the list... E-9 E.1.5 Delete one record of the list... E-9 E.2 C++ s Dynamic Memory Allocation Operators... E-10 E.2.1 The operators new and delete... E-10 E.2.2 Create a simple List... E-11 MM1_091216.doc Page E-1 of 12 Rüdiger Siol
E Structures, s and Dynamic Memory Allocation E.1 C s Dynamic Memory Allocation Functions E.1.1 A conceptual view of memory usage Memory usage of a program static area dynamic area Program- Code Global Data Stack- free- Heap- Area (r.siol) 12.12.2009 Hochschule Ravensburg-Weingarten Technik Wirtschaft Sozialwesen 125 E.1.2 malloc() and free() The C language does not contain the new or the delete operators. lnstead, C uses library functions to allocate and free memory. For compatibility, C++ still provides support for C's dynamic allocation system, and it is still quite common to find the C-like dynamic allocation system used in C++ programs. The following discussion explains how it works. At the core of C's allocation system are the functions malloc( ) and free( ). The malloc( ) function allocates memory, and the free( ) function releases it. That is, each time a malloc( ) memory request is made, a portion of the remaining free memory is allocated. Each time free( ) is called, memory is returned to the system. Any program that uses these functions must include the header <cstdlib>. MM1_091216.doc Page E-2 of 12 Rüdiger Siol
The malloc( ) function has this prototype: void *malloc(size_t num_bytes); Here, num_bytes is the number of bytes of memory you want to allocate. (size_t is a defined type that is some type of unsigned integer). The malloc( ) function returns a pointer of type void, which signifies a generic pointer. You must use a cast to convert this pointer into the type of pointer needed by your program. After a successful call, malloc( ) will return a pointer to the first byte of the region of memory allocated from the heap. If there is not enough memory to satisfy the request, an allocation failure occurs, and malloc( ) returns a null. The free( ) function is the opposite of malloc( ) in that it returns previously allocated memory to the system. Once the memory has been released, it may be reused by a subsequent call to malloc( ). The function free( ) has this prototype: void free(void *ptr); Here, ptr is a pointer to memory previously allocated using malloc( ). You must never call free( ) with an invalid argument; this would cause the free list to be destroyed. While malloc( ) and free( ) are fully capable dynamie allocation functions, there are several reasons why C++ defines its own approach to dynamic allocation. First, new automatically computes the size of the type being allocated. You don't have to make use of the sizeof operator, so you save some effort. More importantly, automatic computation prevents the wrong amount of memory from being allocated. The second advantage to the C++ approach is that new automatically returns the correct pointer type-you don't need to use a type cast. Third, by using new, you can initialize the object being allocated. Finally, as you will see later, you can create your own, customized versions of new and delete. One last point: Because of possible incompatibilities, you should not mix malloc( ) and free( ) with new and delete in the same program. The following program illustrates malloc( ) and free( ): MM1_091216.doc Page E-3 of 12 Rüdiger Siol
E.1.3 Create a simple List Declare a recursive structure with the elements of your record; it is called recursive as it contains elements which are pointers to the same structure. struct char myname[20]; // The name int registration; // The registration ID-Number * ; // A pointer to the record of the same type ; The start of the list is the anchor, this is a pointer to the first record in the list. In the beginning it points to NULL as there is no list available. Anchor mechatronic NULL int main() * mechatronic = NULL; Now mechatronic is an anchor of type. It is initialized to NULL. Connect records to the end of the list. It is necessary to find a record whose - pointer is NULL. p and q are pointers of type. With p we look through the chain of records which is either existent or empty. After the loop q is positioned to the start of the last record. If we connect a record, the associated pointer has to be assigned to q->. while (p) q = p; p = p -> ; // Search the end of the list // q points to the last record The create() function is defined to type and insert the elements of a record and it returns a pointer to that record. Per default it s pointer is NULL. That assures to finish the list with a NULL pointer. q -> = create(); // Add record MM1_091216.doc Page E-4 of 12 Rüdiger Siol
The create function: * create () * q; q = ( *) malloc (sizeof ()); if (!q) cout << "Allocation Failure. \n"; return NULL; cout << "Name:\t\t\t"; cin >> q->myname; cout << "Registration:\t"; cin >> q->registration; q -> = NULL; return q; Now we have the tools available to build a simple list. * build_list ( * mechatronic) * p, *q; int r; cout << "Type the number of records you like to connect to the list: r = "; cin >> r; for (int i = 0; i < r; ++i) if (mechatronic) // Connect the record while (p) // Search the end of the list q = p; // q points to the last record p = p -> ; q -> = create(); // Add record else // Connect the first record mechatronic = create(); return mechatronic; MM1_091216.doc Page E-5 of 12 Rüdiger Siol
And with that function the main() function calls: int main() * mechatronic = NULL; // That's an anchor for the s which registered for mechatronic mechatronic = build_list (mechatronic); document (mechatronic); mechatronic = delete_list (mechatronic); document (mechatronic); return 0; The document(mechatronic) function shows all elements of the list as they are stored in the heap. void document( * ptr) while (ptr) cout << ptr -> myname << "\t" << ptr -> registration << "\t" << ptr -> << endl; ptr = ptr -> ; cout << "\nreached the end of the list." << endl; s which are not any more necessary may be deleted with the use of the free() function; the example shows the deletion of the whole list. * delete_list ( * mechatronic) * p, *q; while (p) q = p; p = p-> ; free(q); return p; MM1_091216.doc Page E-6 of 12 Rüdiger Siol
The source code of the complete program: #include <iostream> #include <cstdlib> #include <cstring> using namespace std; struct char myname[20]; int registration; * ; ; // The name // The registration ID-Number // A pointer to the record of the same type void document( * ptr); * create (); * build_list ( * mechatronic); * delete_list ( * mechatronic); int main() * mechatronic = NULL; // That's an anchor for the s which registered for mechatronic mechatronic = build_list (mechatronic); document (mechatronic); mechatronic = delete_list (mechatronic); document (mechatronic); return 0; void document( * ptr) while (ptr) cout << ptr -> myname << "\t" << ptr -> registration << "\t" << ptr -> << endl; ptr = ptr -> ; cout << "\nreached the end of the list." << endl; * build_list ( * mechatronic) * p, *q; int r; cout << "Type the number of records you like to connect to the list: r = "; cin >> r; for (int i = 0; i < r; ++i) if (mechatronic) // Connect the record while (p) // Search the end of the list q = p; // q points to the last record p = p -> ; q -> = create(); // Add record else // Connect the first record mechatronic = create(); MM1_091216.doc Page E-7 of 12 Rüdiger Siol
return mechatronic; * create () * q; q = ( *) malloc (sizeof ()); cout << "Name:\t\t\t"; cin >> q->myname; cout << "Registration:\t"; cin >> q->registration; q -> = NULL; return q; * delete_list ( * mechatronic) * p, *q; while (p) q = p; p = p-> ; free(q); return p; Type the number of records you like to connect to the list: r = 5 Name: Jimmy Registration: 1250 Name: Mike Registration: 1251 Name: Sven Registration: 1252 Name: Herbert Registration: 1253 Name: Glen Registration: 1254 Jimmy 1250 0x000ce140 Mike 1251 0x000ce160 Sven 1252 0x000ce180 Herbert 1253 0x000ce1a0 Glen 1254 0x00000000 Reached the end of the list. Reached the end of the list. MM1_091216.doc Page E-8 of 12 Rüdiger Siol
E.1.4 Insert one record into the list The list exists in such a complete form. Anchor mechatronic NULL Search an element in the list and insert a new record either after or before that record. Anchor mechatronic NULL E.1.5 Delete one record of the list Anchor mechatronic NULL Search an element in the list and delete the record. MM1_091216.doc Page E-9 of 12 Rüdiger Siol
E.2 C++ s Dynamic Memory Allocation Operators E.2.1 The operators new and delete C++ provides two dynamic allocation operators: new and delete. These operators are used to allocate and free memory at run time. Dynamic allocation is an important part of almost all real-world programs. C++ also supports dynamic memory allocation functions, called malloc() and free(). These are included for the sake of compatibility with C. However, for C++ code, you should use the new and delete operators because they have several advantages. The new operator allocates memory and returns a pointer to the start of it. The delete operator frees memory previously allocated using new. The general forms of new and delete are shown here: p_var = new type; delete p _var; Here, p_var is a pointer variable that receives a pointer to memory that is large enough to hold an item of type type. Since the heap is finite, it can become exhausted. If there is insufficient available memory to fill an allocation request, then new will fail and a bad_alloc exception will be generated. This exception is defined in the header <new>. Your program should handle this exception and take appropriate action if a failure occurs. If this exception is not handled by your program, then your program will be terminated. The actions of new on failure as just described are specified by Standard C++. The trouble is that not all compilers, especially older ones, will have implemented new in compliance with Standard C++. When C++ was first invented, new returned null on failure. Later, this was changed such that new caused an exception on failure. Finally, it was decided that a new failure will generate an exception by default, but that a null pointer could be returned instead, as an option. Thus, new has been implemented differently, at different times, by compiler manufacturers. Although all compilers will eventually implement new in compliance with Standard C++, currently the only way to know the precise action of new on failure is to check your compiler's documentation. Since Standard C++ specifies that new generates an exception on failure, this is the way the code is written. If your compiler handles an allocation failure differently, you will need to make the appropriate changes. The delete operator must be used only with a valid pointer previously allocated by using new. Using any other type of pointer with delete is undefined and will almost certainly cause serious problems, such as a system crash. Although new and delete perform functions similar to malloc() and free(), they have several advantages. First, new automatically allocates enough memory to hold an object of the specified type. You do not need to use the sizeof operator. Because the size is computed automatically, it eliminates any possibility for error in this regard. Second, new automatically returns a pointer of the specified type. You don't need to use an explicit type cast as you do when allocating memory by using malloc( ). Finally, both new and delete can be overloaded, allowing you to create customized allocation systems. Although there is no formal rule that states this, it is best not to mix new and delete with malloc( ) and free( ) in the same program. There is no guarantee that they are mutually compatible. MM1_091216.doc Page E-10 of 12 Rüdiger Siol
E.2.2 Create a simple List #include <iostream> #include <new> #include <cstring> using namespace std; struct char myname[20]; int registration; * ; ; // In C: #include <cstdlib> // The name // The registration ID-Number // A pointer to the record of the same type void document( * ptr); * create (); * build_list ( * mechatronic); * delete_list ( * mechatronic); int main() * mechatronic = NULL; // That's an anchor for the s which registered for mechatronic mechatronic = build_list (mechatronic); document (mechatronic); mechatronic = delete_list (mechatronic); document (mechatronic); return 0; void document( * ptr) while (ptr) cout << ptr -> myname << "\t" << ptr -> registration << "\t" << ptr -> << endl; ptr = ptr -> ; cout << "\nreached the end of the list." << endl; * build_list ( * mechatronic) * p, *q; int r; cout << "Type the number of records you like to connect to the list: r = "; cin >> r; for (int i = 0; i < r; ++i) if (mechatronic) // Connect the record while (p) // Search the end of the list q = p; // q points to the last record p = p -> ; q -> = create(); // Add record else // Connect the first record MM1_091216.doc Page E-11 of 12 Rüdiger Siol
mechatronic = create(); return mechatronic; * create () * q; q = new ; if (!q) // In C: q = ( *) malloc (sizeof ()); cout << "Allocation Failure. \n"; return NULL; cout << "Name:\t\t\t"; cin >> q->myname; cout << "Registration:\t"; cin >> q->registration; q -> = NULL; return q; * delete_list ( * mechatronic) * p, *q; while (p) q = p; p = p-> ; return p; delete q; // In C: free(q); This example shows, we needed three modifications of the C-Version to come to a C++ version of the program. In C++ new and delete are operators but not functions! MM1_091216.doc Page E-12 of 12 Rüdiger Siol