3
\$\begingroup\$

I've recently made a program which generates a (pseudo) random binary digit (1,0) which is tied to a specific subject to learn for every day of the week.

The program generates the digits the first time it's used, stores them in a file for later use and after that every Monday it generates them again. Currently I'm using only 2 subjects and the program has only one option (to view the current week subjects) but I may expand it in the future.

I'm putting it here so I can get a review of it, to understand where and what are my problems, how to fix them and what to do and how to do it for future projects.

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define FILE_DOESNT_EXIST_NUMBER 0
#define FILE_EXISTS_NUMBER 1
#define MAX_DIGITS_FOR_YEAR_NUMBER 4
#define MONDAY_NUMBER 1
#define NUMBER_OF_SUBJECTS 7
#define USER_CHOICE_VIEW '1'
#define USER_CHOICE_UNKNOWN '2'
#define YEAR_DAY_DIFFERENT 1
#define YEAR_DAY_SAME 0

char *year_day                          (struct tm *Date);
char user_input                         ();

int if_previously_saved_year_date       (char yearDay[5]);
int if_rand_numbers_exist               ();
int week_day                            (struct tm *Date);

struct DataInfo schedule_rand           ();
struct WYDay date_retrieval             ();

void date_and_nums_save                 (struct WYDay CurDay, int isFileCreated, int randBits[8]);
void program_start                      ();
void progress_view                      (int weekDayNumb);
void stdin_buffer_cleanup               ();
void usr_choices                        (struct WYDay WeekYearDay, char usrChoice);

struct DataInfo
{
    int subjNumb[8];
};

struct WYDay
{
    int weekNumb;
    char yearNumb[5];
};


int main ()
{
    program_start();

    return 0;
}

void program_start()
{
    char usrOption;

    int fileExistence;
    int ifDiffYearDate;

    struct DataInfo Data;
    struct WYDay Days;

    puts("This is the math and programming schedule check!\n"
       "Would you like to see what you've done this week or add something?\n\n"
       "1.See your progress!\n\n\n");

    usrOption = user_input();
    Days = date_retrieval();
    fileExistence = if_rand_numbers_exist();
    ifDiffYearDate = if_previously_saved_year_date(Days.yearNumb);
    if((Days.weekNumb == MONDAY_NUMBER && ifDiffYearDate == YEAR_DAY_DIFFERENT) ||
    fileExistence == FILE_DOESNT_EXIST_NUMBER)
    {
       Data = schedule_rand();
       date_and_nums_save(Days, fileExistence, Data.subjNumb);
    }
    usr_choices(Days, usrOption);

//    remove("RandomNumbers.txt");
//    remove("DateOfFileCreation.txt");
}

char user_input()
{
    char usrChoice;

    do
    {
        usrChoice = getchar();
        stdin_buffer_cleanup();
    }while(usrChoice != USER_CHOICE_VIEW && usrChoice != USER_CHOICE_UNKNOWN);

    return usrChoice;
}

void stdin_buffer_cleanup()
{
    char ch;

    while((ch = getchar()) != '\n' && ch != EOF);
}

struct WYDay date_retrieval()
{
    char *yearDigit;

    int iterat = 0;

    time_t currentDate;

    struct tm *Date;
    struct WYDay Day;

    time(&currentDate);
    Date = localtime(&currentDate);

    Day.weekNumb = week_day(Date);
    yearDigit = year_day(Date);

    for(iterat = 0; iterat < MAX_DIGITS_FOR_YEAR_NUMBER; iterat++)
    {
        Day.yearNumb[iterat] = yearDigit[iterat];
    }

    Day.yearNumb[MAX_DIGITS_FOR_YEAR_NUMBER] = '\0';

    free(yearDigit);

    return Day;
}

int week_day(struct tm *Date)
{
    char numbOfWeekDay[2];

    int weekDay;

    strftime(numbOfWeekDay, 2, "%w", Date);

    weekDay = numbOfWeekDay[0] - '0';
    if(weekDay == '0')
    {
        weekDay = '7';
    }

    return weekDay;
}

