Erick B
Erick B

Reputation: 1

While return loop issue with function call in C

I´m Working on a program for a class and this is what I have so far. My buddy helped me with the function but when a wrong date is entered it should iterate until a correct date is asked. Not sure what to do we have been working on it for a few hours right now and since we are both new to C, we need some outside help.

#include <stdio.h>      //for input output
#include <stdlib.h>
#include <string.h>     // for string functions
#include <time.h>       //for time functions
#include <stdbool.h>        //bool functions for true/false

//used typedef for convenience, no need to type struct all the time
typedef struct
{
  int m, d, y;
} Data_t;

int checkDate (int m, int d, int y);    //declare function to check input
void modDate (Data_t * data);   //declare function to modify date

int
main ()
{
  int x = 0;    //kill switch for while loop

  //declare a struct variable and initialize it for the date
  Data_t uDate = { 0, 0, 0 };


  /* program has infinite loop bug when using the while loop with x */

  while (x == 0){

      printf ("x before input: %d\n", x);   //debug printer

      // Ask user for date input
      printf ("Enter a date in mm/dd/yyyy format: ");
      //Pass the input to the uDate struct with scanf
      scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y);

      // check data if valid and set x
      x = checkDate (uDate.m, uDate.d, uDate.y);
      printf ("x after check: %d\n", x);    //debug printer

    }
   // end of while loop

  // Display the entered date & modifier message
  printf ("\nDate Entered: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);
  printf ("Adding 1 week to entered date...\n");

  modDate (&uDate); //pass the address of uDate to the modDate function

  /* since it was passed through a pointer (by reference),
     the original uDate struct is now modified */

  // Display the modified date
  printf ("New Date is: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);

  return 0;
}

//Define the checkDate function
int
checkDate (int m, int d, int y)
{
  // This is sloppy.  Clean it up with multiple functions later

  if (y <= 0)
    {
      printf ("Invalid Date, Please try again.\n");
      return false;
    }
  if (m >= 1 && m <= 12)
    {
      //Then check the days against the months & leap years
      if ((d >= 1 && d <= 31)
      && (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10
          || m == 12))
    {
      return true;
    }
      else if ((d >= 1 && d <= 30) && (m == 4 || m == 6 || m == 9 || m == 11))
    {
      return true;
    }
      else if ((d >= 1 && d <= 28) && (m == 2))
    {
      return true;
    }
      else if (d == 29 && m == 2
           && (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)))
    {
      return true;
    }
      else
    {
      printf ("Invalid Date, Please try again.\n");
      return false;
    }
    }
  else
    {
      printf ("Invalid Date, Please try again.\n");
      return false;
    }

}

//Define the modDate function to add 7 days
void
modDate (Data_t * data)
{
  data->d = data->d + 7;    // modify the day element in struct

  // initialize the time_t structs from time.h and pass elements
  struct tm t = {.tm_mon = data->m - 1,.tm_mday = data->d,
    .tm_year = data->y - 1900
  };

  /* month+/-1 is because tm struct stores january as 0 and december as 11
     year+/- 1900 is because year values are calculated starting from
     the year 1900. So when calculating with mktime() you need to get
     the integer value of the year by y-1900.  And to properly display 
     the year value that is returned, you add 1900 as done below */

  mktime (&t);          // call mktime() to calculate the new date

  // pass new values into struct and reformat month & year 
  data->m = t.tm_mon + 1;
  data->d = t.tm_mday;
  data->y = t.tm_year + 1900;
}

Upvotes: 0

Views: 76

Answers (2)

Odysseus
Odysseus

Reputation: 1263

Your problem is that wrong input for scanf is not properly handled.

If you enter something like "A", scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y); won't be successful because it could not read any int that was expected. Because your "A" is not properly processed it remains in your input buffer what will cause scanf to fail again and again.

So first you should check if all 3 expected values are read:

if (scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y) != 3)
    // x remains 0
    printf("Invalid input format!\n");
else
    x = checkDate (uDate.m, uDate.d, uDate.y);

