Обход массива для пользовательского ввода с целью печати пользовательского вывода - PullRequest
0 голосов
/ 20 апреля 2019

Снимок экрана, на котором показана проблема

Я пытаюсь распечатать вывод пользователя путем обхода массива на языке программирования C.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//my global variables
char day[15];
int dailyTrainCount[5];     // variable for daily train count
int trainTimeFrame[5], i;   // variable to daily train time frames and loop control

//begin program
int main()
{   
    printf("Welcome to TMS(TRAIN MANAGEMENT SYSTEM)\n");
    printf("Enter day of Operation\n");
    scanf("%s", day);//user input for day 
    printf("How many trains to operate on %s?(Trains shall not exceed 5)\n", 
     day);
    scanf("%d", &dailyTrainCount[5]);//daily train count variable

    //loop to ensure user enters no more than 5 trains per day
    while(dailyTrainCount[5] > 5){
          printf("Daily train count shall not exceed 5\n");
          printf("enter train count\n");
          scanf("%d", &dailyTrainCount[5]);
        }
    //show train menu to user
    printf("%d Train(s) will operate on %s\n",dailyTrainCount[5], day);
    printf("Available time frames\n");
    printf("(1):7AM-10PM\n");
    printf("(2):10AM-1PM\n");
    printf("(3):1PM-4PM\n");
    printf("(4):4PM-7PM\n");

    for(i=0; i<dailyTrainCount[5]; i++)
    {
        printf("Enter time frame for train #%d: \n",i+1);
        scanf("%d", &trainTimeFrame[5]);

    }

    //This loop is not traversing through the entire array, it only shows the last two input
    for(i=0; i<dailyTrainCount[5]; i++)
    {
        printf("Train #%d is set to time frame #%d\n",   // This is the print statement that
                                                         // is not producing the output as I intended
               dailyTrainCount[5], 
               trainTimeFrame[5]);
    }

    return 0;
}

Как я могуправильно сделать вывод для последнего цикла for?Я использую кодовые блоки.Я также попытался изменить все массивы на [i] вместо [5].

1 Ответ

1 голос
/ 20 апреля 2019

У вас есть фундаментальное неправильное понимание использования массивов в C:

int dailyTrainCount[5];     // variable for daily train count
...
    scanf("%d", &dailyTrainCount[5]);

int dailyTrainCout[5]; объявляет целочисленный массив с 5 элементами. Допустимые индексы для этих элементов: [0-4], C / C ++ использует ноль массивов. Присваивая dailyTrainCount[5], вы назначаете вход в ячейку памяти 1 после конца массива dailyTrainCount, вызывая Неопределенное поведение . (определенное выполнение вашей программы прекращается в этот момент, и может произойти что-то от появления нормального режима до SegFaulting) Более фундаментально, будет только 1 dailyTrainCount, поэтому для начала массив не нужен.

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

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

scanf можно использовать, если используется правильно. Это означает, что вы несете ответственность за проверку возврата из scanf каждый раз . Вы должны справиться с тремя условиями

  1. (return == EOF) пользователь отменил ввод, сгенерировав руководство EOF, нажав Ctrl + d (или Ctrl + z в окнах);
  2. (return < expected No. of conversions) a соответствие или вход произошла ошибка. Для сбоя match вы должны учитывать каждый символ, оставшийся в вашем входном буфере (сканирование вперед во входном буфере с чтением и отбрасыванием символов до тех пор, пока не будет найдено '\n' или EOF); и наконец
  3. (return == expected No. of conversions) указывает на успешное чтение - тогда вам нужно проверить, соответствует ли входные данные каким-либо дополнительным критериям (например, положительное целое число, положительная плавающая точка, в требуемом диапазоне и т. Д.).

Примечание: после неудачного совпадения или успешного чтения вы должны очистить буфер ввода, чтобы убедиться, что он подготовлен для следующего ввода пользователя, независимо от того, какая функция используется принять вход. Например, если вы успешно используете scanf для получения целочисленного ввода, но оставляете завершающий '\n' в буфере ввода, а затем позже пытаетесь ввести с помощью fgets, ваш ввод не удастся, и ваш буфер будет содержать пустым -string независимо от того, сколько символов вводит пользователь ...

Чтобы упростить правильное использование scanf, вы можете использовать короткую вспомогательную функцию для очистки символов из stdin после каждого ввода. После каждого ввода вы просто вызываете getchar() для чтения до тех пор, пока не будет найден '\n' или EOF, например,

/* simple function to empty stdin */
void empty_stdin (void)
{
    int c = getchar();

    while (c != '\n' && c != EOF)
        c = getchar();
}

Затем, как минимум , вы должны подтвердить, что возвращение scanf соответствует количеству конверсий, указанному в вашей строке формата , например,

    char day[MAXDAY];
    int /* dailyTrainCount[5],*/ trainsperday,
        trainTimeFrame[MAXTRAIN], i = 0;

    fputs ("Welcome to TMS (TRAIN MANAGEMENT SYSTEM)\n\n"
            "  Enter day of Operation: ", stdout);
    if (scanf ("%14s", day) != 1) { /* VALIDATE EVERY INPUT - check return */
        fputs ("(user canceled day input.)\n", stderr);
        return 1;
    }
    empty_stdin();  /* empty remaining characters in stdin */

( примечание: ваш массив dailyTrainCount[] был заменен на одну целочисленную переменную trainsperday, чтобы сделать изменение массива из int на одно целое число ясным. empty_stdin() защищает от любых посторонних введенных символов, таких как ввод пользователя "Monday April 22, 2019". Посмотрите, что произойдет, если вы попробуете это без очистки stdin ...)

