All posts by risto

PR2EN5: Qsort and dividing code

Lab materials

Lab tasks

This lab has two tasks

  • First task consist of two separately graded parts plus an additional advanced task.
  • Second task consist of a base task and an advanced task.

Task 1: Quicksort

This task is based on practicing using the  qsort()  function to sort both basic data types and structs. During this, we will also start dividing our code into multiple code files and you can also start making your first header file. The starter code already has file structure given for you.

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

NB! The base code contains code for both parts of the base task and the advanced task as one! 

Requirements
  • Implement the functions that are described in the header files required for the specific part of the task (look below for parts description). Implementation must be written in the .c file with the same name.
  • Call the required functions to sort and display the results from the switch statement in the main function
  • Compile the code from multiple files as was given by the structure in the starter code. Use command line to do so (or Makefile if you already know how).
Graded parts of the task

For part one of the base task, you must have menu options 1 and 2 completed. For this you must

  • Implement the qsort comparison function for arrays made out of integers and real numbers
  • Call out the qsort function with the comparison function made before as well as the print function to prove completion of the task.

For part two of the base task, you must have menu options 3 and 4 completed. For this you must

  • Implement the qsort comparison function for arrays made out of structures. One of them must compare the first name, the other one the employment length.
  • Implement the function to print out the structure array
  • Call out the qsort function with the comparison function made before as well as the print function to prove completion of the task.

For the advanced task, you must have menu option 5 completed. For this you must

  • Implement the qsort comparison functions to compare the structure array members based on their last name. If the last names are the same, you must use first name as an additional criteria for sorting the structures.
  • Call out the qsort function with the comparison function made before as well as the print function to prove completion of the task.
Testing

The following example includes all three graded parts (part 1 and 2 as base tasks and the advanced task).

Click me to see the output

Task 2: External libraries (covid-data)

In this task, we’ll introduce you how to include and compile programs using external libraries. We will use the libcurl library, which can be used to access various online APIs, download files etc. We’ll use this to download Estonian governments opendata. We’ll also proceed to practice dividing code into multiple files.

NB! To simplify your life, solve this task on a UNIX based operating system (e.g. Linux). It can be done on Windows, but the additional setup for this is more exhaustive and you need to change a few parts of the given source code.

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

Requirements
  • Use the starter code given, follow the structure provided.
  • Download Estonian Covid-19 opendata (already given in the starter code)
    NB! The open data is updated once per week!
  • Data specification
  • Display the confirmed cases for the last 14 days
  • Display the top 10 days with the highest confirmed cases count.
  • At minimum, your code needs to be separated into three code and header files
    • file_helper.c  and file_helper.h  contain the data download and preparation (given in the starter code, no need to modify)
    • data_processor.c  and data_processor.h  contain the reading and processing of the data
    • main.c  and main.h  have controls for the program flow and generic macros.
    • If you want, you can separate out reading of the file and processing the data to additional files.
  • Compile all the code files together either from the command line or by using a Makefile.
Recommended workflow
  1. Get acquainted with the structure and the contents of the code files.
  2. Comment in the preferred download format (either space or comma separated data).
  3. Compile and see if the data download works. To compile, you need to add an additional flag  -lcurl
  4. Add a description of the data structure and the necessary macros for sizes to the  main.h  header file.
    Hint: You don’t need to store all of the data from the file in the structures. Pick only the data you need.
  5. Write the reading function to read data from the file into memory into  data_process.c  . Add the prototype to that function into  data_process.h  header file and call the function in the main() function.
    NB! Did you notice the contents of the first line of the file?
    Hint: To ignore a certain field in the file, you can use the format %*s  in the 
    scanf  function. Asterisk notes that the field matching this format will not be stored. In this case, any string until a space or a newline is encountered will be ignored. When you use an asterisk in the format, you also don’t need to provide a pointer where to store the data (scanf parameter).
    Compile and test if your data is successfully read into the structure array!
  6. Create a function to print the data. Call it to print the last 14 days of data.
    Hint: Use your knowledge of arrays and poiinter-arithmetic that we used in the first week (task 1, part 2)! This way you will get a simple printing function that you can reuse in the next step.
  7. Create a comparison function for  qsort  to sort by the confirmed case count and and call qsort  to sort the data. Display the top 10 days based on confirmed case count.
    Hint: If you used pointer-arithmetic to call the printing function in the last step and left your print function to be as simple as possible, you can reuse it to print the top 10!
Testing

NB! The output contains both the base task and the advanced task!

Advanced task
  • Find the number of cases for the last 7-day period.
  • Find the number of cases for the 7-day period preceding it.
  • Print out the date ranges and infection counts for both periods.
  • Find and print if the case count as increased, decreased or remained the same from one period to the next. Also print out the change as a percentage, showing two places after the comma.

Hint: The array was sorted during the base task and cannot be used for the advanced task in a good way without resorting (which we should always avoid if possible). We can however prepare a partial copy of the original data, before we run qsort to sort it. To make a copy, check out the function  memcpy()  – look into the parameters it requires to set the starting point of the copy, you can use pointer arithmetic to make a copy of only the relevant data.

MS Windows

This task is also solvable in MS Windows, however it is a bit more tedious, requiring a few additional steps. These steps have been tested in the spring of 2022! This assumes you installed the 64-bit version of the MinGW (e.g. through chocolatey – as given in the simple installation guide for MS Windows, using the command line).  The steps are given as a transcript of the conversion from last year and are provided as-is!

1. Install libcurl on Windows. Uses chocolatey package manager

choco install curl

2. Make the library (dll file) available to the compiled program. Copy libcurl-x64.dll from libcurl installation directory to your program directory (assumes 64-bit compiler).

3. You need to download CA certificate so cURL can verify the certificate on the opendata website https://curl.se/ca/cacert.pem.

4. You need to specify the certificate authority file location to the code. Add this to the setup of the download in the file_helper.c, replacing the path\\to\\file with the path to the downloaded .pem file.

curl_easy_setopt(curl_handle, CURLOPT_CAINFO, "path\\to\\file");

5. You need to rewrite the check if a file is already downloaded because that uses POSIX library available on UNIX systems – unistd.h. You should rewrite it with windows solution of that. Haven’t tested, but you’ll likely find the function BOOL FileExists(LPCTSTR szPath) in the library io.h. You may need to add additional Windows-specific libraries.

6. You can only download as CSV with the code provided. To download space delimited, you need to rewrite the ReplaceChars function. Easy option would be to open up a second file pointer for writing to a different file and remove the fseek, Simplest would be to do getchar -> putchar with a check in between for commas to be replaced with spaces.

7. You need to add -I and -L flags to your compiler command line arguments. Mine were:

-I C:\ProgramData\chocolatey\lib\curl\tools\curl-7.81.0-win64-mingw\include\ -L C:\ProgramData\chocolatey\lib\curl\tools\curl-7.81.0-win64-mingw\lib\

After the class

  • Be able to separate your program between multiple (.c) code files and compile them into a program.
  • Know how to use the qsort function.
  • Understand the requirements for the qsort comparison function and be able to write such comparison functions for simple arrays and structure arrays.
  • Know about the existence of function pointers and be able to pass a pointer to a function to another function.
  • Know the general steps required to use third party libraries with your programs and be able to compile a program with them.

Additional materials

PR2EN4: Structures 2 and basic header

Lab materials

Lab tasks

For this lab, the base task is divided into two parts graded separately.

Lab task part 1: Print associated data

In part one, we’ll print the data we are reading from the data files. For this, we need to make sure to make the necessary associations.

Data files

