#include #include #include #include #include #ifdef __cplusplus #error *Please use a proper C-Compiler* #endif // needed for reading proper input from stdin #define MAX_LINE_LEN 100 #define STUDENT_INFO "Sven", "Vogel", 1191225 // name of the file to write to on --export const char *FILE_NAME = "info_export.txt"; /** * @brief read some unsigned int form stdin. The value must be within and including in the range between min and max. * * @param min minimum value * @param max maximum value * @param msg message * @return unsigned int */ unsigned int read_ul(const unsigned int min, const unsigned int max, const char* restrict msg) { // buffer to fit line from stdin char line[MAX_LINE_LEN]; // end of buffer char *end = line + MAX_LINE_LEN; unsigned int value; do { // print message printf("%s", msg); // flush stdout to make sure every char is written properly fflush(stdout); // read a line from stdin fgets(line, MAX_LINE_LEN, stdin); // parse line to unsigned long value = strtoul(line, &end, 10); } while (value > max || value < min); return value; } /** * @brief read some double form stdin. The value must be within and including in the range between min and max. * After each attempt to parse a meaningful value msg will be printed to stdout. * * @param min minimum value * @param max maximum value * @param msg message * @return unsigned int */ double read_lf(const double min, const double max, const char* restrict msg) { // buffer to fit line from stdin char line[MAX_LINE_LEN]; // end of buffer char *end = line + MAX_LINE_LEN; double value; do { // print message printf("%s", msg); // read a line from stdin fgets(line, MAX_LINE_LEN, stdin); // parse line to double value = strtod(line, &end); } while (value > max || value < min); return value; } /** * @brief read interest rate and growth rate from stdin * * @param interestRate * @param growthRate * @return true * @return false */ void input_rate_and_growth(double *interestRate, double *growthRate) { // input interest rate *interestRate = read_lf(0.01, 10, "\tEnter interest rate [0.01; 10]: "); // input growth rate *growthRate = read_lf(0.01, 5.0, "\tEnter growth rate [0.01; 5]: "); } /** * @brief fill tab with interest calculations. Each row will contain data for the next year. * the columns will contain [0] := interest rate [1] := investment amount [2] := investment growth * * @param tab 3 column table * @param duration number of years to calculate for * @param investmentAmount start money * @return double sum off total investments */ double calculate_interest_growth(double tab[][3], int duration, double investmentAmount) { // declare variables double interestRate; double growthRate; double totalInterests = 0; input_rate_and_growth(&interestRate, &growthRate); // initialize 1. year tab[0][0] = interestRate; tab[0][1] = investmentAmount; tab[0][2] = investmentAmount * interestRate * 1e-2; for(unsigned int year = 1; year < duration; year++) { unsigned int lastYear = year - 1; // investment = investment form last year + interest tab[year][1] = tab[lastYear][1] + tab[lastYear][2]; // interest rate = last interest rate + interest growth tab[year][0] = tab[lastYear][0] + growthRate; // interest = investmentAmount * interest rate tab[year][2] = tab[year][1] * tab[year][0] * 1e-2; totalInterests += tab[year][2]; } return totalInterests + tab[0][2]; } /** * @brief print the table tab as layouted for calculate_interest_growth() to stdout * * @param tab * @param duration number of rows */ void output_table(double tab[][3], const unsigned int rows) { printf("\n\tinterest rate [%%] investment [€] annual interest [€]\n"); unsigned int year = 0; // print each row of the table for(unsigned int row = 0; row < rows; row++) { year ++; printf("year %2d:% 12.2lf\t% 12.2lf\t% 10.2lf\n", year, tab[row][0], tab[row][1], tab[row][2]); } } /** * @brief find the maximum value in arr * * @param arr * @param len * @return unsigned int index of the maximum value in arr */ unsigned int find_index(double arr[], unsigned int len) { unsigned int current = 0; double max = 0; // look through the entire array for (unsigned int x = 0; x < len; x++) { // test if we have found sth bigger than before if (arr[x] > max) { current = x; max = arr[x]; } } // return index of biggest found element return current; } typedef struct student { const char* name; const char* familyName; // 7-Decimal-Digit UUID number uint32_t matriculationNumber; } Student; /** * @brief create a new stack allocated student * * @param name forename of the student * @param familyName * @param matriculationNumber 7-digit unsigned uuid * @return Student */ Student new_student(const char* restrict name, const char* restrict familyName, const uint32_t matriculationNumber) { Student new_stud = { .name = name, .familyName = familyName, .matriculationNumber = matriculationNumber, }; return new_stud; } /** * @brief writes the format of student to the file specified by FILE_NAME. * * @param text */ void export_to_disk(const char* restrict text) { // open file in write mode only, truncating previous content to zero FILE* handle = fopen(FILE_NAME, "w"); // file could not be opened if (handle == NULL) { fprintf(stderr, "could not open file to export\n"); return; } fprintf(handle, "%s", text); fclose(handle); printf("Author exported to disk. Goodbye!\n"); } /** * @brief fill a destination string with the format "Name , Matriekelnummer: " * * @param dest string to store in, should be 100 bytes in size * @param author student to take inforamtion from */ void generate_string(char * restrict dest, const Student *student) { sprintf(dest, "Name: %s %s, Matrikelnummer: %7d\n", student->name, student->familyName, student->matriculationNumber); } int main(int argc, char **argv) { const Student author = new_student(STUDENT_INFO); unsigned int offerCount; unsigned int years; double investmentAmount; char info[100]; // hopefully no one ever has a name longer than 100 chars generate_string(info, &author); // parse command line argument if (argc > 1 && strcmp(argv[1], "--info") == 0) { printf("%s", info); if (argc > 2 && strcmp(argv[2], "--export") == 0) { export_to_disk(info); // abort, were done return 0; } } // run for ever. or until the user decides to kill it. while (1) { // input data years = read_ul(1, 50, "Enter investment duration in years [1; 50]: "); investmentAmount = read_lf(100, 10000, "Enter investment amount in € [100; 10000]: "); offerCount = read_ul(1, 3, "Enter offer count [1; 3]: "); // allocate table double (*tab)[3] = calloc(years, sizeof(double[3])); // allocate array for all offer sums // alternative dynamic stack allocation: double totalInterests[offerCount]; // alternative static stack allocation: double totalInterests[50]; double *totalInterests = calloc(offerCount, sizeof(double)); for (int i = 0; i < offerCount; i++) { printf("\n--------------------------------------------------------------\n"); // call berechne_zinswachtum() double totalInterest = calculate_interest_growth(tab, years, investmentAmount); // save this offers total interest for later totalInterests[i] = totalInterest; output_table(tab, years); printf("\nTotal interest after 3 years: %.2lf€\n", totalInterest); } // find and print best offer unsigned int bestOffer = find_index(totalInterests, offerCount); printf("\n--------------------------------------------------------------\n"); printf("***Offer %d has the best total interest with %.2lf€ after %d years***\n\n", bestOffer + 1, totalInterests[bestOffer], years); printf("\n--------------------------------------------------------------\n"); // free resources free(totalInterests); free(tab); } return 0; }