PR1EN8: Standard streams

Lab material

Lab tasks

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

Task 1 [W08-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 and return value of the scanf()  statement.

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 is a real date or not
  • Year rage for the date to be considered valid: 1900 – 2099
  • Program must must support leap years correctly
  • 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 starter code
  • When presenting your program, you must use stream redirection. Test data is given on this page
Algorithm

The algorithm is limited to validating the date. The starter code also requires use of arrays, which is not depicted in the algorithm. This also causes variance in the order of operations.

Reminder: Activity diagrams do not show calling functions or data flow between functions.

Ste-by-step guide

To start off, we should create a text file that will contain the inputs we would otherwise have typed from the keyboard. This way we can write the test once and use it every time we update the source code. Depending on the program structure, you may need to have multiple test files to cover different scenarios.

You need to plan your testing in a way, that all possible options for your program would be tested. You need to have both realistic and unrealistic dates. I.e. 11th of December, 1981; 51st of December; month nr 22, month “abc” etc. Special attention should be put into edge cases – e.g. 29th of February. This time we have created the inputs for you. If you wish, you can add more dates in the end.

Save the following file with test inputs into the same directory you stored your program.

Next you’ll need to create a program that will test these dates.

Now let’s start working with the starter code. First two functions will be completed together in the class. If you were absent, watch the lecture recording!

From this point forward, we should have 2 files, both in the same directory

  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 compile the code from the command line. That’s exactly what happens when you press the build button anyway in Geany. The structure of the command 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  , -Wextra  and -Wconversion .

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 -Wconversion date.c

Using this line, 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

  • date  – 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 you need to run the program in such a way, that instead of typing the dates from the keyboard, we use stream redirection on the operating system level (our program is not reading the input file, it doesn’t even know how to do it). For this, we would formulate the command using the structure  ./program_name < data_file

./program_name – this is how you can run a program in Linux or MacOS, on the command line
< – 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 [W08-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
  • Program 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 [W08-3]: 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 [W08-4]: 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