The data is given to you in 2 files, described by an ERD (entity-relationship diagram.

Note: These kind of diagrams can also be shown as UML class diagrams. Check additional materials for a link.

ERD cardinality rules state that

  • A person may own 0 or more vehicles
  • Every vehicle must belong to exactly one person

The data is being associated by the Estonian ID code (person_id)

Download the data files from this link: https://blue.pri.ee/ttu/files/iax0584/andmefailid/4_data.zip

Requirements
  • Implement a header file. Store the struct declarations, macros and function prototypes in there. If necessary, also enums.
  • Read data from two files given to you. Store it in two separately declared structure arrays
    • Avoid more complex solutions such as substructures and pointers to structures during the lab task!
    • eID must be stored as a 64-bit integer in the structures. This will reduce the CPU clock cycles required for comparisons! Use inttypes.h !
  • Practice pointer arithmetic with struct arrays
    • Use the array (->) member-access  operator whenever working with the struct arrays (reading, writing, comparing)
    • Avoid square brackets []for indexing struct arrays
  • Sort the list of people alphabetically in ascending order by their first name.
  • Print out the list of vehicle owners, followed by all the vehicles they own
    • Write the owners information only once as a header
    • Follow this by printing all the vehicles they own
    • For people without any associated vehicles, write an appropriate message
Recommended functions

NB! The list here is just a recommendation. Your functions and their parameters can be different.

Testing

This is the expected output from part 1

Lab task part 2: Calculate taxes

Part 2 continues on part 1 with all the existing requirements staying in place and continuing through this part of the task.

Requirements
  • Find and print the taxation values for every person.
    • Print both the sum as a value and as a percentage to the annual income.
    • Write a warning if the tax percentage is 10% or greater than their annual income.
    • Write an error if there is no income
    • Remember! Make functions that only do one thing. Do not put calculations in the same function as reading the data or printing. Have a separate function that only does the tax calculations!
  • Hint: You should add additional member(s) to your structures to be able to store and display the required results!  Structure members don’t need match exactly to the data fields in the file, adding or even processing and storing it differently in memory is OK.
Recommended functions

NB! The list here is just a recommendation. Your functions and their parameters can be different.

Testing

This is the expected output from part 2

After this class, you should

  • Know how to create and include a header file to your code file
  • Know what should be written to the header file and what must not be written there
  • Know common use cases for headers
  • Know what’s the difference and how the addressing changes whether you are using quotes “” or angle brackets <> to include a header
  • Know why we need guards for the headers and how to implement them
  • Know how to embed debugging statements in your code using macros in two different ways
  • Know how to initialize structures
  • Know how to nest structures
  • Know how to return a structure
  • Know how and when to use the arrow operator to access structure members
  • Know how to use pointer arithmetic when working with structure arrays
  • Be able to read simpler ERD diagrams and know what they are used for modelling data
  • Know that there are class diagrams in UML that are similarly used to model data as ERD diagrams are.

Additional materials

PR2EN3: Structures

Lab materials

In the lab, a sample solution will be written together and commented where data fill be read from the file and stored in a struct array. This is also published as a code example for those not participating in the labReading from a file into structure array

Lab tasks

In this lab, you have one task which is expanded by 4 advanced tasks.

Lab task: employee search

In this program, we will mimic an employee database from where we will filter out employees based on search criteria.

Data file

Download the test data from the following link https://blue.pri.ee/ttu/files/iax0584/andmefailid/3_data_short.zip

Data file is composed of randomly generated data.

Requirements

  • Read employee data from the file
    • File has one  record per line
    • Every data field is separated by a space. All data fields are single word.
    • Data structure in the file:
      <eID> <first_name> <last_name> <city>
  • You need to keep the data in the memory as a struct array
  • Program must work in a situation where the exact number of records is unknown and can change (e.g. somebody gets employed, fired or leaves)
    • Create a reasonable limit in your program and test that you wouldn’t go beyond it
    • If the data file is longer than the allowed limit, print a corresponding message. Behavior after this is up to you.
  • Allow the operator to perform searches based on the city name
    • Program will output all employees in the city
    • Show how many matches were found (E.g. [0 / 91])
    • Search must be repeatable without exiting and restarting the program
    • In the base task, print all the data available – eID, last name, first name, city
  • User must be able to exit the program when they desire. Create functionality for that (e.g. a specific command)
  • Reading the data file more than once within your program is not permitted.
  • The structure members don’t need to be an exact match for the file. You can add additional struct members – this is useful for the advanced tasks.

Example output

NB! The example output already includes all 4 advanced tasks!

Click me to see the output

Advanced task 1: Sorting structures

Requirements:

  • The list of employees must be sorted alphabetically by the last name in ascending order.
  • Output name format must be  last name, first name

Advanced task 2: List available cities

Requirements

  • List all the cities present in the file
  • List of the cities must be generated based on the data file (must not be hardcoded into the program)
  • Operator must be able to print the list of city whenever they wish by typing the appropriate command. Add a command for this to your program.
  • Operator must be able to repeatedly print out the list during the runtime of the program.
  • The list of the cities can only be composed once per execution of the program.

Advanced task 3: Better search

Requirements

  • The search must be case-insensitive. Searching for either  TALLINN  or tallinn  must print all employees living in Tallinn.
  • Search must support partial matches. E.g. when searching for  all , you should display employees living both in Kallaste and Tallinn.
  • Both features must working at the same time. The last result should also be obtainable by entering ALL or aLL

Advanced task 4: Parse the eID

Requirements

  • Do not display the eID in the output of your program
  • Display the employees date of birth with the format d. MMMM yyyy

Official information about eID: https://www.riigiteataja.ee/akt/114022017005

Short description of it in English: https://en.wikipedia.org/wiki/National_identification_number#Estonia

Click me to see date and time format guide

m – Minutes from 0 to 59.
mm – Minutes from 00 to 59. Minutes from 0 to 9 are prefixed with a zero.

h – Hour from 1 – 12.
hh – Hour from 01 to 12. Hours from 1 to 9 are prefixed with a zero.
H – Hour from 0 – 23
HH – Hour from 00 – 23. Hours from 0 to 9 are prefixed with a zero.

d – Day from 1 to 31
dd – Day from 01 to 31. Days from 1 to 9 are prefixed with a zero.
ddd – Day as a short name (Mon, Tue, Wed, …)
dddd – Day as a long name (Monday, Tuesday, Wednesday, …)

M – Month from 1 to 12
MM – Month from 01 to 12. Months from 1 – 9 are prefixed with a zero.
MMM – Month as a short name (Jan, Feb, Mar, Apr, …)
MMMM – Month as a full name (January, February, March, …)

y – Year from 0 to 99
yy – Year from 00 to 99
yyy – Year with a minimum of 3 digits (1 -> 001; 15 -> 015; 145 -> 145; 1949 -> 1949)
yyyy – Year with 4 digits

After the class, you should

  • Know how to declare a new structure type
  • Know how to pick members for a structure
  • Know what is structure padding and how it affects the size of the structure
  • Know what affects the final size of a structure
  • Know which structure member access exist and be able to use the dot operator
  • Know how to create an array of structures and read data from a file into that array of structures
  • Know how to assign structures
  • Know how to give existing types new names (use typedef)

Additional content

PR2EN1: Pointers

Lab materials

Reminder on style

  • Your code should be easily readable
  • Have a uniform style
  • Simple over bloated
  • Be commented (not required for lab tasks, tests and exams)
  • Be modular (code is divided into short, simple, easily reusable functions that you can reuse in the future, including during the test and the exam)
  • Use optimal algorithms and data structures (covered so far during the course)
  • Typically avoid global variables (we will see exceptions this semester)

Tasks

There are two lab tasks this time. Second task is given in two separately graded parts. Advanced task builds on the second task.

Lab task 1: Pointer to a variable

This is a classical swap the two values in a function task.

Download the starter code here: https://blue.pri.ee/ttu/files/iax0584/aluskoodid/t1_swap_template.c

Requirements
  • Use the starter code provided
  • All parts you need to complete are marked with TODO in the starter code
  • Create two functions according to function comments in the starter code. One to read values, second to swap values. Call those out
  • Print out the memory addresses where the data is stored in 3 different locations
    • In main function, the original locations of the variables
    • In the reading function, show the addresses where you are storing the values
    • In the swap function, show the location where the values are you are swapping
  • Explain the significance of the address values when defending!
Testing

Lab task 2 part 1: Pointer to an array

In the second lab task, we will explore the memory addresses in an integer array and use pointers to get multiple values out of a function. Additionally, we will be practicing pointer arithmetic.

Requirements

Create a program that fulfills the following requirements

  • During this task, you are not permitted to use square brackets [] for indexing the array. For indexing, pointer arithmetic must be used. The array itself can still be declared using square brackets.
  • Create a function, that reads 10 numbers and store them in an array.
    Reminder: Pass both the array and the length of the array to functions!
    Hint: read them from a file or use stream redirection to speed up testing!
  • Create a function that prints out all numbers and the memory address where they are stored
  • Create a function that  find both the minimum and maximum number
    • You can only call this function once – it must find both results in one go and store them
    • The function return type must be void .
    • Assume that only one minimum and maximum exists
    • Use the concept of pointers to solve getting multiple values from a function.
      • Do not use arrays to store min/max values!
      • Do not print the results in this function.
  • All created functions must be called from the main() function.
  • Minimum and maximum value are printed in the main() function.
Testing

Expected output of part 1

Lab task 2 part 2: concept of pointers to arrays

The purpose of part 2 of this task is to make sure you understood the concept that an array can be interpreted as the pointer to the first member.

Requirements
  • Create (or reuse) a function that is able to print n numbers and their memory addresses in the array.
  • The function can only have two parameters.
  • The function must be built in a way that it is able to print any arbitrary sequence of values from that array.
  • To demonstrate that you wrote this function correctly (and understood the topic correctly), call the function 3 times, so that
    • it will print out all members of the array
    • it will print out elements 0 to 4
    • it will print out elements 3 – 9

Hint: Think before acting! This part of the task is about the concept of pointers and arrays rather than creating some very clever and devious solution! Do not attempt to over-engineer the solution, it is not a puzzle!

Testing

Expected output of part 2

Advanced task: minmax task with addresses

In this task, we will recreate the minmax function from part 1 of task 2 . We add the ability to also print the memory addresses and indexes for the minimum and maximum value.

Requirements
  • Create a new function or alter the existing one to find the locations of the minimum and maximum elements in the array in one go.
  • The return type of this function must be void .
  • The function can have 4 parameters
    • Array
    • Length of the array
    • 2 pointers or double pointers – figure out what to store in them!
  • In the main function, print out the following results
    • The min and max value
    • The addresses of where the min and max are in the original array
    • The indexes of where the min and max value are in the original array.
    • NB! You are not allowed to loop through the array more than once (e.g. once to find min/max, second time to find the position)! You must use the idea of pointers to calculate the results!
Testing

Expected output of Advanced task

After the class, you should

  • Understand the requirements for this subject, including how to get a grade
  • Understand what a pointer is
  • Understand the significance of memory addresses
  • Understand virtual and physical addresses
  • Know what affects the address length
  • Know the extra memory requirements for explicit use of pointers
  • Be able to declare pointers
  • Know the coding style aspects of declaring and using pointers
  • Know what’s the importance of pointer data types
  • Know the significance and use for NULL pointers
  • Know the two pointer operators and where to use them
  • Have some understanding of possible use cases for pointers
  • Know how to use pointer arithmetic
  • Have a better understanding of the scanf arguments and how pointers come into play here
  • Understand why we said that arrays were editable when passed to a function, but variables were not
  • Be able to pass the addresses of variables to functions as pointers
  • Be able to edit multiple variables in a function
  • Understand the concept of double pointers
  • Know how to use a ternary operator

Additional content

PR2EN2: Enumerations

Lab materials

Tasks

The lab has two tasks. These tasks cover a lot of topics from Programming 1, but are enriched with the enumeration topic introduced this week.  Both tasks also benefit from the pointers covered last week.

Lab task: File categorization

In this task, you will create a utility that will be able to count how many files of each category exist (e.g. how many image files in a directory and its subdirectories).  We will only create the part that categorizes files and counts the totals.

To find the names of files, we will use knowledge from the Linux task lask semester. We will use a tool called find  to find the files recursively  and pipe them to our program. By doing this, we will be able to index and categorize any amount of files recursively in all subdirectories.

Note: To demonstrate the potential of combining programs you need to be in a Linux. Easiest way is to test in the university environment (use the lab computer, Horizongate or create an SSH tunnel to one of our servers or lab computers).

Requirements

Create a program that

  • Accepts an unknown number of file names from the standard input ( stdin ).
    • You are not allowed to preemptively ask for number of inputs or have a designated string to stop reading inputs.
    • To stop reading the strings and show the statistics, listen for the EOF  (end of file) signal.
  • Categorizes those files to groups based on the identifiable extensions and counts how many files in each category.
  • Display how many files were in each category.
  • Categories must be identified as enumeration type in code.
  • One of the functions you need to have is specified for you. It needs to  take the file extension as a parameter and returns the enum of the category. Proposed function prototype:
    enum FileCategory GetFileType(char *extension);
  • Your program can provide a prompt when started (i.e. instructions), but must not write anything to the output in between inputs.
Categories and extensions
  • Archives: zip, rar, 7z, tar, gz
  • Data: csv, xls, xlsx, ods
  • Documents: pdf, doc, docx, rtf, odt
  • Code: c, h, cpp, hpp, py
  • Text: txt
  • Images: jpg, jpeg, png, svg,
  • Other: all files with extensions, but not in the previously listed types
  • No extension
Template for the task

In order to give you a bit better idea on the expected structure and how the reading and processing would work, you are provided a template to base your task on.

Recommended steps for solving the task
  1. Add a function that will fix the trailing newline in the read string
    I.e. void FixTrailingNewline(char *str);
  2. Add a function that will find the location of the last point (.) symbol in the string to identify the start of the file extension.
    I.e. int GetLastPointPos(char *str);
  3. Add the category enumeration to your code and create an initialized array of counters for the categories.
  4. Add a function to print the array of counters (result)
  5. Add a function that will, based on the given extension, find the category of the file.
    I.e.  enum FileCategory GetFileType(char *extension);
Hints and warnings:
  • Check out the additional enum example on this page. It is based on a similar categorization task, it will offer quite a few ideas on code structure.
  • You should recognize various subtasks from last semester – i.e. parts of the first and second strings lab task and age classifier home work.
  • If you add a count item after the last enumerated item, it will tell you the number of items in the list. This will only work if you allow it to automatically number all items!

    This allows you to automatically declare the correct length array for counters.

  • By using what you learned about pointers last week (i.e. pointer arithmetic),  you can use the location of the point as an offset to calculate the address where the extension starts. That new address would also be pointing at a string.
  • The length of the reading loop is of unknown length. fgets()  returns NULL  when EOF  (end of file, indicating no more inputs) is reached.
  • fgets()  stores the trailing newline character which needs to be corrected for.
  • Input for your program comes from a pipe to your programs stdin
  • To quickly test without the command line, you can hit ctrl+d  to send the EOF  signal
Testing manually when creating the program

To test manually, we can run the program normally, type in the names of files, pressing enter after each file name. Once done, hit ctrl+d  to send the EOF (end of file) signal.

Testing correctness

To test the correctness, we will index a folder that I have prepared for you. Your numbers for each category should match the ones presented in this example.

We use a tool called find to search for files and folders and limit it to only show files and print without the path. First we show the location where we are searching in, then we specify to only show files (omit folders) and we then print the names of files without the path. This will be piped into the program we just created.

Command executed: find ~/M/risto.heinsar/lab_cat/ -type f -printf '%f\n' | ./task1_category

Hint: if you’re curious, you can also test your own P drive and add extensions and/or categories.

Backup for when university network fails

Note: if you are unable to demonstrate the correctness due to networking issues or the systems go offline, you can can demonstrate the correctness by using the following the archived version of the directory structure.

https://blue.pri.ee/ttu/files/iax0584/andmefailid/2_1_file_cat_directory_structure.zip

The structure is the same as on the M drive.

Lab task 2: Distance conversion

You have been provided activity data from a group of employees in an international company. Your task is to convert all data to the desired output units, show the results and give basic statistics.

Requirements
  • Program takes 2 command line arguments
    • First argument is the name of the input file
    • Second argument is the desired output unit of distance (available options: m  for meters, ft  for feet and km  for kilometers)
  • Input file is a basic ASCII text file (first command line argument).
    • Each line in the file contains one entry
    • Each entry consist of two fields, separated by a space: <distance> <unit>
    • Distances are given as real numbers
    • Units are given as strings. Units in the input file can only be in feet or meters.
  • Calculate and display all distances, converted to the desired output unit
  • Calculate and output the average and total distances walked.
  • All distances are shown with 2 places after the comma.
  • Units must be handled using enums. Recommended list is provided:
  • Conversion coefficients are also provided
Data files

There are 3 files provided for you to test your program with. Look under the paragraph Testing for what you should look out for when testing with each of the files!

Download the test files: https://blue.pri.ee/ttu/files/iax0584/andmefailid/2_2_converter_data.zip

Hints and tricks

There are a lot of units in play. Printing the correct one can be a bit tricky. There are two ideas to help you with:

Option 1: Create a function to print the unit and call it when you need it. Call it whenever you need to print the correct unit according to the task.

Option 2: Create a function that will return you a pointer to a string containing the unit.  Since it is written as a constant, it will be available in the memory after the function returns. It makes this really convenient to use it in print statements – e.g. printf("%.2f %s\n, distance, ReturnPrintableUnit(unit));

Testing

This program has a lot of ways it can go wrong. Make sure to test for all constraints!

Test 1 – 3: Invalid arguments

This test actually is comprised of 3 different tests, but all of them have wrong arguments passed to the program.

Test 4, 5: Problematic arguments

The next two tests are about parsing the arguments themselves and making sure that both the file exist and the unit is within the allowed list.

Test 6: empty file

The purpose of this test is to make sure that our program does not crash when there is no data to process.

task2_data1.txt contents:

And the results for this data file: 

Test 7 – 9: Conversion tests

In these tests we will go over all of the possible input and output unit conversions. We use a simple data file that allows us to easily observe if our answers are correct.

task2_data2.txt contents:

And the results for this data file:

Test 10: Different file

The emphasis for this test is to test your program with a different data file – just different length and units to make sure that nothing got passed us by.

task2_data3.txt contents:

And the results for this data file:

Sidenote: did you notice what we didn’t test for, but cold also be improtant?

Advanced task: comprehensive converter

The advanced task is based on lab task 2 and must be an extension of the base task. Disregard the concept of “walking” and consider the task as just a distance converter with statistics.

Requirements
  • Add support for additional distance units
    • Yard (yd)
    • Inch (in)
    • Decimeter (dm)
  • You must allow all 6 units to be both inputs and outputs for the program.
  • Design the conversions in a expandable fashion so that if we would add additional units, it wouldn’t require large overhauls of the code. The complexity of adding another unit must not expand the codebase exponentially!

Warning! Even though the expected  method for conversion is simple to implement and manage, it may increase the error of the final result due to rounding of the conversion coefficients outside of metric system. Be careful with tasks requiring high precision!

After the class, you should

  • Be able to work with enumerations
    • Declaring new enum types
    • Declaring variables based on enum types
    • Pass enums to functions, return enums from functions

Additional content

Note: most sites explaining enumerations can’t even follow the same coding style on a single page! Use the style guide provided by us!

6. lab: functions

Lab material

Lab tasks

For this lab, you have 2 tasks. There is also an advanced task, which extends the features of lab task #2.

In the first task, you need to write the declarative part of functions in a pre-written program. In this task, you will only be working with variables.

In the second task we focus on arrays and you have to write the entire program.

Task 1: Electricity price calculator

In this task, we have written most of the program already. This includes the entirety of main()  function.

You will need to fill in the missing parts in the functions for this program. In the base code, all of the returns from the functions have been written as return 0 . This is done so that the program would compile and you could test it step-by-step. You need to replace this in every function based on the description in the function comment, right above the function itself.

Download the starter code from here: 6_1_electricity_basecode.c

Requirements
  • Start by introducing yourself to the base code. Your task must be built on it.
  • Your task is to write te declarative part of seven functions. The purpose of the function is described right before it as a comment.
  • main()  function and the structure of the code cannot be changed. It’s recommended to also avoid renaming the functions and variables.
Recommendations and hints
  • Start by going through the code. Look at where all the parts of the code are – libraries, macros, prototypes, main function and the rest of the user-defined functions. Check out how main calls the user-defined functions, what is given as parameters etc. Do not change anything right now!
  • Once familiar, start by writing the function bodies (declarative part of the function). Solve 1 function at a time, compile and test if it works! Do not move forward before it works!
  • The recommended structure for the input functions is a do while loop, which has an if statement inside to print an error for wrong input.
  • All other functions are solvable by just writing one line. You need to replace the  return 0  with the correct formula.
  • Careful with units! There is a mix of megawatw-hours, kilowatw-hours and watt-hours! Check the function comment for which it is.
  • VAT – value added tax, 20% in Estonia
  • Current market price in MWh before taxes:  https://dashboard.elering.ee/et
  • Current market price per kWh in cents, including taxes:  https://www.elektrikell.ee
Testing
Test 1: no errors
Test 2: invalid input tests

Task 2: finding results from an array

The purpose of the second task is to find results from a user-entered array, based on the knowledge acquired so far. The functions you create must be universal (array length must not be fixed, but passed). These will also be the first function in your own collection of functions that you can easily copy in as needed later in the course!

Requirements
  • Program should read 5 integers from the user. Numbers must be from -100 to 100, ends inclusive.
  • Print out the numbers entered (self-check)
  • Find and print the arithmetic mean with 2 places after the comma.
  • Find and print the smallest value in the array
  • Allow the user to enter a number and then find if it was a part of the originally entered array or not.
  • All functions must be made according to the function descriptions provided on this page under “Step-by-step guide to solve the task”
Code general structure

This is a general recommendation of order of operations for the code which you may use as a template.

Step-by-step guide to solve the task

In addition to what you have studied before, the following rules also apply

  • Constants defined as macros that could vary from task to task (e.g. array length, min and max values, tax percentage) must be passed as a parameter. This does not apply for magical number that will never change (e.g. mass of an electron, universal gas constant, pi).
  • The functions you create for calculation results must not have side effects (e.g. arithmetic mean, min value, does the vaule exist in an array). The result must be returned and printed out in main. Printing the result in the function is not allowed.
  • Side effects are allowed (and expected) in functions dealing with input and output (e.g. reading a single integer, printing of the array).
  • No global variables! All variables must be declared as local variables, values should be passed as parameters and given back using the return value.

Solve the program step-by-step. Test your code every time after you complete a function. The functions are given in the order in which we recommend to complete them for this task.

You must create all functions described below. There can be more functions than initially may seem reasonable. Just as a reminder – the philosophy is to write simple and short functions that typically don’t have any side effects and that do only one thing (and do it well).

 ➡ Function: reading a single integer

Description:

Reads one integer from the user, that is checked to be in the allowed range. The function must not return before the entered value is within the allowed range. If the user entered number wasn’t between the allowed minimum and maximum, the user will be warned and prompted again.

Parameters:

  • integer – minimum allowed value.
  • integer – maximum allowed value.

Return: integer, that is between the allowed minimum and maximum.

Use: You will need to ask the user for input in two places in your program. Use this function for both of those!

 ➡ Function: filling the array

Description: Function is used to read n integers and store them in the array. However the function itself does not include any  scanf()  statements to read the values! To read a number, instead it will call the function “reading a single integer” and the value returned by it will be stored into the array. This will be done repeatedly in a loop for each member of the array.

Parameters:

  • integer array – the array that will be filled.
  • integer – array length.

You can add 2 extra parameters, min and max, if you wish to do so (lower and upper bound of the values).

Return: none.

 ➡ Function: printing the array

Description: Function prints values stored in the array.

Parameters:

  • integer array – the array that will be printed.
  • integer – array length.

Return: none.

 ➡ Function: arithmetic mean

Description: Function finds the arithmetic mean from the array and returns it.

Parameters:

  • integer array – array, that contains the members of which the average will be calculated.
  • integer – array length.

Return: real number – arithmetic mean.

 ➡ Function: minimum value

Description: Function finds the smallest member of the array and returns it.

Parameters:

  • integer array – values from where the minimum value will be searched for.
  • integer – array length.

Return: integer – smallest number in the array.

Testing
Test 1: no errors
Test 2: errors in input

Advanced task 1: Check if value in array

For this task, you will create a function that checks if a given number is in the array or not.

You can use a boolean value instead of a coded integer, however boolean data type is not yet covered in the class (will be in a few weeks).

Reminders:

  • When returning a coded integer, avoid magical numbers! 0 and 1 are magical in this context because they have a meaning.
  • Function cannot have side effects.
Function description

Description: Function looks if the entered value is within the array or not. The result will be coded as an integer and returned.

Parameters:

  • integer array – values from were the search key is being looked for.
  • integer – array length.
  • integer – the value that is being looked for.

Return: integer – was the entered number present in the array or not.

Testing

Advanced task 2: multiples of n to the new array

  • User enters a multiplier (positive integer). Reusa a function you already have made!
  • Create a function inside of which you will fill the members for a new array
    • Values where the absolute value is a multiple of the entered multiplier will be added to the new array. New array members must also be absolute values.
    • Function cannot have any side effects – it is not allowed to print the array. In addition, you are not allowed to call a print function from this function.
  • Print the members of the newly populated array. Use a function that you already have made before.

E.g.: Input array (-5, 3, -12, 9, 22), multiplier (3), formed array(3, 12, 9)

After the class, you should

  • Know the difference between a local and a global variable
  • Understand what a function is and why it is important to use them
  • Understand that we have been using functions from the first week. Both functions that return values and those that don’t!
  • Understand, that we can create functions just like those we have been using.
  • Understand the following terms
    • Function prototype
    • Function return type
    • Function arguments
    • Function parameters
    • Function header
    • Function body
  • Be able to create proper functions
  • Be able to pass variables and arrays to functions
  • Be able to store the value returned from a function
  • Be able to reuse functions with different arguments
  • Be able to decompose your code into smaller functions
  • Have a small list of universal functions that you can reuse in future codes! This list of functions will increase every week from now on.

Additional content

PR1EN15: Files

Lab materials

Lab tasks

This lab has two tasks, both of which have advanced tasks building upon the base task.

Task 1: Odd or even

The main purpose of this task is to practice having multiple files open at the same time while getting all the technical nuances correct.

Requirements
  • Read an unknown number of integers from a file. Numbers are separated either by a space or a newline. There can be infinitely many numbers.
    • Example: 5 3 -6 0 25 955 -1024
  • The numbers will be divided into files based on the following principles:
    • 0 or lower numbers are ignored.
    • Positive odd numbers are written to the file odd.txt .
    • Positive even numbers are written to the file even.txt .
  • Follow the basic best practices for working with files
    • Opening of the file is always checked.
    • Notify the user if the file doesn’t open, including which file it was.
    • Close the file before exiting.
  • If the input file is corrupted, the program must halt upon detecting it
    • E.g. 9 -5 hey 14
Warnings and hints!
  • Be very careful with infinite loops when writing to files. You can fill up the drive space in just a few seconds
  • Write the output on the screen during testing so you can follow along what’s happening and to which file data is written to. This way it is easier to detect if something goes wrong and terminate the program ( ctrl+c )
  • If the first file opened successfully, but the second one didn’t, you must close the first one!
Advanced task 1: Statistics

Find the following statistics

  • Sum and arithmetic mean.
  • Smallest and greatest number.
  • The results must cover all the values from the input file regardless of the value (this includes negative numbers).
  • You’re not allowed to read the file more than once.
  • Program must still work with infinitely many numbers.
Advanced task 2: command line arguments

Add support for command line arguments. Change your program as follows

  • The name of the input file is always read from the command line
    • If the name of the file was not given, give an error and exit
    • The name of the file must always be the first argument
  • Verbose
    • Your program must detect if the argument -v  (verbose) was passed to it.
    • This is a common argument to make the programs chatty (simplifies detecting errors).
    • Program will display when and which input files were open (including the name of the file).
    • Program will display all numbers read from the input.
    • Program will display (if) the value was written to an output file, including which file, or discarded.
    • Program will display closure of each file
    • If verbose is not active, the program should not print any lines in the output (terminal), with the exception of error messages and advanced task 1.

Both of these arguments are widely known and used practices for command line programs, but are are also often available for graphical programs.

Examples of how the program should be executed:

  • ./parity input_nums.txt
  • ./parity input_nums.txt -v

Task 2: Processing penalty notices

Your task is to create a program that can compose penalty notices from speed camera measurement data.

Additional references

The task is composed based on the following guidelines

Principles of penalties
  • The measurement uncertainty is 4 km/h (50 – 90 km/h speed limit area)
  • The processing of the penalty is started if the vehicle exceeded the speed limit by at least 3 km/h.
  • Every km/h that is exceeded from the limit is fined by 5€.
  • Maximum penalty is 300€.
  • If the speed limit was exceeded by more than 50 km/h, a general procedure is started.
  • E.g. If a vehicle is driving 99 km/h and the speed limit is set at 90 km/h, the fine is going to be 25€.
Input file

Download your input file from here: 14_2_speeds.txt

Input file contains one measurement per line. The structure of the input file is: <registration number> <measured speed> <speed limit>

  • Car registration number – up to 9 characters
  • Measured speed – positive integer
  • Speed limit – positive integer
Output files

Your program must create two output files – one with processed fines and another for general procedure calls.

First file will contain fines. This file will only contain  fine notices that the owners of the respective vehicles need to pay. Each fine notice will be written on a separate line. Every line has three data fields:

  • Car registration number
  • Exceeded speed without the measurement uncertainty (how many km/h in excess was measured)
  • Penalty (amount to be paid)

Expected output:

The contents of the second file are notices for general procedure. You can only write those entries against whom the general procedure will be started. The format for those notices is as follows:

Expected output:

Advanced task: Settings

Due to regulations and laws changing, it must be possible to easily adjust the settings that the application is using. Figure out a way to implement it so that the following requirements would be satisfied.

1. settings for processing of notices must be configurable:

  • Fine size for every exceeded km/h (e.g. 3€, 5€, 10€)
  • Maximum fine size (e.g. 100€, 190€, 300€)
  • Speed excess to start the general procedure (E.g. 40 km/h, 61 km/h, 100 km/h)

2. adjusting settings must be simple but stay invisible during day-to-day operations

  • Adding the ability to adjust settings must not add extra time to use the program normally.
    Thought: The officials working with the application on a daily basis don’t want to waste time on adjusting settings or even confirming current settings each time they use it.
  • Changes must persistent – once settings are changed, updated values should be used until they are changed again
    Thought: Values will typically be updated when the laws are changed. It is done quite seldom, so the operator doesn’t want to reconfigure it on a daily basis.
  • Changing the setting must not require recompilation of the program.
    Thought: You wouldn’t expect officials to know how to edit source code or recompile a program. Even if done by the IT, they are just support, not developers.

After this class, you should

  • know how to open and close files.
  • know how to check if a file opened.
  • know the difference between file modes and how they behave if the file exists and if it does not.
  • know in which situations files may fail to open when opened for reading or for writing.
  • know different ways of addressing files.
  • know why buffering files is important and what problems it may cause.
  • know how to read and write files.

Additional content

13. Strings

Lab materials

Lab tasks

In this task you have 2 tasks. First of which we’ll focus on the string.h library and in the second one we’ll look at manipulating strings manually.

Task 1: introducing the string.h library

In this task we’ll be focusing on the functions in the string.h library.

Requirements
  • Follow the step-by-step guide when solving this task!
  • The program must ask for a predefined password when starting. You must not allow the user past it until a correct password is entered.
  • User is asked for a sentence. Program will show how many characters there were in the given sentence (including spaces, punctuation).
  • The user is asked for a search phrase, after which it will output whether the phrase was present in the originally entered sentence (yes/no answer).
  • User is asked for 2 words, which are used to compose a sentence
    • You can choose the types of words yourself (e.g. verbs, nounds, names of items, names of people etc)
    • You can also choose the sentence you wish to compose
    • Compose the given words with others to compose a simple sentence consisting of at least 4 words.
    • One of the words given by the user must be the first word in this sentence.
    • The composed sentence must be written in a completely new (empty) variable, which must fit the composed sentence even in the worst case scenario (e.g. maximum possible length for the user-entered words).
Helper function for debugging

If you have any trouble figuring out what is actually in the string, use this function. It will print out the string, followed by each individual character (one per line). It will print the index, ascii code and the character it represents. This way it’s easy to figure out if you have a stray line change for an example.

Step-by-step guide
1. step: getting user input

We will go through this step in the class together! In this step we will create two functions necessary for our program.

For starters, let’s create a function to read a string. In the solution it is important that we would be able to read strings consisting of multiple words – we must be able to read  strings containing spaces. There are multiple ways to do this. In this sample, we will approach it using the function fgets() . If you wish to take a different approach, you are welcome to do so.

The function  fgets()  is meant to be used for reading files. However everything is a file, including the data stream coming from the keyboard. To use it, we will read the data from a file called  stdin . Secondly, the function requires us to specify the maximum length for the string – this is for safety so we wouldn’t be susceptible to buffer overflow attacks. Thirdly and the most problematic for us is that when we press the enter key when writing text, the newline \n  created by the enter key is also stored into the array.

We will approach this with the idea of creating a wrapper function. Wrappers surround an existing function or functions while providing extra features, convenience or safety.

Our wrapper needs two inputs – the character array (string) where we will store the input and the maximum length of that string.

In the solution for this function, I’ve left in question marks in 3 places where you will have to fill the gaps! Hint: if the read string is 10 characters, then at the index 8 is the last important character for us which the user entered. It is followed by the unwanted newline character, which we must get rid of. To do so, we will replace it with the string terminator symbol.

If you need, you can use the helper function provided earlier to see the contents of the read string.

In order for it to compile, the two lines handling the newline correction are commented out. Once you have replaced the question marks, comment them back in for it to work correctly.

Once the reading is done, let’s write another wrapper, this time for our  GetString()  function. This way it will be a lot cleaner to ask for input.

Now let’s try to get some input. In the example I have a character array sentence[]  , which has a length of  MAX_STR , defined a macro. The function call will look like this:

2. step: read a sentence and print its length

Read a sentence from the user. Find and print the length of the sentence the user entered.

3. step: search phrase

Add a new function to the program, where you will ask the user to input a search phrase. The function should then print whether the phrase existed in the previously entered sentence or not.

A yes/no answer is enough. To achieve this, you can just check the return value as such:

4. step: password prompt

Add a function to the program that will ask the user for their password. It could look something like this:

The prompt must be inside of a loop in such a way that the user wouldn’t be able to proceed to use your program before they’ve entered a correct password. The password prompt must be case sensitive. If you wish, you can add hints on incorrect input or limit the amount of tries the user has.

5. step: composing a sentence

Add a function to your program that will compose a simple sentence of at least 4 words. Since we don’t have any good inputs or outputs for the function, we can create it as follows (typically avoid void-void functions!):

Think! How long should the variable sentence  be to hold both user entered words in the worst case scenario, as well as all the characters you are using to formulate the sentence? The size can be approximated, but must be sufficient!

Now think of a sentence you wish to create. The sentence will have two gaps that the user will have to fill. You can choose which type of words go in there (names of objects, people, verbs, adjectives, …). One of the words that the user enters must be the at the start of the sentence. The location of the second word is up to you. E.g.  <word1> is a <word2> name! .

Once you have asked the user for input and read the words, you must compose the sentence. The sentence must be written into a new, unused (empty) character array. You must account for the worst case scenario for fitting the sentence (when the user decides to enter the maximum possible length words for booth inputs).

Example
Advanced task: Alternative count

Create a new function to do a manual count and add statistics

  • Count and show how many alphabetical characters [a-zA-Z] there were. Do not count punctuation, spaces etc.
  • Calculate and print the percentage of non-alphabetical characters in the sentence.
  • Show the percentage with one place after the comma.

Example

Task 2: Generating e-mail addresses from CSV

In this task we’re introducing you to a widely used file format for keeping data. The purpose of this task is to practice working with characters inside of a string manually.

Download the starter code: 12_2_csv_starter.c

CSV format

CSV stands for comma separated value. CSV files are used for storing structured data. Every data field in a CSV file, as the name suggest, is separated by a comma. It’s one of the most widely used formats for storing and backing up data next to database systems themselves. The primary benefit of CSV is in its simplicity, making it supported by almost all applications that process any kind of data.

In the most simple case, all data fields are separated by comas:

We are using the same complexity level for this lab task. To see how more complicated data is stored when you also need to store commas and quotes within the data fields, as well as add column headers, check here: https://en.wikipedia.org/wiki/Comma-separated_values#Basic_rules

Requirements
  • The task must be built on the starter code.
  • Program generates e-mail addresses for every person
    • The name part of the e-mail address must be composed of first 3 characters from the first name, followed by the first 3 characters of the last name.
    • The name part is followed by a domain of your choosing
    • You can only have lower case characters in the e-mail address
    • The e-mail address must be stored in a new character array that you create. Print it to the screen from that array. You are not allowed to print the characters on the fly while processing the entry.
  • The program must print:
    • The full name of the person. First and last name must be separated by a space.
    • Generated e-mail address
  • You are not allowed to change the code present in the starter code without a confirmation from us. The starting point of the code you write is in the function  ProcessPerson()  . You are welcome (and recommended) to add more functions to the code.
Example
Hints
  • By knowing the location of the comma, you will also be able to calculate the position of the first character from the last name
  • Lower and upper case ASCII characters differ from each other by a single bit, which is valued at 32 (e.g. A is 65, a is 97)
  • All operations in this task besides adding the domain address in the end are easiest done character at a time. Library functions from string.h  can be used, but they might be unnecessarily complex for now.
  • The most common mistake in this task is forgetting to add a string terminator to the end after copying over the name part of the address!
Advanced task 1: short names

Change the way you are generating the e-mail addresses to accommodate people with shorter first or last names.

Example: Ly Kask -> lykask@ttu.ee

Advanced task 2: unique e-mail addresses

Change the way you are generating the e-mail addresses in such a way that for similarly starting names the resulting e-mail address would be different.

Change your data array to the following:

Requirements

  • The e-mail addresses must be unique
  • The name part of the address must be 6 characters
  • The addresses must still refer to the owner’s name as much as possible
  • The exact algorithm and thus the final form of the address is up to you. You will defend your decision when showing.

After this lesson, you should

  • Know that there are various ways of encoding characters, including ASCII and Unicode
  • Know what is an ASCII table and how to use it.
  • Know how strings work in C.
  • Know how to terminate a string in C and why it’s necessary.
  • Know that strings in C are also related to byte-arrays.
  • Know what is CSV, where it’s used and why.
  • Know how to use the string.h library to manipulate strings.
  • Be able to write your own string manipulation functions (manipulating characters)
  • Know what is buffer overflow and the attacks related to it.

Additional content

12. Lab: Linux and CLI

Remote lab
Note: In 2024 autumn, this lab is intended to be solved remotely. Check for more information on MM.

Lab materials

Help on commands

If you need help with some of the commands, there are three main ways to get information on the commands. Third and the slowest would be using the internet, so we’ll skip this one. The other two sources of information are available quickly from your command line

tldr (simplified community-driven man pages)

This is a quick “handbook” composed by daily Linux users. It’s main purpose is to quickly and simply describe the most common ways to use each of the programs, as well as some less common, but important ones. The downside to this utility is that it often lacks detailed information and explanations, however it will get you the information you need or at least a starting point most of the time

The tool does not come as default, but we have installed it on the lab computers.

To use in the command line type tldr command

Alternatively, you can use the web version from https://tldr.sh

I.e.. to learn how to copy files, write tldr cp

man pages

man stands for manual and comes native with Linux. It includes manuals for commands, libraries, system calls etc. It includes manuals on how to use most programs. To use a manual, just type man command .

E.g. to check out how to copy files, you can run  man cp.

To close the manual, hit the letter  q . To search within a manual, hit   / , followed by what you are searching from. All other hotkeys and additional help can be read by hitting the key  h .

The advantage of  man  compared to  tldr  is that its very detailed and has a variety of different types of information. This can also be a downside for new users, as they are very throughout and might discourage or even terrify new users.  However, once you get used to reading information in this way, it becomes irreplaceable.

Lab tasks

There are two lab tasks this week. Both of them end up with a web form that you must fill! You do not need to present us your solutions after completion. Solutions are presented by filling out web based forms.

Task 1: working on the command line

The following task will introduce you to the command line and some basics working on it.

The task will end with a web form that must be filled. The submission of the web form confirms the completion of the task.

Pick your method

Before you can start solving you will need access to Linux and a terminal window. Some options that would work for this task:

  1. Solve the task in the lab computer
  2. Solve the task by using a remote desktop connection to the lab
    Guide: Remote access using RDP
  3. Solve the task by connecting to the lab computers through an SSH tunnel
    Guide: SSH connection guide

Note: Don’t use your own Linux for this task as there are some parts of it that can only be done with the university mount points.

Solving the task

The task is written as a step-by-step workflow that you should follow. All actions should be done using the command line. In the end, you will need to submit your command history. Prepare yourself enough time to solve the task 1 from start to finish, as you will need to submit your command history in the end of the task.

Step 1: Pick your working directory

In this step, you need to choose the location for the files that you will create during this lab. Most likely it should be somewhere on your P drive – i.e. ~/P/iax0583/lab11 .

The following commands will help you navigate:

  • Use  pwd  to check your current working directory
  • Use cd  to navigate from and to directories
  • Use  mkdir  to create a directory
  • Use  ls  to check the contents of the directory. Use additional arguments for more details.
  • Use mv  to rename directories and files  (if you happened to make a mistake)
  • Use tldr command  and man command  to get help on the commands.

Change the directory to the one you intend to solve your lab task

Step 2: Download the test program

The program wget  is most often used to download files off the internet. Use this to download a tester program by running the following command

Step 3: Unpack the tester and execute it

You’ve just downloaded a zip archive. Use the program called unzip to unpack it. First learn how to use it. Then pay close attention to the output that this program will give you in order to understand what was unpacked and where! Double-checking everything with ls  doesn’t hurt either. You need to understand what was unpacked and where!

You may need to manually make the test program executable

Once you have everything unpacked and found the testing program, you may need to add execute permission to it. Note, that it may also already be set by default. If you need to add the execute permission, use chmod  to change file access permissions (including adding execution privilege)

Execute the testing program

From this point on you can try to run the program provided. Try it now! Execute the tester!

The program will stop when an unmet requirement is encountered. You should retry the testing program  after every step from this point beyond.

You should see the following output:

Execute the tester after each step in this task.

Step 4: Download VIM configuration file

NB! You should skip this step if you already have one!

Vim is one of the more commonly used command line based text editors. It’s a lot more configurable and capable compared to basic text editors such as nano.

Lets download a configuration file that will make it a little bit nicer. I.e. introduce syntax highlighting, automatic tabs etc. The file needs to be stored in your home folder – that’s were Vim will be looking for it.

1. Go to your home directory. To do this, use the command cd .  Shorthand for your home directory is ~

2. Download the configuration file. Use wget  to download the following file: blue.pri.ee/.vimrc

Use the tester to verify completion of this step!

Step 5: Copy over an additional data file with the secret

Go to the M folder in your home directory (~/M/). Find your lecturer’s public directory and go to it. In there you will find a hidden directory (it starts with a dot).

Inside you will find a .dat file. Copy that file over to the same folder as the test program. For this you will need to use the cp  command. Specify the file you want to copy and the path you want to copy it to.

To test if this worked, run the program and see if it finds the secret!

Step 6: Next up, you need to create a file with your matricula

The file you need to create is named matricula . It needs to be saved into the same folder as the rest of the files so far. To create it, I’ll provide two possible options.

Option 1: Open up your preferred command line text editor, write a file called “matricula”

Vim guide:

    • Start by writing vim matricula  to create a file called matricula and open it in Vim.
    • Press ‘i’ to enter writing mode.
    • Now write your matricula number into the file.
    • Press ‘esc’ to exit write mode.
    • write :wq  in normal mode to write the file and exit

Option 2: This is what most people who use terminal regularly would likely do. They would use the echo  command, that just prints the passed text back on the screen and then redirect that output to a file, e.g. echo "text" > file

Step 7: Write a program that prints “Hello world!”

NB! Before continuing, remind yourself what is a file extension. What extension is used by C source code and what is used by programs!

Again use a command line text editor. We recommend Vim, as it supports C code, but you can use any other editor as well.

Once done, compile the program. Use -o hello  to specify the output (name of the program) as “hello”.

NB! Do not write the name of your source code file after -o. This will overwrite your source code!

Now run the test program that you downloaded from us. If everything was successful, it will create a new file with instructions.
Follow those instructions to complete the task.

Task 2: filtering logs and web home

In this task we will look at a tool that is widely used for digging through large amounts of data. We will also take a look at piping the standard output stream of one program into the standard input stream of another program. Lastly, we’ll do a quick introduction to your web home.

Input data

I’ve generated a file with someone random data that would simulate a log file from a robot. These kind of log files are typically extremely long. Usually we only look into them when something goes wrong and even then we are usually interested in only a fraction of what it contains.

Log file is at my web home: http://www.tud.ttu.ee/web/Risto.Heinsar/sensors.txt

Filtering data

To filter long text files we use a tool called grep . Grep is a pattern matching tool that will try to match entered the pattern and print all the lines containing it. Other lines will be skipped.

The patterns can be simple such as a single letter words or part of a string, e.g.  SENSOR , ERROR , firefox etc. In this case we would run the program as  grep pattern .

The patterns can also be more complex, containing regular expressions. To enable the use of regular expressions, we add a an argument -E  when executing. E.g.  grep -E sensor[1-3]:  will display us all the lines containing either  sensor1: , sensor2:  or sensor3: . Notice that the colon was also included in the pattern.

You can test your regular expressions here: https://regex101.com

Hint 1: You can grep the output of grep again – you don’t need to do everything with one execution if that is too difficult. Though you should definitely try!

Hint 2: the output of grep can be written to a file using output stream redirection.

Hint 3: You can also do regular expressions that include logical operations (e.g. one or the other).

Submitting the task (base and advanced)
  1. Decide whether you wish to solve the base or advanced task and solve it.
  2. Copy the resulting output file to your web home and figure out the public address of it
  3. Fill the following web form: https://forms.office.com/r/kb72jTqeXu

NB! If you have technical issues with the web home, let us know after filling out the form. Show us the location of your file and the addresses you tried.

Base task requiremets

Your task is to find all the lines in the file given by me which have the severity level of ERROR and which are related to the sensor number derived from your matricula number using the formula matricula % 10 .

Example:

Student code 123456IACB -> matricula 123456.
123456 % 6 is 6

So the output has to be about SENSOR6. Some examples:

The task can be solved either in one go or in parts – it’s up to you.

Write this output to a text file using stream redirection. The name of the created file should be your student_code.txt. E.g. if your student code is 123456IACB, then your file name should be called 123456iacb.txt.

Extra task requirements

Your task is to find all lines containing the severity level ERROR. The lines you are looking for should contain the sensors matricula % 10  and motor number matricula % 4 .

Example:

Student code 123456IACB, matricula 123456
123456 % 10 -> 6
123456 % 4 -> 0

This means we are looking for SENSOR6 and MOTOR0. Some examples of the lines:

The task can be solved either in one go or in parts – it’s up to you.

Write this output to a text file using stream redirection. The name of the created file should be your student_code.txt. E.g. if your student code is 123456IACB, then your file name should be called 123456iacb.txt.

Using the web drive

All students have their own web drive where they can hold and publish simple web pages and files. It’s the W drive. Copy the output of your filtered data to that drive.

More information on the web drive (Estonian only): https://taltech.atlassian.net/wiki/spaces/ITI/pages/38994529/li+pilase+veebikataloog+Online+student+directory

Copy the resulting file to your web drive. You can use cp  to copy files.

Now the file should be accessible under one of the following links:

  • http://www.tud.ttu.ee/web/uni-id/student_code.txt
  • http://www.tud.ttu.ee/web/Firstname.Lastname/student_code.txt

Now fill out the form!

Additional content

8. Standard streams

Lab material

Lab tasks

In this lab you have two tasks. Both of the tasks have an extra task available

Task 1: date validation

The purpose of this task is to check given numerical dates and check if the date is valid or not. In this task, we’ll also introduce stream redirection.

Download the starter code: https://blue.pri.ee/ttu/files/iax0583/aluskoodid/8_1_date_base.c

Requirements
  • The program checks each date and prints if it was a real date or not after it.
  • Limited year range: 1900 – 2099
  • The program implements leap year check
  • Must be able to verify 100 dates in a single run
  • Dates are given in DDMMYYYY format
  • For the base task, the functions must be implemented exactly as  they are described and structured in the base code.
  • When presenting your program for submission, you must use stream redirection. Input file to test with is also given on this page with the test dates.
Algorithm

The algorithm is showing a higher level view of the solution and is given for you as a guideline to solve the task. It doesn’t show the information exchange between functions. Due to separating the code out to functions you will notice that also the order of some operations will change as well as some logic will be written differently.

Ste-by-step guide

To start off, we should create a text file that will contain the inputs we would have otherwise typed in from the keyboard. This way we can write the test once and then use it each time after we change something in the program to test it quicker. Depending on the program structure, you may need to have multiple test files with different scenarios.

For this task we are able to only write one test file. We need to have both valid and invalid dates to make sure our algoritm detects them correctly. E.g. 11th of December 1981 would be a valid date, however 51st of December, month number 22 etc. will would not. In addition, you need to take extra care to test the edge cases – e.g. months 0, 1, 12, 13. Also testing days and months combined, e.g. 31st of December and 32nd of December. There is some additional complexity for leap years where the month of February can have either 28 or 29 days.

Here are your dates to test. Save it as a text file to the same directory as your source code and program! You’re allowed to add your own lines to the end.

Next you’ll need to make a program that will start to verify these dates.

Now let’s work with the starter code.

First two functions from it be done during the class. If you weren’t in the lab, check out the lecture recording!

From this point forward, we should have 2 files:

  1. Program code (e.g. date.c )
  2. Text file with the dates (e.g. input  or input.txt )

Next up we need to compile the program. One option would be to use Geany or any other IDE that you’ve used so far. You can do that if that’s what you feel the most comfortable with. Just don’t forget to recompile after changing the code!

Click me to see how to compile from command line

As an alternative, you can try to compile the code from the command line (that’s basically what happens when you press the build button anyway). The structure to do it yourself is compiler_name -o program_name source_code_file.cIt is important that -o is followed by the name of the desired program (output). In the end of the line we put the name of the source code file that we wrote. In addition we will also use flags to make sure that all the warnings are displayed – e.g. -Wall  and -Wextra .

Now lets put all this together. Once you are in the right directory with your command like, you can enter the following line:

gcc -o date -Wall -Wextra date.c

Using this like, the source code file date.c  will be compiled into a program called date .

Let’s verify that everything is where it should by by using the command ls -l :

Before we had 2 files, now we should have 3 of them:

  • date  – the so called binary file , that we produced by compiling our program. Can be executed.
  • date.c  – source code. This is the file we wrote our code in. Cannot be executed.
  • input.txt  – text file, that contains dates (test data).

Now we run the program so that instead of writing the input from the keyboard, it will be read from the file that we’ve composed (using the stream redirection). We need to use the following structure, but replace the names with the ones for our files  ./program_name < data_file

./program_name – this is how you can run a program in Linux console
< – a symbol denoting that the input stream will be redirected for this program
data_file – the file it will use to stream the input from

This is how the output will look like after we finish the part of the code done together and you will start your individual work

Testing: completed solution

After implementing the date validation, Your output should look something like this:

Task 2: Lottery

Start by downloading the starter code

Requirements
  • Lab task must be built on the starter code. It contains a list of functions with comments that you need to implement and use.
  • Lottery numbers can be from 1 to 25 (ends inclusive).
  • User is asked to enter 6 numbers
  • Computer will randomly generate 10 lottery numbers
  • Program will print out both the user and the randomly generated numbers
  • Check and show how many and which numbers matched (won)
    • There is no number uniqueness requirement for the base task
    • Every user number can win only once
  • If all numbers won, congratulate on jackpot. If none of the numbers won, give your condolences.
Testing

NB! The nature of a lottery is to be random, however testing this program without knowing that numbers to expect is not possible. Due to this, we will fix the random seed (srand function parameter) to be the same on every run. Then generate the lottery numbers once and remember them / write them down so you can test the program!

Test 1: Random numbers, some may win, no errors on input

Test 2: No winning numbers

Test 3: Jackpot

Test 4: Invalid user input

Test 5: Every user number can win only once (sanity check)

In this test, we will change the specification for the constants. This will help us test that every user number can only win once. This is also called a sanity check type of test.

NB! This test will only work if you haven’t yet solved the extra task where all numbers are checked to be unique. Repetition of numbers must be allowed for this!

After changing the constant, check for 2 things:

  1. How many numbers match! Should be  Matched 6 out of 6!)
  2. Check the numbers generated by the program. They can only be ones! (0 or 2 would mean that you have a mistake in the formula for limiting random numbers)

Extra task 1: reason for validation failure (date validation)

Lets improve our program to make it more clear why a date failed our validation.

Requirements
  • Extend your program in a way that it will give a reason for why the date didn’t validate
  • At minimum, you must be able to differentiate
    • Invalid year
    • Invalid month
    • Invalid day. You must differentiate between dates lower and higher than the allowed range for a specific month
    • Non-leap year 29th of February.
  • You are allowed to add functions and modify the existing structure of the program within reason.
  • Reminder! Avoid magical numbers! Define your constants
Testing

Extra task 2: unique numbers for lottery

By completing this task, you will make your program more realistic. For this we need to only solve 1 more function CheckIfNumInArray()  and start using it

Requirements
  • Enforce a requirement for the user entered numbers to be unique. If a user enters a number that they already entered before, immediately ask them for a different number.
  • Enforce the same requirement for the lottery machine.
  • Do not chagne the implementations of  GetUserNumbInRange()  and GenerateRandomNum()  functions. There is a better suited place for this.
  • Comment in and solve the function  CheckIfNumInArray() . You need to start using it in three different places
    • During user input to make sure that the values are unique
    • During generation of lottery numbers to make sure that they are unique
    • To count how many user numbers matched with the winning number in the function FindMatchCount()
Testing

Test 1: Check the uniqueness requirement for the user

NB! Use the exact same sequence to test!

Test 2: Check the uniqueness requirement for generated lottery numbers

To test the random numbers, we need to manipulate one of the constants

We will force the amount of numbers the computer is generating to be exactly as many unique numbers can be generated based on our lower and upper bounds for the numbers. We should get all numbers from 1 – 10 and none of them can repeat.

Think and answer the question: What would happen if we would have made the constant to be 9?

After the class, you should

  • Know which standard streams exist
  • Know how to use stream redirection on different platforms
  • Know how to execute the programs you create on Linux command line
  • Be able to use Boolean values
  • Be able to split up input
  • Know how to use the return value of scanf
  • Know how and when to omit curly braces. Also when not to.
  • Know what a dangling else statement is.
  • Be able to generate pseudo-random numbers
    • … within a specific range
    • … while fixing the seed for testing
    • … while making them dependent on the current time
  • Know the difference between pseudorandom and random
  • Know how UNIX time works and what’s the importance of 1st of January, 1970.

Additional content