0

I am making a simple program where it takes a year from the user and determines if its a leap year or not. The problem I am having is I want it so if the user enters a string it will either end the program if the string is "N" and if its any other string of characters it will just print input is invalid. But as of right now any string input into scanf breaks the program and causes it to loop infinitely.



#include <stdio.h>
#include <stdbool.h>
#include "leapyear.h"



int main() {

    int year = 0;

    while (true) {
        printf("Please enter a year to check:");
        scanf("%i", &year);

        if (year <= 0) {
            printf("Sorry that input is invalid..\n");
        }

        else if(year == "N") {
            printf("Quitting....");
            return 0;
        }

        else {
            if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
                 printf("%i IS a leap year \n", year);
            }
            else {
                printf("%i IS NOT a leap year \n", year);
            }
        }
    }
    return 0;
}

Ive went through about every post on here about scanf and how to take an int while also allowing for a string to be inputted and stored into the same variable but I cant wrap my head around it. Any help at all would be greatly appreciated.

mokmok74
  • 1
  • 1
  • please edit your example to make it reproducible (take out reference to "leapYear()" and replace it with a placeholder so we can run your code) – erik258 Feb 07 '23 at 19:15
  • 4
    If you want to input a string, you need a char buffer and input into it. Then you can check it's contents to see if it is the string representation of an int or not. An int is not a string and variables in C do not change type. Oh, and you can't compare c-style strings with ++. Perhaps you need a better book? – Avi Berger Feb 07 '23 at 19:16
  • Err, change that to "you can't compare c-style strings with ==." – Avi Berger Feb 07 '23 at 19:23
  • You can make this very easy if you change your requirements slightly. If you change your requirement to "Enter a year number to check, or the words 'n' or 'none' *or any other non-numeric input* to quit", then you can use the very simple code 'if(scanf("%i", &year) != 1) { printf("Quitting...."); return 0; }`. – Steve Summit Feb 07 '23 at 19:31
  • If you want to separate the "Quitting" and "Sorry that input is invalid" cases, it's exponentially harder, and essentially impossible using `scanf` alone. You can use `%d` to read integers, or `%s` to read strings, but there's no `scanf` format for "integer-but-maybe-it's-a-string". – Steve Summit Feb 07 '23 at 19:32

2 Answers2

1

The line

else if(year == "N") {

does not make sense, because year is of type int and therefore unable to represent the string "N".

If you want to determine whether the input the user entered represents an integer or not, you can read the input as a string using fgets and then use the function strtol to attempt to convert it to an integer. Here is an example:

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

int main( void )
{
    char line[200];
    long i;
    char *p;

    //read a line of input from the user as a string
    printf( "Please enter an integer or a string: " );
    if ( fgets( line, sizeof line, stdin ) == NULL )
    {
        fprintf( stderr, "Input error!\n" );
        exit( EXIT_FAILURE );
    }

    //remove newline character from input, if it exists
    line[strcspn(line,"\n")] = '\0';

    //attempt to convert string to an integer
    i = strtol( line, &p, 10 );

    //test whether conversion was successful
    if ( p != line )
    {
        printf( "The input was successfully converted to the integer %ld.\n", i );
    }
    else
    {
        printf( "Unable to convert input to an integer, so the input is a simple string.\n" );
    }
}

This program has the following behavior:

Please enter an integer or a string: 5
The input was successfully converted to the integer 5.
Please enter an integer or a string: test
Unable to convert input to an integer, so the input is a simple string.

If the input is not an integer and you want to determine whether the user entered "N", you can use the following condition:

if ( strcmp( line, "N" ) == 0 )
{
    printf( "You entered \"N\".\n" );
}
else
{
    printf( "You did not enter \"N\".\n" );
}
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
1

The C language is a statically typed language, which means that if you have your int year defined as, indeed, an integer, you cannot store a string in there.

That said, while you cannot take both a string and an integer at the same time because of that reason, what you can do is take the input as a string and then parse the result to see if it happens to be an integer.

To do so, simply use strtol as suggested here:

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

int main() {
    char yearString[10];

    while(true) {
        printf("Please enter a year to check: ");
        
        // scan our year to a string
        fgets(yearString, 10, stdin);
        
        // parse it
        int year = (int)strtol(yearString, NULL, 10);
        
        if(year <= 0) {
            // in this case the input might be either
            // invalid or a string so we check for that
            if(yearString[0] == 'N') {
                printf("Quitting....");
                return 0;
            } else {
                printf("Sorry that input is invalid..\n");
            }
        } else {
            if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
                 printf("%i IS a leap year \n", year);
            } else {
                printf("%i IS NOT a leap year \n", year);
            }
        }
    }
    return 0;
}
SerialSniper
  • 46
  • 1
  • 4
  • I accidentally created a c++ file to test it indeed, as for the `fgets` I didn't know that, thanks for the suggestion! I just modified the code to comply with your tips. – SerialSniper Feb 07 '23 at 20:34