char *year_day(struct tm *Date)
{
    char *numbOfYearDay;

    numbOfYearDay = calloc(MAX_DIGITS_FOR_YEAR_NUMBER, sizeof(char));
    strftime(numbOfYearDay, MAX_DIGITS_FOR_YEAR_NUMBER, "%j", Date);

    return numbOfYearDay;
}

int if_rand_numbers_exist()
{
    int fileIsCreated;

    FILE *fcheck;

    fcheck = fopen("RandomNumbers.txt", "r");

    if(fcheck == NULL)
    {
        fclose(fcheck);
        fileIsCreated = FILE_DOESNT_EXIST_NUMBER;
        return fileIsCreated;

    }
    else
    {
        fclose(fcheck);
        fileIsCreated = FILE_EXISTS_NUMBER;
        return fileIsCreated;
    }
}

int if_previously_saved_year_date(char yearDay[5])
{
    int diffYearDay;
    int lastYearDay;
    int yearDayInt;

    FILE *ftest;

    sscanf(yearDay, "%i", &yearDayInt);

    ftest = fopen("DateOfFileCreation.txt", "r");

    if(ftest == NULL)
    {
        fclose(ftest);
        return diffYearDay = YEAR_DAY_DIFFERENT;
    }
    else
    {
        fclose(ftest);
        fscanf(ftest, "%i", &lastYearDay);
    }

    if(lastYearDay == yearDayInt)
    {
        return diffYearDay = YEAR_DAY_SAME;
    }
    else
    {
        return diffYearDay = YEAR_DAY_DIFFERENT;
    }

}

struct DataInfo schedule_rand()
{
    const int BASE_VALUE = 10;
    const int RAND_DIVIDE_FOR_REMAINDER = 2;

    float maxNumFloat, minNumFloat;

    int incr1 = 0;
    int maxNumInt, minNumInt;
    int randZeroAmount;
    int randNumber;

    struct DataInfo SubjInfo;

    srand(time(NULL));

    for(incr1 = 0; incr1 < NUMBER_OF_SUBJECTS; incr1++)
    {
        randZeroAmount = rand() %4 + 1;

        maxNumFloat = pow(BASE_VALUE, randZeroAmount);
        minNumFloat = pow(BASE_VALUE, randZeroAmount - 1);

        maxNumInt = maxNumFloat;
        minNumInt = minNumFloat;
        randNumber = rand() %(maxNumInt - minNumInt) + minNumInt; /*No idea how this formula works!*/
        SubjInfo.subjNumb[incr1] = randNumber %RAND_DIVIDE_FOR_REMAINDER;

//        printf("Max numb of zeros:[%i]\n", randZeroAmount);
//        printf("Min numb:(%i)\n", minNumInt);
//        printf("Max numb:{%i}\n", maxNumInt);
//        printf("Rand numb between min and max:%i\n\n", randNumber);
    }

    return SubjInfo;
}

void date_and_nums_save(struct WYDay CurDay, int isFileCreated, int randBits[8])
{
    int fIterat = 0;
    int lastTimeYearDay;
    int yearNumbInt;

    FILE *filep;

    sscanf(CurDay.yearNumb, "%i", &yearNumbInt);

    filep = fopen("DateOfFileCreation.txt", "r");

    if(CurDay.weekNumb == MONDAY_NUMBER || (filep == NULL))
    {
        fclose(filep);

        filep = fopen("DateOfFileCreation.txt", "w");
        fprintf(filep, "%s", CurDay.yearNumb);
        fclose(filep);
    }

    filep = fopen("DateOfFileCreation.txt", "r");
    fscanf(filep, "%i", &lastTimeYearDay);
    fclose(filep);

    if((CurDay.weekNumb == MONDAY_NUMBER && yearNumbInt != lastTimeYearDay) ||
       isFileCreated == FILE_DOESNT_EXIST_NUMBER)
    {
        filep = fopen("RandomNumbers.txt", "w");

        for(fIterat = 0; fIterat < NUMBER_OF_SUBJECTS; fIterat++)
        {
            fprintf(filep, "%i\n", randBits[fIterat]);
        }
        fclose(filep);
    }
}

void usr_choices(struct WYDay WeekYearDay, char usrChoice)
{
    if(usrChoice == USER_CHOICE_VIEW)
    {
        progress_view(WeekYearDay.weekNumb);
    }
}

