PR2EN8: Dynamic memory 2

Lab materials

Lab tasks

This lab has one task that is extended by two extra tasks

Lab task [W08-1]: Reading a file dynamically

The purpose of this task is to introduce how to read an unknown length file and allocate the structure array for it dynamically in the exact length required.

Data file

Data file structure for the task: <index> <last name> <first name> <curriculum code> <points>

  • Index (integer)
  • First and last name – strings with varying length
  • Curriculum code – string with exactly 4 characters
  • Points – floating point value from 10.0 to 30.0 with a precision of 0.1.

You can use the data file generator from last week for this. To test, we’ve also provided files so you can compare your output.

Download data files here that we used in the testing part.: https://blue.pri.ee/ttu/files/iax0584/andmefailid/8_scholarship_data.zip

Requirements
  • Read an unknown length data file into memory
    • Use realloc()  to read the data, expanding your memory as you are reading the file
    • Store the data into a dynamically created structure array
    • Once the reading is finished, you allocated memory size must match the exactly to how many were read from the file
    • You can only read the file once (repeat reading is forbidden, this includes just checking for newline count!)
    • The length of the file can change  – the exact length is determined during reading.
  • All variable length strings must be stored in memory exactly (using dynamic memory allocation).
    • During reading, use a static buffer and then use dynamic memory to store it into the struct.
  • The file contains students competing for a scholarship. Scholarships are given for 7 best students (highest points) of the following curriculums: IACB, EARB, MVEB
  • Print the list of students who will receive the scholarship and also print the number of students who got it from each curriculum.
  • Make sure there are no memory leaks!
Data structure for the task

For this task, we will transition into using dynamic memory for variable length strings (and other arrays) inside of our structure in order to save memory. The struct will now take the following form:

Note:

  • You can alter the naming to your liking.
  • The fName  and lName  are now pointers that need dynamic memory allocation due to the length being variable from person to person.
  • String for the curriculum code is static because the length never changes – using dynamic memory here would be wasteful (slower and more complex).
  • Single variables such as index and points remain static because again, using dynamic for those members would be making the program purposefully slower and more complex.
Recommended list of functions

NB! The actual form the functions take depends on how you tackle the task.

At minimum, you need three functions:

  • Reading the data (check the next subheading).
  • Printing the results.
  • Freeing the memory.

Recommended functions to make your life easier

  • qsort compare function
  • Printing the data of a single student (useful for printing the students who get the scholarship).
  • For defensive programming, use the function shown on the slides

To make sure you read the file correctly, you might want to have a function that just prints everyone’s data. This is however not a part of the task.

Reading the file using dynamic memory allocation

From now, the reading function takes a new form. We need to get 2 values from the reading function – memory location of the array and number of lines read from the file. I’m proposing a three variants for this  function. Choose the one that works for you the best.

Variant 1: Most similar to the previously introduced reading function. It returns the line count and uses a double pointer for for the array.

Variant 2:  By returning the array pointer and passing the line count as a pointer, we can avoid the use of a double pointer.

Variant 3: This one uses pointers for both the array and the line count. This allows us to return the status of the function (did it succeed or failed and potentially how it failed).  This is also the most similar to the natural style of C functions – many of them return if the function succeeded or not.

Note, that using a wrapper struct (extra task 2) is also effective on cleaning up the parameter list.

Variant 1Variant 2Variant 3
Testing

In the first file, we’re using the longer data file where all scholarships got assigned. Notice the heap summary!

In the second example, I’m using the shorter data file.

Extra task 1 [W08-2]: Optimal algorithms for allocation

In this task we’re changing the algorithm how we are allocating memory to a more reasonable one.

Requirements
  • Change the file reading in a way that you would be using the (n * 2) expansion strategy
    • Every time you run out of memory, you reallocate to a 2x higher amount that you have right now.
  • To start, pick an initial allocation that is greater than 1 (pick a size that would be 3x lower than the file length just so you can observe the correctness).

Extra task 2 [W08-3]: wrapper struct

In this task, we’re making our code a bit more readable and contained. We will put both the struct and its properties into a wrapper to keep everything tightly integrated.

Requirements
  • Put your structure array pointer into the other struct (wrapper)
  • In your wrapper, you should have 3 variables – pointer to the struct, number of structs allocated, number of structs used
  • Change your function parameters for the existing functions to use the new wrapper struct
  • NB! Think through for which functions it is required to pass a pointer to the wrapper where it is unnecessary.

Hint: Now you will need an extra access layer to get from the wrapper to the struct itself. To help with readability, you might want to “unpack” those variables when you need to use them. See the following example.

After this class, you should

  • Know how to use defensive programming to handle memory freeing
  • Know the definition of a dangling pointer and how to safely handle dangling pointers
  • be able to to structure your code in order to read files that can be of any length
  • be able to handle changing the size of a dynamically allocated array
  • be able to read data into an expanding array using dynamic memory allocation
  • know all possible ways realloc works
  • know the difference between (n + 1) and (n * 2) allocation strategies and be able to implemetn at least one of the two
  • be able to  allocate memory to members of structures
  • Know all the steps strdup() does in the background and be able to use it

Additional materials