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