void progress_view(int weekDayNumb)
{
    char subjectNumb;

    const char CURRENT_DAY_SUBJECT_CHARACTER[] = "<--";
    const char NUMB_ONE_SUBJ[] = "Programming";
    const char NUMB_ZERO_SUBJ[] = "Mathematics";
    const char REMAINDER_ONE = '1';
    const char REMAINDER_ZERO = '0';

    int subjectIterator = 0;

    FILE *fview;

    fview = fopen("RandomNumbers.txt", "r");

    while(subjectIterator < NUMBER_OF_SUBJECTS)
    {
        subjectNumb = fgetc(fview);

        if(subjectNumb == '\n')
        {
            continue;
        }
        else if(feof(fview))
        {
            break;
        }
        else
        {
            if(subjectNumb == REMAINDER_ZERO)
            {
                printf("\n%s", NUMB_ZERO_SUBJ);
                subjectIterator++;
            }
                else if(subjectNumb == REMAINDER_ONE)
            {
                printf("\n%s", NUMB_ONE_SUBJ);
                subjectIterator++;
            }
            else
            {
                printf("Unrecognized subject");
            }

            if(subjectIterator == weekDayNumb)
            {
                printf("  %s", CURRENT_DAY_SUBJECT_CHARACTER);
            }

        }
    }
    fclose(fview);

}
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

I think that you've got some decent stuff here. You've made structs for a variety of data types you use, which is helpful for understanding the code. You've broken things into functions, which is good, too. Here are some things you could do to improve it.

Use Typed consts or enums Instead of Macros

When you define a constant using const you give it a type which helps to clarify how you expect it to be used. I recommend using const values instead of macros for constants for this reason. I would get rid of all the #defines and change them to typed constants.

It looks like FILE_DOESNT_EXIST_NUMBER and FILE_EXISTS_NUMBER are a matched pair. It may make sense to make them into an enumerated type like this:

typedef enum File_Status {
    FILE_DOESNT_EXIST_NUMBER = 0,
    FILE_EXISTS_NUMBER = 1
} File_Status;

This lets a reader know that these are 2 possible values that a variable or function return can hold. They're not 2 unrelated constants. Same with YEAR_DAY_DIFFERENT and YEAR_DAY_SAME.

Odd Formatting

The formatting of your function prototypes is seriously confusing. When I looked at it, I couldn't understand what it was because I've not seen anyone write them that way. It took me a good 5 or 10 looks to figure out if it was a type definition, a global variable definition, or something else. There's no reason to line up the parentheses of your prototypes and it makes it much harder to read. For the functions you have grouped together, it makes it difficult to figure out which set of parameters goes with which function name because they're so far apart.

Naming

I think your function names are mostly pretty good. Your constants seem oddly named to me. For example, you don't need to put NUMBER at the end of the name. (Particularly if you use a const or enum for them.)

Your struct names could use some work. The name DataInfo is entirely free of meaning. It's like naming it "ThingStuff". All bytes in a computer are some sort of data and all data is information. Since it appears to hold subject numbers, why not name it Subject?

Likewise, it's not clear what WYDay means. It's clearly related to a date. What do the W and Y stand for? "Week" and "Year"? If so, then what is the word "Day" in there for? I would name it something clearer like simply Date or Week or WeekOfYear or something along those lines. Likewise, the name weekNumb is confusing. Is it the index of the week of the year? Like January 1st starts week 1 and December 31st ends week 52? If so, a name like weekOfYear would be clearer. And yearNumb is not a number but an array of chars. So it shouldn't be called an anything "Numb". I would simply name it year. And I might just make it a 16-bit or larger unsigned int.

Odds and Ends

What is the purpose of the function program_start()? You're main() function does nothing except call that function. It doesn't just start the program, it runs the whole thing! I'd remove that function and put its code into main().

\$\endgroup\$
0
\$\begingroup\$

You have small error in your stdin_buffer_cleanup function:

void stdin_buffer_cleanup()
{
    char ch;

    while((ch = getchar()) != '\n' && ch != EOF);
}

The variable ch should be int, as getchar is int getchar(void) and returns int and EOF may not fit in char variable.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.