This alone would not be enough because the wrong input still remains in your input buffer. So you need to flush it before you are making the next try:

Edit As @AndrewHenle pointed out you should avoid using fflush(stdin) (at least if you are not on a windows platform and want to keep your code portable). So another solution is to read every input including newline character after user input with e.g. while((getchar()) != '\n');

if (scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y) != 3)
    // x remains 0
    printf("Invalid input format!\n");
else
    x = checkDate (uDate.m, uDate.d, uDate.y);

// flush input buffer
while((getchar()) != '\n');

Upvotes: 1

ralf htp
ralf htp

Reputation: 9422

You have declared return type of int checkDate (int m, int d, int y); as int but return a bool. When correcting this to bool checkDate (int m, int d, int y); the code seems to work:

#include <stdio.h>      //for input output
#include <stdlib.h>
#include <string.h>     // for string functions
#include <time.h>       //for time functions
#include <stdbool.h>        //bool functions for true/false

//used typedef for convenience, no need to type struct all the time
typedef struct
{
  int m, d, y;
} Data_t;

bool checkDate (int m, int d, int y);    //declare function to check input
void modDate (Data_t * data);   //declare function to modify date

int
main ()
{
  bool x = false;    //kill switch for while loop

  //declare a struct variable and initialize it for the date
  Data_t uDate = { 0, 0, 0 };


  /* program has infinite loop bug when using the while loop with x */

  while (x == false){

      printf ("x before input: %d\n", x);   //debug printer

      // Ask user for date input
      printf ("Enter a date in mm/dd/yyyy format: ");
      //Pass the input to the uDate struct with scanf
      scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y);

      // check data if valid and set x
      x = checkDate (uDate.m, uDate.d, uDate.y);
      printf ("x after check: %d\n", x);    //debug printer

    }
   // end of while loop

  // Display the entered date & modifier message
  printf ("\nDate Entered: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);
  printf ("Adding 1 week to entered date...\n");

  modDate (&uDate); //pass the address of uDate to the modDate function

  /* since it was passed through a pointer (by reference),
     the original uDate struct is now modified */

  // Display the modified date
  printf ("New Date is: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);

  return 0;
}

//Define the checkDate function
bool
checkDate (int m, int d, int y)
{
  // This is sloppy.  Clean it up with multiple functions later

  if (y <= 0)
    {
      printf ("Invalid Date, Please try again.\n");
      return false;
    }
  if (m >= 1 && m <= 12)
    {
      //Then check the days against the months & leap years
      if ((d >= 1 && d <= 31)
      && (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10
          || m == 12))
    {
      return true;
    }
      else if ((d >= 1 && d <= 30) && (m == 4 || m == 6 || m == 9 || m == 11))
    {
      return true;
    }
      else if ((d >= 1 && d <= 28) && (m == 2))
    {
      return true;
    }
      else if (d == 29 && m == 2
           && (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)))
    {
      return true;
    }
      else
    {
      printf ("Invalid Date, Please try again.\n");
      return false;
    }
    }
  else
    {
      printf ("Invalid Date, Please try again.\n");
      return false;
    }

}

//Define the modDate function to add 7 days
void
modDate (Data_t * data)
{
  data->d = data->d + 7;    // modify the day element in struct

  // initialize the time_t structs from time.h and pass elements
  struct tm t = {.tm_mon = data->m - 1,.tm_mday = data->d,
    .tm_year = data->y - 1900
  };

  /* month+/-1 is because tm struct stores january as 0 and december as 11
     year+/- 1900 is because year values are calculated starting from
     the year 1900. So when calculating with mktime() you need to get
     the integer value of the year by y-1900.  And to properly display 
     the year value that is returned, you add 1900 as done below */

  mktime (&t);          // call mktime() to calculate the new date

  // pass new values into struct and reformat month & year 
  data->m = t.tm_mon + 1;
  data->d = t.tm_mday;
  data->y = t.tm_year + 1900;
}

Upvotes: 0

Related Questions