1

So i have this simple code that i've found here. I want to make it work in a loop. I've tried couple of times with diffrent methods but output is bad. Working in Ubuntu Visual Studio

EDIT I've added if(y>=2015 && y<=3000) and it is working properly?

EDIT 2 I've modified my code and followed @Sergey advice... It is still not working properly... I've tried to add "Check return value of scanf" but it is also not working.

        if ((scanf("%u", &d) == 1) && (scanf("%u", &m) == 1) && (scanf("%u", &y) == 1))
            while (fdateCheck());
        else
    //...EOF or conversion failure...
            while (fdateCheck());

or

while ((rc = scanf("%u.%u.%u", &d, &m, &y)) != EOF)
{
    if (rc != 3)
        //...oops data problems...
    else
        //...all OK...
}

Need advice about checking return of scanfs

int fdateCheck();

unsigned int d,m,y;
unsigned int daysinmonth[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int rc;
int legit = 0;

int main()
    {
        printf("Enter the date\n");
        scanf("%u.%u.%u",&d,&m,&y);
        while (fdateCheck());
    }
int fdateCheck()
    {   
        if (y % 400 == 0 || (y % 100 != 0 && y % 4 == 0))
            {
                daysinmonth[1]=29;
            }
            else if (y >= 2015 && y <= 3000)
                {
                    if (m < 13)
                        {
                            if (d <= daysinmonth[m-1])
                            legit = 1;
                        }

                    if (legit == 1)
                        {
                            system("clear");  
                            printf("It is a legitimate date!\n");
                            return 0;
                        }
                }
            else
                system("clear");     
                int ch = fgetc(stdin);
                if (ch == '\n')
                    {
                        system("clear");
                        printf("It's not a legitimate date!\n");
                        printf("\nRetry: ");
                        return 1;
                    }
                fflush(stdin);
    }

jadamian
  • 33
  • 7
  • [`int ch`](https://stackoverflow.com/questions/35356322/difference-between-int-and-char-in-getchar-fgetc-and-putchar-fputc) – Antti Haapala -- Слава Україні Aug 14 '19 at 09:16
  • 2
    Don't use [*magic numbers*](https://en.wikipedia.org/wiki/Magic_number_(programming)) like `0x0A`. If you mean a newline `'\n'` then say so explicitly. – Some programmer dude Aug 14 '19 at 09:18
  • 2
    Also, calling `main` recursively is a *really bad* habit. Use real loops instead. – Some programmer dude Aug 14 '19 at 09:18
  • When i type date ```20.12.2015``` its ok, when i type ```20.20.2015``` output is correct, but when i type ```a.a.a``` im getting ```Segmentation fault (core dumped)``` – jadamian Aug 14 '19 at 09:20
  • 3
    You need to learn how to check function return values for error conditions. Most definitely you need to check what [`scanf`](https://en.cppreference.com/w/c/io/fscanf#Return_value) returns. And to solve that crashing problem, consider using [`fgets`](https://en.cppreference.com/w/c/io/fgets) in combination with `sscanf`. – Some programmer dude Aug 14 '19 at 09:24
  • So i have added ```if(y>=2015 && y<=3000)``` before first ```if``` and it's working now...?? – jadamian Aug 14 '19 at 10:07
  • 2
    Check *return value* of scanf. Handle errors. Then things might start making sense. – hyde Aug 14 '19 at 11:11
  • 1
    another thing, u should have an else on your leap year check, otherwise if it once is set to 29 it will remain that way for all years. – AndersK Aug 14 '19 at 11:14
  • return main() is not a good practice. you already got a while loop. why not add one more and then make sure you empty the stdin before calling scanf – AndersK Aug 14 '19 at 11:15
  • OT: for ease of readability and understanding: 1) please consistently indent the code. Indent after every opening brace '{'. Unindent before every closing brace '}'. Suggest each indent level be 4 spaces. 2) separate code blocks: `for` `else` `if` `while` `do...while` `switch` `case` `default` via a single blank line. – user3629249 Aug 15 '19 at 02:26
  • the posted code is missing the function: `main()` and missing the needed `#include` statements for the needed header files, – user3629249 Aug 15 '19 at 02:27
  • regarding: `printf("Enter the date\n"); scanf("%d.%d.%d",&d,&m,&y);` the prompt needs to specify the desired order (day, month, 4 digit year) because, a 2 digit year is not being allowed and (in America, the typical order is 'month day year') and the practice of placing a comma before the year is not being checked – user3629249 Aug 15 '19 at 02:34
  • regarding: `return main();` NEVER call the function: main() in this manner. The function `main()` is expecting certain parameters to be available that are not being setup in the posted code – user3629249 Aug 15 '19 at 02:36
  • per the posted code, a user could enter a 0 or negative number for month and/or day and the code would accept it. However, the result would be incorrect. Suggest using `%u` for the input conversion specifiers for the call to `scanf()` and declaring the month and day and year variables as `unsigned int` rather than `int` – user3629249 Aug 15 '19 at 02:50
  • Thanks for all that, but i still have problem with return of scanf values – jadamian Aug 19 '19 at 10:57
  • @Anders can you help me with that else for leap year? – jadamian Aug 19 '19 at 12:38
  • @Some programmer dude Could you explain to me how should i use ```fgets sscanf``` here – jadamian Aug 19 '19 at 12:55

1 Answers1

1

If you have an appropriate code in the function void main() and need to repeat it in a cycle as you describe you can do the following:

  1. rename original void main() to int one_step()
  2. put return 0; after printf("It is a legitimate date!\n");
  3. put return 1; after printf("It's not a legitimate date!\n");
  4. create the new void main() function as:
void main() {
    while(one_step());
}

You do not need break; and return main();. You may need some enhancements as described in the comments above. Good luck in coding!

UPDATE #1

I meant such an improvement of your code:

#include <stdio.h>
#include <stdlib.h>

int fdateCheck();

int main()
{
    while (fdateCheck());
}

int fdateCheck()
{
int res;
int legit = 0;
unsigned int d,m,y;
unsigned int daysinmonth[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    // get input block
    printf("Enter the date\n");         // prompt for data
    res = scanf("%u.%u.%u",&d,&m,&y);   // get input data
    if (res == EOF) {                   // check if no more input
            printf("Input error\n");
            exit(1);
    }
    // check if input data is valid
    if (res != 3) {                     // check if 3 numbers scanned
            system("clear");
            printf("It is not a date\n");
            fflush(stdin);
            return 1;
    }
    // make leap year correction
    if (y % 400 == 0 || (y % 100 != 0 && y % 4 == 0)) {
        daysinmonth[1]=29;              // leap year correction
    }
    // check if year, month and day is valid
    if (y >= 2015 && y <= 3000) {       // check if year in this range
        if (0 < m && m < 13) {          // check if month in this range
            if (0 < d && d <= daysinmonth[m-1]) // check if day in this range
                legit = 1;
        }
    }
    // print a message and finish the iteration
    if (legit == 1) {
        printf("It is a legitimate date!\n");
        return 0;
    }
    else {
        system("clear");
        printf("It's not a legitimate date!\n");
        printf("Please retry.\n");
        fflush(stdin);
        return 1;
    }
}

I also moved all variables inside the function. This will restore values of legit and daysinmonth[1] before each iteration.

UPDATE #2

My next proposal:

#include <stdio.h>
#include <stdlib.h>

int fdateCheck();

int main()
{
    while (fdateCheck());
}

int fdateCheck()
{
int res;
int legit = 0;
unsigned int d,m,y;
unsigned int daysinmonth[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    // get input block
    printf("Enter the date\n");         // prompt for data
    res = scanf("%u.%u.%u",&d,&m,&y);   // get input data
    if (res == EOF) {                   // check if no more input
            printf("Input error\n");
            exit(1);
    }
    // check if input data is valid
    if (res != 3) {                     // check if 3 numbers scanned
            fgetc(stdin);               // remove a barrier
            system("clear");
            printf("It is not a date\n");
            fflush(stdin);
            return 1;
    }
    // make leap year correction
    if (y % 400 == 0 || (y % 100 != 0 && y % 4 == 0)) {
        daysinmonth[1]=29;              // leap year correction
    }
    // check if year, month and day is valid
    if (y >= 2015 && y <= 3000) {       // check if year in this range
        if (0 < m && m < 13) {          // check if month in this range
            if (0 < d && d <= daysinmonth[m-1]) // check if day in this range
                legit = 1;
        }
    }
    // print a message and finish the iteration
    if (legit == 1) {
        printf("It is a legitimate date!\n");
        return 0;
    }
    else {
        system("clear");
        printf("It's not a legitimate date!\n");
        printf("Please retry.\n");
        fflush(stdin);
        return 1;
    }
}
Sergey
  • 522
  • 2
  • 8
  • thanks for this answer, it will be helpful in the future – jadamian Aug 19 '19 at 10:00
  • Code works properly, but there is an error. When input is for example ```a.b.c.``` program is in endless loop – jadamian Aug 20 '19 at 07:30
  • I've added this ```system("clear"); int ch = fgetc(stdin);if (ch == '\n'){system("clear");printf("It's not a legitimate date!\n");fflush(stdin);return 1;}``` in ```if (res!=3)``` – jadamian Aug 20 '19 at 08:18
  • 1
    Perfect! You caught me. But I still think that it is not necessary to check the value of `ch`. Please see update #2. – Sergey Aug 20 '19 at 16:57