Classroom practice: Structures
Gábor Horváth / Zsolt Kohári · 2020.10.16.
Defining and using complex data structures.
The C programming language does not have built-in support for rational numbers. Let us add this feature! Declare a type to store rational numbers (numerator, denominator) and write functions
- to print a rational number
- to read a rational number from the input
- to add, and to multiply two rational numbers
- to convert a rational number to a real (double) number
Solution
#include <stdio.h> typedef struct Rational { int num, den; } Rational; /* prints a rational number */ void rational_print(Rational r) { printf("%d/%d", r.num, r.den); } /* reads a rational number from the input */ Rational rational_read() { Rational r; scanf("%d / %d", &r.num, &r.den); return r; } /* add two rational numbers */ Rational rational_add(Rational r1, Rational r2) { Rational res; res.num = r1.num*r2.den + r2.num*r1.den; res.den = r1.den*r2.den; return res; } /* multiplies two rational numbers */ Rational rational_mul(Rational r1, Rational r2) { Rational res; res.num = r1.num*r2.num; res.den = r1.den*r2.den; return res; } /* returns the floating point value of the rational number */ double rational_real(Rational r) { return (double)r.num / r.den; } int main() { Rational x = {1, 2}, y; y = rational_read(); printf("The sum of the the two rational numbers is: "); rational_print(rational_add(x, y)); printf(" the product is: "); rational_print(rational_mul(x, y)); return 0; }
Write a C program that stores time points in a structure: hour and minute. Write the following functions operating on the time points:
print_time(i)
: prints the time point in format hour:minute.add_to_time(i, p)
: addsp
minutes to time pointi
and returns with the new time point. For instance, 15:15 + 45 = 16:00.elapsed_time(i1, i2)
: returns how many minutes have elapsed between the two time points. For instance, 16:30-15:15 = 75 minutes. (The order of the parameters is: i1 is the later, i2 is the earlier time point)subtract_from_time(i, p)
: subtractsp
minutes from time pointi
and returns with the new time point. For instance, 15:45 - 30 = 15:15.
Solution
For the treatment of the 60 minute and 24 hour limits the modulo operator (%) comes handy.
E.g., in case of 16:55+10
we get :55+10 = :65
,
which should be :05
in the next hour. Observe that 65%60
returns exactly the
minute we are looking for, and the result of 65/60
returns 1, which is the number
by which the hour should be incremented. Than, the hour can be taken as a modulo 24, since we dont care
about the days.
Subtracting is not that easy, since (5-10)%60 = (-5)%60 = -5
.
Hence, we need some extra code to treat such negative values. The solution below uses loops for that,
but an alternative solution without loops is also feasible.
#include <stdio.h> /* Structure to store time points */ typedef struct Time { int hour, min; } Time; /* Prints the time point received as a function argument. */ void print_time(Time i) { printf("%02d:%02d", i.hour, i.min); } /* Adds p minutes to time point i and returns the increased time point. * p must be positive. */ Time add_to_time(Time i, int p) { int frommidnight = i.hour * 60 + i.min + p; Time newtime; newtime.min = frommidnight % 60; newtime.hour = frommidnight / 60 % 24; return newtime; } /* Computes how many minutes have elapsed from i1 to i2 * assuming that i2 is later than i1 and they fall to the same day. */ int elapsed_time(Time i2, Time i1) { return i2.hour*60-i1.hour*60 + i2.min-i1.min; } /* Subtracts p minutes from time point i and returns the resulting time point * assuming that p is positive. */ Time subtract_from_time(Time i, int p) { Time newtime; newtime.min = i.min-p; newtime.hour = i.hour; while (newtime.min < 0) { newtime.min += 60; newtime.hour -= 1; } while (newtime.hour < 0) newtime.hour += 24; return newtime; } int main(void) { Time i1 = { 11, 50 }, i2 = { 12, 10 }, i3 = { 3, 30 }; printf("i1 = "); print_time(i1); printf("\n"); printf("i2 = "); print_time(i2); printf("\n"); printf("i3 = "); print_time(i3); printf("\n"); printf("i2-i1 = %d\n", elapsed_time(i2, i1)); printf("i1+195 = "); print_time(add_to_time(i1, 195)); printf("\n"); printf("i2-195 = "); print_time(subtract_from_time(i2, 195)); printf("\n"); printf("i3-240 = "); print_time(subtract_from_time(i3, 240)); printf("\n"); return 0; }
Write a program to store a date in a struct: year, month, day. Write the following function that operate on this struct:
date_print(d)
: prints the date in format year.month.daydate_day_of_year(d)
: returns which day is it in the given year (0-365/366). Take the leap years also into consideration!date_subtract(d1, d2)
: returns the number of days elapsed from d2 to d1 (d1 is earlier than d2)which_day(d)
: returns which day of the week the date falls to. 1=Monday, 7=Sunday. January 1, 1900 was a Monday.
Solution
#include <stdio.h> /* the definition of the date type */ typedef struct Date { int year, month, day; } Date; /* prints the date in format year.month.day */ void date_print(Date d) { printf("%4d.%02d.%02d", d.year, d.month, d.day); } /* auxiliary function: is it a leap year? */ int leapyear(int year) { return year%400==0 || (year%100!=0 && year%4==0); } /* returns which day is it in the given year */ int date_day_of_year(Date d) { int months[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int num, m; num = 0; for (int m = 1; m < d.month; ++m) num += months[m-1]; num += d.day; if (leapyear(d.year) && d.month>2) num += 1; return num; } /* returns the number of days elapsed from d2 to d1 * d1 is earlier than d2 */ int date_subtract(Date d2, Date d1) { /* the difference in the days */ int diff = date_day_of_year(d2) - date_day_of_year(d1); /* ...plus the difference given by the years */ for (int year = d1.year; year < d2.year; year += 1) diff += leapyear(year) ? 366:365; return diff; } /* returns which day of the week the date falls to. * 1=Monday, ..., 7=Sunday. */ int which_day(Date d) { Date reference = { 1900, 1, 1 }; /* Monday */ /* count the difference in days. Due to modulo 7 result can be 0...6 * where 0 is the Monday. Add +1 to get the result between 1...7 */ return date_subtract(d, reference)%7 + 1; } int main() { Date today = { 2018, 10, 13 }, start = { 2018, 9, 3 }; printf("Today: "); date_print(today); printf(", is the %d. day of the week.\n", which_day(today)); printf("Beginning of the semester: "); date_print(start); printf(", days elapsed: %d.\n", date_subtract(today, start)); printf("this is week %d of the semester.\n", date_subtract(today, start)/7+1); return 0; }
The date_subtract()
function calculates the difference between the dates.
First it subtracts the difference of the days counted from the beginning of their
years (can be negative). Then, it adds either 365 of 366 for each year falling between
the two dates. The calculation can be demonstrated with an example, where the two dates are
2012.09.03 and 2013.10.06. The first date is the 279th, the second is the 247th day of their
respective year, hence, 279-247=32 days have passed between September 3 and October 6. We have
to add to this number the days of the entire year 2012 (which is actually a leapyear).
Observe that we have to sum up the first month-1
elements of the array months[]
.
We could have choosen an alternative solution where the array stores the sums instead of the lengths of the months,
hence the content would be: 0 (January), 31 (February), 59=31+28 (March), etc. This way the loop responsible for the
summation can be eliminated, at the cost of the degraded readability of the source code.
A factory produces metal rods. Due to the inaccuracy of the manufacturing process, their length varies a little bit: for instance, the length of a 1 meter rod can vary between 999 mm and 1001 mm. If two such rods are joined together, their total length can vary between 1998 and 2002 mm.
- Define a type to store the minimal and maximal length of a rod!
- Write a function that receives the parameters of two rods and returns the parameters of the rod created by joining the them!
- Write a function that returns the mean length of the rod received as input!
- Extend the code to a full C program, that creates two rods with parameters 999-1001 mm and 498-502 mm. By calling the functions, print the minimum, the maximum and the mean length of the rod created by joining them!
Solution
#include <stdio.h> typedef struct Rod { double min, max; } Rod; Rod sum(Rod r1, Rod r2) { Rod res; res.min=r1.min+r2.min; res.max=r1.max+r2.max; return res; } double meanlength(Rod r) { return (r.min+r.max)/2; } int main() { Rod a = { 999, 1001 }, b = { 498, 502 }, s; s = sum(a, b); printf("min: %f, max: %f, mean: %f\n", s.min, s.max, meanlength(s)); return 0; }