PR2EN7: Dynamic memory allocation

Lab materials

Lab tasks

This week we have one lab task that is extended by two advanced tasks.

Task 1: random data file generator

This week, we will create a program that can generate random data files. These are useful for testing other applications without having access to real data.

Download the starter code: https://blue.pri.ee/ttu/files/iax0584/aluskoodid/7_generator_starter.zip

Requirements
  • Build your application on the starter code given
  • Ask the user for how many generated entries they need. There must be no upper bound!
  • All entries are stored in a struct array during generation. Struct array itself is generated using dynamic memory allocation.
  • Pick random first and last name and curriculum code from the pools given to you.
  • Generate admission points
    • Admission points are in range from 10 to 30, ends inclusive. Precision is 0.1 points (e.g. 24.7)
  • Sort the structures based on the generated last name. If last names for two entries match, order them by their first name.
  • Write the output in the following format:
    <index> <last name> <first name> <curriculum code> <admission points>
    • Index is a unique integer. First entry will have the index as 0, every following one is incremented by one.
  • Make sure that all resources (including memory) is freed when the program exits, use valgrind to make sure.
Qsord comparison function

I’m proposing two different comparison function options. In the first case, the type cast will be done as needed, removing the need for additional variables.

In the second case, we will create temporary pointers that take up some memory, but improve the readability of the code.

Workflow
  • Create the necessary structure declaration to keep the data
  • Ask the user how many entries to generate
  • Allocate the memory, check the allocation!
  • Generate the necessary entries
    • For every person, you must generate the entries randomly.
    • For every field from the pools, you must create a random number to pick out the member
      Hint: you can either copy the name to your struct or only keep a pointer to the name
    • In addition, you need to generate the admission points.
      Hint: Think about this mathematically – e.g. what’s the difference between 30 and 300!?! rand() function will always give you an int, regardless if what you try to do to it.
  • Sort the structure array
  • Write the results to an output file
  • Free the allocated memory

Check with valgrind for correctness! Not only in the end, but also if you encounter some weirdness, crashes or corruption!

Testing

The output of your application should be relatively simple and short.

When looking out the output file, we see that everything is sorted by name (showing only first 15 lines)

Advanced task 1: output file formats

In this task, we’ll add CSV as a secondary output format for our application. User must be able to choose which output format they want.

Requirements
  • Add ability to your program to generate data in the CSV format
    • First line of the CSV must be the header with the field names.
    • This will be followed by data lines. Each member is separated by a comma. NB! In CSV, we don’t put a space after the comma!
  • Ask the user in which format they wish the file to be generated in (CSV or space-delimitted) and generate the appropriate data file.
  • For the space-delimitted file, the extension must be .txt  and for the CSV file, use the extension  .csv .
  • Make sure that the CSV is correctly generated – try to open (or import) it using  Libreoffice Calc’i  or Microsoft Office and see if they recognize the format correctly.

Advanced task 2: settings

In this task, we’ll make our generation a bit more flexible and add settings to it.

Requirements
  • All settings must be kept in a structure – create a new structure declaration for this!
  • All settings must have default values
  • Program must use the defaults if the user does not wish to change the settings. What the user needs to do to alter the settings is up to the developer
    E.g. the program could ask if they wanted to change them as the first thing it does or the user can use a specific command like argument, that allows settings to be edited.
  • User must be able to alter the following settings, while inside of the program.
    • Which data fields are generated (it must be possible to turn each one of them on or off).
    • Name of the output file (only the name part. Extension must be chosen automatically based on the output format!)
    • Output format (this is from advanced task 1, move the location of the setting into the struct).
    • Number of items generated (base task part, move the location of the setting to the struct)
    • Lowe rand upper bounds for the admission points
  • NB! The number of entries generated must be asked regardless if the user wished to change the settings or not. Purpose of this is just to keep all settings neatly in one struct.
  • User must be shown the settings the generation will be performed under regardless if they chose to edit it or not.

Note: if you wish, you can make a settings file, however it is not necessary. The updates to settings do not need to be remembered between executions. However if you do include a settings file, make sure that the user can change those settings within the program without editing the file manually.

Hint: You can make nice use of the trinary operator here
printf("First name: %10s\n", settings.genFirstName ? "Yes": "No");

After this class, you should

  • Know how to use dynamic memory allocation
  • Know how to check for memory leaks.
  • Know in which situations it is reasonable to use dynamic memory and in which situations you should not.
  • Know the difference between function call stack and heap.

Additional materials