Scanf () не ожидает целочисленного ввода - PullRequest
0 голосов
/ 24 августа 2018

Во второй раз, когда я вызываю scanf в этой программе, функция не ждет ввода пользователя.Я знаю, что с символами вы должны оставить пробел перед спецификатором формата (который я пробовал), но не могу понять, что происходит с этим int.Спасибо!

// 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);
}

1 Ответ

0 голосов
/ 24 августа 2018

Это связано с спецификатором формата %i.

Вы не можете наблюдать каких-либо различий в поведении %d и %i При использовании с printf(), но при использовании с scanf значение очевидно, что %i принимает целочисленное значение в качестве целочисленного значения с десятичный, шестнадцатеричный или восьмеричный тип, основанный на некотором префиксе, такой, что если он начинается с 0x, то он принимает Hex, а перед 0 - как восьмеричное значение. Когда вы используете %d в scanf, оно принимает основание 10.

Итак, вам нужно заменить %i на %d.

Кроме того, выработайте привычку к чтению справочных страниц из стандартной библиотеки тех функций, которые вы планируете использовать. Например, scanf, раздел «Преобразования» гласит, что

я

Соответствует необязательно подписанному целому числу; следующий указатель должен быть указателем на int. Целое число читается в базе 16, если оно начинается с 0x или 0X, в базе 8, если оно начинается с 0, и в базе 10 в противном случае. Используются только символы, соответствующие основанию.

Также в разделе «Возвращаемое значение» , оно гласит,

Возвращаемое значение Эти функции возвращают количество элементов ввода, успешно сопоставленных и назначенных, которое может быть меньше предусмотренного или даже равно нулю в случае сбоя при раннем сопоставлении.

Значение EOF возвращается, если достигнут конец ввода перед первым успешным преобразованием или ошибкой сопоставления. EOF также возвращается, если происходит ошибка чтения, и в этом случае устанавливается индикатор ошибки для потока (см. Ferror (3)), и устанавливается errno, обозначающий ошибку.

Получение возвращаемых значений из scanf и добавление некоторой обработки ошибок для неожиданного возврата избавят вас от многих проблем в будущем.

Дополнительные входы:

  1. Обычно предпочитают / рекомендуют называть вашу функцию глаголом (или действием), а не тем, что не имеет смысла.

Например,

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

Если я проверяю ваш код, я не знаю, что делает эта функция. В дальнейшем назовите функции и другие переменные так, чтобы это имело смысл.

  1. Использовать совместимые типы данных

Например,

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

N1 и N2 относятся к типу данных long int, а valueofN() возвращает int. Это другой тип данных, в этом коде нет непосредственного вреда, но в этой практике есть потенциальный вред.

  1. Некоторое улучшение

Это

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

могло бы быть

int valueofN (struct date d)
{
    return (int)(1461 * (f(d.year, d.month) / 4) + 153 * (g(d.month) / 5) +d.day);
}
  1. Еще одно улучшение: вы всегда должны проверять данные, введенные пользователем (если вы не знаете нижнюю и верхнюю граничные значения). Например, пользователь может ввести 50 для month. Это не подтверждено. Обработайте это на самом этапе ввода. Сделайте это привычкой.
...