C - using fgetc to store value in enum 'class' - c

I am writing a program that accepts a file with database entries in it. The entries are all in the same format, with the data in the same order. The first number in the file is the number of entries. Then the data looks like this:
LastName FirstName StudentID age year GPA expectedGraduationDate
Ex:
Doe John 12345678 23 freshman 4.0 2013
My issue is with the year value. We are supposed to declare it as type 'class', which is supposed to be enum class{freshman, sophomore, junior, senior, grad};
I have a header file with the following declaration:
typedef enum {firstYear, sophomore, junior, senior, grad} class;
Then my main file:
#include <stdio.h>
#include <stdlib.h>
#include "class.h"
int main(int argc, char *argv[]){
typedef struct{
int DBrecordID; //ID for each entry, range 0-319
char *last; //student last name
char *first; //student first name
char studentID[8]; //student ID
int age; //student age
class year; //year in school
float gpa; //GPA
int expGradYear; //expected graduation year
}DBrecord;
int numEntries;
DBrecord **record;
char buffer[80];
FILE *fpt;
int c, i;
int j = 0;
//check for invalid file arguments
if(argc != 2){
printf("Number of arguments is invalid\n");
exit(1);
}
//error if unable to open file
if((fpt = fopen(argv[1], "r")) == NULL){
printf("Error: Couldn't open file.\n");
exit(1);
}
//set file pointer to read passed file
fpt = fopen(argv[1], "r");
//scan first int in file and assign to numEntries
//fscanf(fpt, "%d", &numEntries);
//allocate memory for structures, each is 36 bytes
*record = malloc (sizeof (DBrecord) * numEntries);
//loop through each DB entry
do{
for(i=0; i<numEntries; i++){
numEntries = record[i]->DBrecordID;
do{
c=fgetc(fpt);
buffer[j++] = c;
}while(c != ' ');
strcpy(record[i]->last, buffer);
j=0;
do{
c=fgetc(fpt);
buffer[j++] = c;
}while(c != ' ');
strcpy(record[i]->first, buffer);
j=0;
do{
c=fgetc(fpt);
buffer[j++] = c;
}while(c != ' ');
strcpy(record[i]->studentID, buffer);
j=0;
do{
c=fgetc(fpt);
memcpy(c, buffer[j++], 1);
}while(c != ' ');
memcpy(buffer, record[i]->year, 4);
j=0;
do{
c=fgetc(fpt);
buffer[j++] = c;
}while(c != ' ');
memcpy(buffer, record[i]->gpa, 4);
j=0;
do{
c=fgetc(fpt);
buffer[j++] = c;
}while(c != ' ' || c != '\n');
memcpy(buffer, record[i]->expGradYear, 4);
j=0;
}
}while(c != EOF);
return 0;
}
*Updated errors
main.c:75: warning: passing arg 1 of `memcpy' makes pointer from integer without a cast
main.c:75: warning: passing arg 2 of `memcpy' makes pointer from integer without a cast
main.c:77: incompatible type for argument 2 of `memcpy'
main.c:83: incompatible type for argument 2 of `memcpy'
main.c:89: warning: passing arg 2 of `memcpy' makes pointer from integer without a cast
main.c:94: parse error before "DBrecord"
So I'm assuming I can't do what I'm trying to do with memcpy, or I'm just doing it wrong. Suggestions?

There quite a few errors in the program but for a start
1) record should be of type DBrecord* not DBrecord**
2) strcpy takes destination as the first argument so this wouldn't work
strcpy(buffer, record[i]->last);
3) you also need to allocate memory for record[i]->last
4) strcpy is used to copy strings so if you wan't to store to float or int i.e. gpa etc you need to use memcpy also the value from buffer should be converted using strol strod
also would recommend to get hold of this book K&R it would be really helpful overtime

Why would you try to strcpy (String Copy) from an int, like expGradYear?
strcpy is for STRINGS. If you want to append an int to a buffer, use memcpy (MEMory Copy)

Related

How to read Text Files into 2d Arrays?

Alright, I'm making a grading program/code that will have its own text file where it stores all the grades. And I thought of making a 2d array where the first "dimension" will be the student and second "dimension" the individual grade (if there's a smarter way of doing grades tell me, by the way I chose this method because it is the only way I know how I could later on just add more students or more grades) keep in mind that the number of grades and students isn't always set so there's no easy way out. Anyways I've tried something, and I think it only works with characters and not with integers (even though the grades will be 1-5).Also I want a way to print it out but I think this is the bigger problem. Anyways THANKS.
typedef char string [20];
string row;
int i=0,j=0;
char arr[20][20];
FILE *fp;
fp=fopen("grades.txt","r");
for(i=0;arr[i-1][j]!=EOF;i++)
{
fgets(row,sizeof(row),fp);//I used fgets so I could get the size of the line
for(j=0;j<strlen(row);j++)
{
fscanf(fp,"%c ",&arr[i][j]);
}
}
I don't know if it will help but I thought the text file would look something like this:
54455
43544
22443
21232
21121
fgets reports if it worked or not. So, reading till end of file or till the buffer is full:
for(i = 0; i < sizeof arr / sizeof *arr && fgets(arr[i], sizeof arr[i], fp); i++)
{
// probably remove the \n that fgets writes into the buffer
// otherwise nothing else to do
}
Site notes:
fgets reads from the file, no need for additional reads with fscanf
fgets reads a line including the newline character, remove it if you don't want it
you need to check if fopen worked
I found out the best way to store grades of students in struct. Every student in general has first name, last name, grades,... You can add whatever you want. I am just fine with fname, lname, grades.
typedef struct student_s {
char fname[25];
char lname[25];
int* grades;
int count_of_grades; // Track number of grades for each student
} student_t;
By allocating a dynamic array of student_t you can get as many students as you want.
// Allocate array of structs
student_t* students = (student_t *) malloc(sizeof(student_t));
By using getline() you can read the whole line from file at once (line ends with \n). getline() is not a standart C function therefore you need to put #define _GNU_SOURCE at the beginning of your script.
while ((read_len = getline(&line, &len, fp)) != -1)
Every time function getline() reads next line of file, the array size count will be incremented and reallocated array.
++count;
// Increase size of array beacause of new student to add
students = realloc(students, sizeof(student_t) * count);
if (students == NULL)
{
printf("Couldn't allocated memmory\n");
return 1;
}
Next step is to allocate grades array which will store all grades of specific student. Looping through line you can extract each grade. Then by just defining members of struct you can add grades for each student.
// Allocate array to store all grades from file for one student
// Count of grades does not have to be the same for every student
students[index].grades = (int *) malloc(sizeof(int) * (read_len-1));
// Iterate grades read from file
for (int i=0; i<read_len-1; ++i)
{
// char --> char *
char grade[2] = "\0";
grade[0] = line[i];
// Add grade to the array of grades
students[index].grades[i] = atoi(grade);
}
At the end you should store number of grades are in array for a simple manipulation with data later in your script.
// Track number of grades
students[index].count_of_grades = read_len-1;
++index
Full code:
#define _GNU_SOURCE // necessery to use getline()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct student_s {
char fname[25];
char lname[25];
int* grades;
int count_of_grades;
} student_t;
int main(int argc, char const *argv[])
{
// Allocate array of structs
student_t* students = (student_t *) malloc(sizeof(student_t));
int count = 0;
int index = 0;
FILE* fp;
char* line = NULL;
size_t len = 0;
ssize_t read_len;
fp = fopen("data.txt", "r");
if (fp == NULL)
{
return 1;
}
// Read line by line from file until fp reaches end of file
while ((read_len = getline(&line, &len, fp)) != -1)
{
++count;
// Increase size of array beacause of new student to add
students = realloc(students, sizeof(student_t) * count);
if (students == NULL)
{
printf("Couldn't allocated memmory\n");
return 1;
}
// Replace with your code, which adds name to struct or get rid of it (also from struct)
memcpy(students[index].fname, "John", 4);
memcpy(students[index].lname, "Wash", 4);
// Allocate array to store all grades from file for one student
// Count of grades does not have to be the same for every student
students[index].grades = (int *) malloc(sizeof(int) * (read_len-1));
// Iterate grades read from file
for (int i=0; i<read_len-1; ++i)
{
// char --> char *
char grade[2] = "\0";
grade[0] = line[i];
// Add grade to the array of grades
students[index].grades[i] = atoi(grade);
}
// Track number of grades
students[index].count_of_grades = read_len-1;
++index;
}
fclose(fp);
if (line)
{
free(line);
}
// Print data from structs
for (int i=0; i<count; ++i)
{
printf("%s: ", students[i].fname);
for (int j=0; j<students[i].count_of_grades; ++j)
{
printf("%d ", students[i].grades[j]);
}
printf("\n");
}
return 0;
}

Can't dynamically allocate a string

I tried to dynamically allocate a string using a function I named ALLO, but when I execute I get an error, which is my function ALLO can't get the string using getc, it gets skipped.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ALLO(char *str){
char c=0;
int i = 0, j = 1;
str = (char*)malloc(sizeof(char));
printf("Enter String : ");
while (c != '\n') {
// read the input from keyboard standard input
c = getc(stdin);
// re-allocate (resize) memory for character read to be stored
str = (char*)realloc(str, j * sizeof(char));
// store read character by making pointer point to c
str[i] = c;
i++;
j++;
}
str[i] = '\0'; // at the end append null character to mark end of string
printf("\nThe entered string is : %s", str);
free(str); // important step the pointer declared must be made free
}
int main(){
char *NomAF;
int NAF;
printf("Entrer le nombre des ateliers : ");
scanf("%d",&NAF);
ALLO(NomAF);
return 0 ;
}
The semantics are wrong.
You ask the user for the names of the athletes, and then you scan it into an integer. You should ask for the number of athletes first. Then, after that, you allocate memory to accommodate each name.
int num_names;
scanf("%d", &num_names);
After you know the number of names, you then allocate a buffer for each name, separately.
char **names;
names = malloc(num_names * sizeof(char **));
for(int i = 0; i < num_names; i++)
ALLOC(&names[i]);
Also, you shouldn't be using scanf for user input. Use fgets instead, which is a little better.
Then, you also should be using a pointer to pointers to get those strings.
A little modified version of your code (which you should review and fix, as needed):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ALLO(char **str){
/* use INT for getc() return */
int c=0, i = 0;
/* you are gettting 1 byte of memory */
*str = malloc(sizeof **str);
/* should use fprintf(stderr...) or fflush(stdout) to guarantee
* the sentence will be seen by user
*/
printf("Enter String : ");
while (c != '\n') {
// read the input from keyboard standard input
c = getc(stdin);
// re-allocate (resize) memory for character read to be stored
/* i = 0 in the first run,
*
* and you have 1 byte alloced in the first run.
*
* so you get 1 byte for actual getc() return
* 1 byte for next character + NULL byte
*
* NOTE: you are STORING the NULL byte in your string. You only
* check for it AFTER you do the assignment, so your strings
* contain a newline before the NULL byte.
*/
*str = (char*)realloc(*str, (i + 2) * sizeof **str);
// store read character by making pointer point to c
(*str)[i] = c;
// you can use only 'i' for this...
i++;
/* #i
*
* Using only 'i' requires that you understand what #i is doing
* during execution. #i will keep the current buffer position,
* and you know you need one more position for the next
* character and one more for the NULL byte.
*
* Therefore, in your realloc statemente, you need #(i + 2)
*/
}
(*str)[i] = '\0'; // at the end append null character to mark end of string
printf("\nThe entered string is : %s", *str);
// if you free here, you can't get the string at #main for printing.
// free is the last step
//free(str); // important step the pointer declared must be made free
}
int main(){
char **NomAF;
int NAF, i;
char buf[100];
printf("Number of athlets : ");
fgets(buf, sizeof(buf), stdin);
NAF = atoi(buf);
NomAF = malloc(NAF * sizeof *NomAF);
// check malloc errors
// get names
for(i = 0; i < NAF; i++) {
ALLO(&NomAF[i]);
printf("New name: %s\n", NomAF[i]);
}
// print names, then free() then
for(i = 0; i < NAF; i++) {
printf("Name: %s\n", NomAF[i]);
free(NomAF[i]);
}
// free the base pointer
free(NomAF);
return 0 ;
}
Add this
while((c=getchar()!='\n')&&c!=EOF);
before getc it skips white space.
Because after this scanf("%d",&NAF); take you are giving input 5(+enter) this goes 5'\n' 5 is got by scanf and '\n' is in buffer and this new line is got by your getc.
and change this str[i] = '\0'; to str[i-1] = '\0';, it replaces the newline with NULL and you allocated memory for i characters only.
You can return the string by return str; and change function return type as char* or if don't want that take a parameter that allocated by malloc.
See this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ALLO(char *str)
{
char c=0;
int i = 0;
printf("Enter String : ");
while (c != '\n')
{
while((c=getchar()!='\n')&&c!=EOF);
c = getc(stdin);
str = (char*)realloc(str, (i+1) * sizeof(char));
if(!str) exit(1);
str[i] = c;
i++;
}
str[i-1] = '\0';
}
int main()
{
char *NomAF;
int NAF;
NomAF=malloc(sizeof(char));
if(!NomAF) exit(1);
printf("Entrer le nombre des ateliers : ");
scanf("%d",&NAF);
ALLO(NomAF);
printf(NomAF);
free(NomAF);
return 0 ;
}
output:
Entrer le nombre des ateliers : 5
Enter String : a
s
d
f
g
----->newline to stop the loop
asdfg
Process returned 0 (0x0) execution time : 8.205 s
Press any key to continue.
I entered it as a string not character by character, its not practical to ask the user the enter letter by letter
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
char * inputword(char **);
int main()
{
char *word;
printf("Enter Word:");
word=inputword(NULL);
printf("Word Entered:%s",word);
free(word);
printf("\nEnter Word 2:");
inputword(&word);
printf("Word Entered:%s",word);
free(word);
return 0 ;
}
char *inputword(char **word)
{
char *str=NULL,ch,*memerr="Memory Error";
int i=0,flag=1;
do
{
str=realloc(str,((i+1)*sizeof(char)));
if(!str)
{
printf(memerr);
exit(1);
}
ch = getch();
switch(ch)
{
case 13:
str[i] = '\0';
putc('\n',stdout);
flag=0;
break;
case '\b':
if(i>0) i--;
str[i--]='\0';
printf("\b \b");
break;
default:
str[i] = ch;
putc(ch,stdout);
}
i++;
}while(flag);
if(word!=NULL)
*word=str;
return str;
}
output:
Enter Word:Hai, How are You?(1 String)
Word Entered:Hai, How are You?(1 String)
Enter Word 2:Hai, How are You?(2 string)
Word Entered:Hai, How are You?(2 string)
Process returned 0 (0x0) execution time : 58.883 s
Press any key to continue.

How to make a C program that can read a data and copy some in a variable?

I'm a student, I am wondering...
How can I make a program that can Get some data from my text file to a variable on my program and print them
Example:
My Text File
I,Ate,Cookies
She,Drink,Coffee
Tom,Wears,Pyjamas
My code
main()
{
FILE *fp=fileopen("c:\\textfile.txt","r");
char name[20],action[20],item[20];
prinf("Enter name: \n");
scanf("%s",&name);
/* I dont Know what to do next */
}
I though about some checking code:
if (name==nametxt) /*nametxt is the first line on the text file */
{
printf("%s\n %s\n %s\n",name,action,item);
}
If the name is "I",the output would look like this :
Enter name:
I
I
Eat
Cookies
A help will satisfy my curiosity thanks in advance
You are reading characters from file until you receive new line character (\n) or fill an array, then you return characters stored in an array passed by caller.
From this returned array you may get separated values with strtok.
Repeat until you receive 0 from getline (Getline received EOF from file.)
Here is simple example with your own getline function which you may modify.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int getline(char s[],int lim, FILE * fp)
{
int c, i;
for (i=0; i < lim-1 && (c=fgetc(fp))!=EOF && c!='\n'; ++i)
{
s[i] = c;
}
if (c == '\n')
{
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
int main()
{
FILE * fp = fopen("c:\\textfile.txt", "r");
char line[100];
char * ptr;
while (getline(line, 100, fp))
{
ptr = strtok(line, ",");
while( ptr != NULL )
{
printf(" %s\n", ptr);
ptr = strtok(NULL, ",");
}
}
return 0;
}
Output
I
Ate
Cookies
She
Drink
Coffee
Tom
Wears
Pyjamas
Storing strings into variable isnt tough, here is an example
strcpy(name, ptr);
But be careful, writing outside of bounds have undefined behavior.
strncpy(name, ptr, 100); You can limit number of copied characters with strncpy, but be careful, this function is error-prone.
You can do like this,
Go on reading characters from a file, after every character is read compare with ',' character.
If the character read is ',' then you have finished reading the name, otherwise store it in a character array and continue reading the file.
Once you hit ',' character, terminate the character array with null character(Now you have a complete name with you).
Compare this character array with a string you receive as input using a strcmp(String compare function). If its it matches decide what you wanna do?
I hope i am clear.
There is different ways to read data from a FILE * in C :
You read only one character : int fgetc(FILE *fp);.
You read a whole line : char *fgets(char *buf, int n, FILE *fp); (take care to buf, it must point to allocate memory).
You read a formatted string, which is your case here : int fscanf(FILE *stream, const char *format, ...), it works like printf() :
This way :
char name[20], action[20], item[20];
FILE *f = fopen("myfile.txt", "r");
if (! f)
return;
if (3 == fscanf(f, "%19[^,\n],%19[^,\n],%19[^,\n]\n", name, action, item))
printf("%s %s %s\n", name, action, item)
%30[^,\n], here is used to read of whole object of your line, except , or \n, which will read item by item the content of your string.
start with like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DATA_FILE "data.txt"
#define LEN 19
#define SIZE (LEN+1)
//Stringification
#define S_(n) #n
#define S(n) S_(n)
enum { NOT_FOUND, FIND };
int pull_data(const char name[SIZE], char action[SIZE], char item[SIZE]){
int ret = NOT_FOUND;
FILE *fp = fopen(DATA_FILE, "r");//fileopen --> fopen
if(fp == NULL){
perror("fopen:");
exit(EXIT_FAILURE);
} else {
char nametxt[SIZE];
*action = *item = 0;
while(fscanf(fp, "%" S(LEN) "[^,],%" S(LEN) "[^,],%" S(LEN) "[^\n]%*c", //"%19[^,],%19[^,],%19[^\n]%*c"
nametxt, action, item) == 3){
if(strcmp(name, nametxt) == 0){//Use strcmp for comparison of strings
ret = FIND;
break;
}
}
}
fclose(fp);
return ret;
}
int main(void){
char name[SIZE], action[SIZE], item[SIZE];
printf("Enter name: \n");//prinf --> printf
if(scanf("%" S(LEN) "s", name) == 1){
if(pull_data(name, action, item) == FIND){
printf("%s\n%s\n%s\n", name, action, item);
} else {
printf("%s not found.\n", name);
}
}
}

C Array struct, trying to access data, but is coming up with the same for all arrays

So, my goal is to create a linear search, but i have got that down pat, I am having one problem with accessing strings from the struct, that i have stored using a txt file, so in linearSearch() I tried doing this:
printf("Name: %s \n", q.name[i]);
printf("Data: %d \n", q.data[i]);
The data would be perfect but name would just print out the same name for every array which would be the last item that I put into the array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char* name[10];
int data[10];
}Word;
//int bubblesort (Word word);
void linearSearch(char* name, Word q);
int main (int argc, const char *argv[]){
Word q;
char username[9]; /* One extra for nul char. */
int score;
int i = 0;
FILE *ifp, *ofp;
ifp = fopen("Data.txt", "r");
while (fscanf(ifp, "%s %d", &username, &score) == 2) {
q.name[i] = username;
printf ("Name: %s, I = %d \n", q.name[i], i);
q.data[i] = score;
printf ("Data: %d, I = %d \n", q.data[i], i);
i++;
}
linearSearch("Matt", q);
return EXIT_SUCCESS;
}
void linearSearch(char* name, Word q){
int i = 0;
int foundIt = 0;
int numNames = sizeof(&q.name);
while ((foundIt == 0) && (i <= numNames)){
printf("Name: %s \n", q.name[i]);
printf("Data: %d \n", q.data[i]);
if ((strcmp(name, q.name[i]) != 0)){
i = i + 1;
} else {
foundIt = 1;
}
}
if (foundIt == 1){
printf("Name found at position %d", i);
} else {
printf("Required person not found");
}
}
This happens because of the code
q.name[i] = username;
You cannot assign the value of an array using = operator. Here, you're assigning the address of username to every q.name[i]. So, the last value of username is reflected throughout the array.
What you actually need is to use malloc() to allocate memory and then strcpy() to copy the string contents.
Otherwise, you can also make use of strdup().
Either way, don't forget to free() the allocated ememory once you're done using them.
I can see that you declared char username[9], so I assume your names should be at most 8 characters long. You should :
read with : fscanf(ifp, "%8s %d",&username, &score) == 2 : the & is useless in front of an array (it decays nicely to a pointer), but you should limit size of input - ok , your problem does not come from there
use a 2D char array for Word.name instead of an array of pointers. That way your memory is already allocated and you can safely strcpy to it :
typedef struct {
char name[10][9];
int data[10];
}Word;
then :
strcpy(q.name[i], username); /* safe because qname[i] and username are both [9] */
The rule here is always control that you do not risk a buffer overrun when writing in char arrays/
An alternative way would be to do dynamic allocation through strdup but in that case you should free it.

fscanf() filter

I have a file with data in this format:
Name WeekDay Month day, Year StartHour:StartMin Distance Hour:Min:Sec
Example:
John Mon September 5, 2011 09:18 5830 0:26:37
I want to scan this into a struct:
typedef struct {
char name[20];
char week_day[3];
char month[10];
int day;
int year;
int startHour;
int startMin;
int distance;
int hour;
int min;
int sec;
} List;
i use fscanf():
List listarray[100];
for(int i = 0; ch = fgetc(file) != 'EOF'; ch = fgetc(file), i++){
if(ch != '\0'){
fscanf(file, "%s %s %s %d %d %d %d %d %d %d %d", &listarray[i].name...etc)
}
}
My issue is that I want to filter out the noise in the input string, that being:
Month day*,* year <- the comma is consistent in all entries. I just want the month in the char array, the day in int.
And the time stamps:
startHour:startmin and hour:min:sec <- here I want to filter out the colon.
Do I need to put it into a string first and then do some splitting, or can I handle it in fscanf?
Update:
Okay, så I've been trying to get this to work now, but I simply cannot. I literally have no idea what the issue is.
#include <stdio.h>
/*
Struct to hold data for each runners entry
*/
typedef struct {
char name[21];
char week_day[4];
char month[11];
int date,
year,
start_hour,
start_min,
distance,
end_hour,
end_min,
end_sec;
} runnerData;
int main (int argc, const char * argv[])
{
FILE *dataFile = fopen("/Users/dennisnielsen/Documents/Development/C/Afleveringer/Eksamen/Eksamen/runs.txt", "r");
char ch;
int i, lines = 0;
//Load file
if(!dataFile)
printf("\nError: Could not open file!");
//Load data into struct.
ch = getc(dataFile);
//Find the total ammount of lines
//To find size of struct array
while(ch != EOF){
if(ch == '\n')
lines++;
ch = getc(dataFile);
}
//Allocate memory
runnerData *list = malloc(sizeof(runnerData) * lines);
//Load data into struct
for(i = 0; i < lines; i++){
fscanf(dataFile, "%s %s %s %d, %d %d:%d %d %d:%d:%d %[\n]",
list[i].name,
list[i].week_day,
list[i].month,
list[i].date,
list[i].year,
list[i].start_hour,
list[i].start_min,
list[i].distance,
list[i].end_hour,
list[i].end_min,
list[i].end_sec);
printf("\n#%d:%s", i, list[i].name);
}
fclose(dataFile);
return 0;
}
I've been told that "only strings to do not require & in front of them in fscanf();" but I tried both with and without ampersand to no avail.
Put the "noise" in the format string.
Also you might like to limit the size of strings.
And get rid of the & for arrays.
And test the return value from scanf!
// John Mon September 5, 2011 09:18 5830 0:26:37
if (scanf("%19s%2s%9s%d,%d%d:%d%d%d:%d:%d", ...) != 11) /* error */;
// ^^^ error: not enough space
Notice week_day has space for 2 characters and the zero terminator only.
You can put this noise in the scanf format string.
Note also that for date/time strings, you can use strptime. It does the same kind of job that scanf, but is specialized on date/times. You will bo able to use %Y, %M ... and other with it.

Resources