Presentation is loading. Please wait.

Presentation is loading. Please wait.

Dynamically allocating arrays within structures

Similar presentations


Presentation on theme: "Dynamically allocating arrays within structures"— Presentation transcript:

1 Dynamically allocating arrays within structures

2 Outline In this lesson, we will:
See how to allocate memory in data structures Learn that this should be done within functions Look at how to use such an array

3 Structures and arrays Recall that it is possible to declare a structure with a fixed-size array struct coordinate_t { double point[3]; }; It is not possible to declare a structure with an array capacity that is not known at compile time: double point[n];

4 Dynamically allocated arrays
If the array size is not known at compile time, the only means of allocating that memory is through dynamic allocation Previously, we saw that we had to always pass around both: The address of an array, and Its capacity This is tedious, and error-prone, so let us create an array data structure

5 Arrays and pointers Consider this data structure:
struct array_t { std::size_t capacity; double *a_entries; }; When we declare such a data structure, we should immediately initialize both its entries: array_t my_array{0, nullptr}; This avoids the possibility of a wild pointer

6 Arrays and pointers In order to initialize this data structure, we must assign to the entries We will do this in a function: int main() { array_t data{0, nullptr}; // Allocate memory for the array and set all entries to 0.0 data.capacity = 14; data.a_entries = new double[data.capacity]; for ( std::size_t k{0}; k < data.capacity; ++k ) { data.a_entries[k] = 0.0; } // Do something with this data... return 0;

7 Arrays and pointers Because we will perform all of these steps repeatedly, it is better to convert this to a function call: void init_array( array_t &array, std::size_t array_capacity, double initial_value = 0.0 ) double initial_value ) { array.capacity = array_capacity; array.a_entries = new double[array.capacity]; for ( std::size_t k{0}; k < array.capacity; ++k ) { array.a_entries[k] = initial_value; } The default value is in the function declaration

8 Arrays and pointers This initialization function simplifies our program: int main() { array_t data{0, nullptr}; init_array( data, 14 ); // Use the default value of 0.0 // Do something with this data... return 0; }

9 Arrays and pointers Here is another function that uses this array data structure: double array_average( array_t const &array ); double array_average( array_t const &array ) { if ( array.capacity == 0 ) { return 0.0; } else { double sum{0.0}; for ( std::size_t k{0}; k < array.capacity; ++k ) { sum += array.a_entries[k]; } return sum / array.capacity;

10 Arrays and pointers Here is another:
double array_standard_deviation( array_t const &array ); double array_standard_deviation( array_t const &array ) { if ( array.capacity == 0 ) { return 0.0; } else { double sum_squares{0.0}; double average{array_average( array )}; for ( std::size_t k{0}; k < array.capacity; ++k ) { double diff{array.a_entries[k] - average}; sum_squares += diff*diff; } return std::sqrt( sum_squares / array.capacity );

11 Arrays and pointers We can now declare an instance of this class and use it: int main() { array_t data{0, nullptr}; init_array( data, 15 ); for ( std::size_t k{0}; k < data.capacity; ++k ) { std::cout << "Enter a number: "; std::cin >> data.a_entries[k]; } std::cout << "The average is " << array_average( data ) << std::endl; return 0;

12 Arrays and pointers Question: What happens when this instance goes out of scope? int main() { array_t data{0, nullptr}; init_array( data, 15 ); for ( std::size_t k{0}; k < data.capacity; ++k ) { std::cout << "Enter a number: "; std::cin >> data.a_entries[k]; } std::cout << "The average is " << array_average( data ) << std::endl; return 0;

13 Arrays and pointers When an instance of a data structure goes out of scope, the compiler simply ensures that the memory for the member variables is available for future computations That is, only the memory for the capacity and the pointer are reclaimed Consequently, we have the likelihood of a memory leak…

14 Arrays and pointers To avoid a memory leak, it is necessary to free up the dynamically allocated memory immediately before the array goes out of scope: double collect_data() { array_t data{0, nullptr}; init_array( data, 15 ); for ( std::size_t k{0}; k < data.capacity; ++k ) { std::cout << "Enter a number: "; std::cin >> data.a_entries[k]; } double average{array_average( data )}; delete[] data.a_entries; data.a_entries = nullptr; data.capacity = 0; return average;

15 Arrays and pointers As we will be doing these three steps again and again, it is preferable to define a function: void destroy_array( array_t &array ); void destroy_array( array_t &array ) { delete[] array.a_entries; array.a_entries = nullptr; array.capacity = 0; }

16 Arrays and pointers As we will be doing these three steps again and again, it is preferable to define a function: double collect_data() { array_t data{0, nullptr}; init_array( data, 15 ); for ( std::size_t k{0}; k < data.capacity; ++k ) { std::cout << "Enter a number: "; std::cin >> data.a_entries[k]; } double average{array_average( data )}; destory_array( data ); return average;

17 Resizing the array Suppose we want to resize the array: We must
Allocate a new array of the appropriate size For this, we will need a temporary local variable Copy over the data to the new array Delete the old array Update the member variables

18 Resizing the array Suppose we want to resize the array:
void resize_array( array_t &array, std::size_t new_capacity, double initial_value ) { if ( new_capacity != array.capacity ) { double *a_new_entries{ new double[new_capacity] }; std::size_t minimum{std::min( array.capacity, new_capacity )} for ( std::size_t k{0}; k < minimum; ++k ) { a_new_entries[k] = array.a_entries[k]; } for ( std::size_t k{minimum}; k < new_capacity; ++k ) { a_new_entries[k] = initial_value; delete[] array.a_entries; array.a_entries = a_new_entries; a_new_entries = nullptr; array.capacity = new_capacity;

19 Summary Following this lesson, you now
Understand how to allocate memory for data structures Know how to allocate and deallocate such memory It is best to use functions, as this is a repeated operation Resizing an array is possible, but requires careful assignments Local variables going out of scope do not destroy that memory

20 References [1] No references?

21 Colophon These slides were prepared using the Georgia typeface. Mathematical equations use Times New Roman, and source code is presented using Consolas. The photographs of lilacs in bloom appearing on the title slide and accenting the top of each other slide were taken at the Royal Botanical Gardens on May 27, 2018 by Douglas Wilhelm Harder. Please see for more information.

22 Disclaimer These slides are provided for the ece 150 Fundamentals of Programming course taught at the University of Waterloo. The material in it reflects the authors’ best judgment in light of the information available to them at the time of preparation. Any reliance on these course slides by any party for any other purpose are the responsibility of such parties. The authors accept no responsibility for damages, if any, suffered by any party as a result of decisions made or actions based on these course slides for any other purpose than that for which it was intended.


Download ppt "Dynamically allocating arrays within structures"

Similar presentations


Ads by Google