-1

The second time I call scanf in this program, the function doesn't wait for user input. I know with chars you have to leave a space before the format specifier (which I have tried) but can't figure out whats happening with this int. Thanks!

// Program to calculate the number of elasped days between two dates.

#include <stdio.h>

struct date
{
    int day;
    int month;
    int year;
};

int valueofN (struct date d);
int f(int year, int month);
int g(int month);

int main (void)
{
    struct date date1, date2;

    printf("Enter the first date - dd:mm:yyyy : ");
    scanf("%i:%i:%i", &date1.day, &date1.month, &date1.year);

    printf("Enter the second date - dd:mm:yyyy : ");
    scanf("%i:%i:%i", &date2.day, &date2.month, &date2.year);

    // The line above here is where the problem lies ^^^^

    long int N1 = valueofN (date1);
    long int N2 = valueofN (date2);

    printf("Number of elasped days = %li\n", (N2 - N1));

    return 0;
}

// Functions

int valueofN (struct date d)
{
    int N;
    return N = (1461 * (f(d.year, d.month) / 4) + 153 * (g(d.month) / 5) +d.day);
}

int f(int year, int month)
{
    if (month <= 2)
        return (year - 1);
    else
        return year;
}

int g(int month)
{
    if (month <= 2)
        return (month + 13);
    else
        return (month + 1);
}
KaiserKatze
  • 1,521
  • 2
  • 20
  • 30
Paul B
  • 125
  • 13
  • 1
    What does your input look like? As you including the colon in your input? – nicomp Aug 24 '18 at 12:33
  • 1
    e.g. for todays date 24:08:2018 – Paul B Aug 24 '18 at 12:35
  • The second time around, its not even waiting for an input though. That's my problem. – Paul B Aug 24 '18 at 12:36
  • 1
    I compiled your code with **gcc** and there is no problem. What **compiler** do you use and what **terminal environment** are you running your program in? – KaiserKatze Aug 24 '18 at 12:39
  • @user3121023 Ah thanks! %d did it. I'm not really sure of the difference between %i and %d. I need to do some reading! – Paul B Aug 24 '18 at 12:40
  • @KaiserKatze Yes it compiles ok, the problem is fixed, just needed to replace %i with %d, thanks. – Paul B Aug 24 '18 at 12:41
  • @PaulB Sometimes, especially **terminal enviroment** causes similiar problems. that's why I asked. :) – KaiserKatze Aug 24 '18 at 12:43
  • @KaiserKatze I'm using the CS50 IDE – Paul B Aug 24 '18 at 12:44
  • @user3121023 Ok thanks. – Paul B Aug 24 '18 at 12:45
  • How could switching from `%i` to `%d` solve your problem? The program works fine for me as it is (at least the input, I didn't understand or verify the computations). – Peter - Reinstate Monica Aug 24 '18 at 12:58
  • @PeterA.Schneider I'm not too sure but it did fix the problem. With `%d`, the program now waits for the second input. (BTW If anyone is interested, I think the formula for calculating the elasped days is not correct - the code is an exercise from the Stephen Kochan book "Programming in C", and the formula was given.) – Paul B Aug 24 '18 at 13:07
  • 3
    Tip: when `scanf()` does not behave at expected, best that code checks the return value of `scanf()` like `if (scanf("%i:%i:%i", &date1.day, &date1.month, &date1.year) != 3) printf("oops!\n"):` This will quickly narrow the problem. – chux - Reinstate Monica Aug 24 '18 at 13:31
  • @chux very good advice, and often forgotten. – Peter - Reinstate Monica Aug 24 '18 at 14:04
  • @chux Thanks, I noticed there was a problem and added another printf statement to print out the contents of date2. I saw that they were filled with garbage values. I'll try your method though, thanks! – Paul B Aug 24 '18 at 14:54

1 Answers1

1

This is due to format specifier %i.

You may not observe any difference in behaviour %d and %iWhen used with a printf(), but when used with scanf the significance is obvious, that %i takes an integer value as integer value with decimal, hex or octal type, based on some prefix, such that if it begins with 0x its taken a Hex, when preceded with 0, its taken as an Octal value. When you use %d in a scanf, it assume the base 10.

So, you need to replace %i with %d.

Additionally, make a habit of standard library reading man pages of the functions that you are planning to use. For example, scanf, section "Conversions" states that,

i

Matches an optionally signed integer; the next pointer must be a pointer to int. The integer is read in base 16 if it begins with 0x or 0X, in base 8 if it begins with 0, and in base 10 otherwise. Only characters that correspond to the base are used.

Also in section "Return Value", it states,

Return Value These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.

The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set indicate the error.

Getting the return values from scanf, and addition some error handling for unexpected return will save you a lot of pain going ahead.

Additional Inputs:

  1. Its usually preferred/recommended to name your function with verb (or an action) rather than anything that makes no sense.

For example,

int valueofN (struct date d);
int f(int year, int month);
int g(int month);

If I am reviewing your code, I don't know what this function does. Going ahead, name functions and other variables in such a way that it makes sense.

  1. Use compatible data types

For example,

long int N1 = valueofN (date1);
long int N2 = valueofN (date2);

N1 and N2 are of the data type long int while valueofN() is returning an int. Its a different data type, there is no immediate harm with this code, but there is a potential harm in this practice going ahead.

  1. Some improvement

This

int valueofN (struct date d)
{
    int N;
    return N = (1461 * (f(d.year, d.month) / 4) + 153 * (g(d.month) / 5)+ d.day);
}

could have been

int valueofN (struct date d)
{
    return (int)(1461 * (f(d.year, d.month) / 4) + 153 * (g(d.month) / 5) +d.day);
}
  1. Some more improvement: You should always validate the data entered by user (unless you don't know the lower and higher bound values). For example, user can enter 50 for month. It isn't validated. Handle that at the input stage itself. Make that a habit.
WedaPashi
  • 3,561
  • 26
  • 42
  • Thank you very much for all the advice! I've only been programming for 4 weeks so I've a long way to go and i'll take all your advice on board. Yes I usually do validate user input with a printf error message and a do-while loop. Thanks again ;) – Paul B Aug 24 '18 at 14:59
  • The function names and formula were given in the text book example I was working on. I usually do name them appropriately. The functions were part of the formula for N. I too thought that they make no sense! :) – Paul B Aug 24 '18 at 15:12