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(¤tDate);
Date = localtime(¤tDate);
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);
}
2 Answers 2
I think that you've got some decent stuff here. You've made struct
s 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 const
s or enum
s 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 #define
s 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 char
s. 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()
.
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.