Чтобы полностью проверить каждый требуемый вход, вы должны проверить и адекватно обработать все три условия, изложенные выше, например,

    for (;;) {  /* loop continually until valid input received */
        printf ("\n  How many trains to operate on %s?"
                " [1-5]: ", day);
        int rtn = scanf ("%d", &trainsperday);  /* save scanf return */
        if (rtn == EOF) {   /* handle EOF */
            fputs ("(user canceled day input.)\n", stderr);
            return 1;
        }
        empty_stdin();  /* empty remaining characters in stdin */
        if (rtn < 1)    /* if matching failure */
            fputs ("  (error: invalid integer input.)\n", stderr);
        else if (trainsperday < 0 || 5 < trainsperday)  /* out of range */
            fputs ("  (error: trainsperday exceeds 5.)\n", stderr);
        else            /* good input, break input loop */
            break;
    }

Таким образом, вы можете выполнять заполнение расписания поездов, обрабатывая все ошибки ввода или значения вне диапазона, в то же время позволяя пользователю отменять ввод в любой точке и обеспечивая плавное завершение вашей программы. Переделка вашего кода может быть:

#include <stdio.h>

/*  my global variables - don't use them, declare in scope needed, but
 *  do #define any constants needed to avoid magic-numbers in your code
 */
#define MAXTRAIN 5
#define MAXDAY  15

/* simple function to empty stdin */
void empty_stdin (void)
{
    int c = getchar();

    while (c != '\n' && c != EOF)
        c = getchar();
}

int main (void)
{   
    char day[MAXDAY];
    int /* dailyTrainCount[5],*/ trainsperday,
        trainTimeFrame[MAXTRAIN], i = 0;

    fputs ("Welcome to TMS (TRAIN MANAGEMENT SYSTEM)\n\n"
            "  Enter day of Operation: ", stdout);
    if (scanf ("%14s", day) != 1) { /* VALIDATE EVERY INPUT - check return */
        fputs ("(user canceled day input.)\n", stderr);
        return 1;
    }
    empty_stdin();  /* empty remaining characters in stdin */

    for (;;) {  /* loop continually until valid input received */
        printf ("\n  How many trains to operate on %s?"
                " [1-5]: ", day);
        int rtn = scanf ("%d", &trainsperday);  /* save scanf return */
        if (rtn == EOF) {   /* handle EOF */
            fputs ("(user canceled day input.)\n", stderr);
            return 1;
        }
        empty_stdin();  /* empty remaining characters in stdin */
        if (rtn < 1)    /* if matching failure */
            fputs ("  (error: invalid integer input.)\n", stderr);
        else if (trainsperday < 0 || 5 < trainsperday)  /* out of range */
            fputs ("  (error: trainsperday exceeds 5.)\n", stderr);
        else            /* good input, break input loop */
            break;
    }
    /* show train menu to user */
    printf ("\n%d Train(s) will operate on %s\n\n"
            " Available time frames\n"
            "  (1) - 7AM-10PM\n"
            "  (2) - 10AM-1PM\n"
            "  (3) - 1PM-4PM\n"
            "  (4) - 4PM-7PM\n\n", trainsperday, day);

    while (i < trainsperday) {  /* use while, not for, to handle errors */
        printf ("  Enter time frame for train #%d: ", i + 1);
        int rtn = scanf ("%d", &trainTimeFrame[i]); /* save scanf return */
        if (rtn == EOF) {   /* handle EOF */
            fputs ("(user canceled day input.)\n", stderr);
            return 1;
        }
        empty_stdin();  /* empty remaining characters in stdin */
        if (rtn < 1)    /* if matching failure */
            fputs ("  (error: invalid integer input, valid input [1-4].)\n",
                    stderr);
        else if (trainTimeFrame[i] < 0 || 4 < trainTimeFrame[i]) /* valid? */
            fputs ("  (error: invalid time frame, valid input [1-4].)\n",
                    stderr);
        else            /* good input, now increment i */
            i++;
    }

    /* output train schedule */
    printf ("\nTrain Schedule:\n\n");
    for (i = 0; i < trainsperday; i++)
        printf ("  Train #%d is set to time frame #%d\n",
                i + 1, trainTimeFrame[i]);

    return 0;
}

( примечание: использование цикла while вместо цикла for при заполнении таймфреймов для каждого поезда. Если используется for и происходит сбой, восстановление невозможно Использование while и только увеличение счетчика на допустимом вводе дает решение)

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

Пример использования / Вывод

С преднамеренным неверным вводом для этой цели.

$ ./bin/trainsperday
Welcome to TMS (TRAIN MANAGEMENT SYSTEM)

  Enter day of Operation: Tuesday April 23, 2019

  How many trains to operate on Tuesday? [1-5]: Ten Trains on Tuesday
  (error: invalid integer input.)

  How many trains to operate on Tuesday? [1-5]: 7
  (error: trainsperday exceeds 5.)

  How many trains to operate on Tuesday? [1-5]: 3

3 Train(s) will operate on Tuesday

 Available time frames
  (1) - 7AM-10PM
  (2) - 10AM-1PM
  (3) - 1PM-4PM
  (4) - 4PM-7PM

  Enter time frame for train #1: 7AM-10PM
  (error: invalid time frame, valid input [1-4].)
  Enter time frame for train #1: 5
  (error: invalid time frame, valid input [1-4].)
  Enter time frame for train #1: 3
  Enter time frame for train #2: 1
  Enter time frame for train #3: 2

Train Schedule:

  Train #1 is set to time frame #3
  Train #2 is set to time frame #1
  Train #3 is set to time frame #2

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...