C Функция выхода перед вводом - PullRequest
1 голос
/ 03 декабря 2009

В настоящее время я делаю проект для класса программирования Beginner C, где я должен создать базовую систему заказов для компании. У меня проблема с одной из моих функций, она отлично работает как отдельная программа, но как функция в программе упорядочения не позволяет мне вводить новый элемент до выхода из функции. Кажется, однако, чтобы пройти через все после get (item); как я получаю добавленный \ n каждый раз, когда я запускаю его.

Вот мой код:

do{
printf("Menu here");
scanf("%c", &menu);
switch(menu)
{
    case 'A':
        listItem();
        break;

    case 'B':
        addItem();
        break;

    ...

    case 'X':
        break;
}

printf("Press Enter to continue.");
scanf("%c%c", &enter, &enter);
system("cls");

}while(menu != 'X');


void addItem()
{
    char item[30];
    printf("\nAdd new item: ");
    gets(item);
    FILE * output;
    output = fopen("items.txt", "a");
    fputs(item, output);
    fprintf(output, "\n");
    fclose(output);
}

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

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

Ответы [ 3 ]

5 голосов
/ 03 декабря 2009

Что происходит, это:

  1. Программа печатает меню.
    • Типы пользователей "B <enter>".
    • scanf читает символ B. <enter> все еще ожидает во входном потоке.
    • addItem называется.
    • gets() вызывается, читает <enter>, который все еще ждет, и возвращает пустую строку.

Вы можете исправить это, прочитав и отбросив все, вплоть до следующего символа новой строки, после того как вы прочитали символ выбора меню с помощью scanf:

int c;

printf("Menu here");
scanf("%c", &menu);
do {
    c = getchar();
} while (c != EOF && c != '\n');
1 голос
/ 03 декабря 2009

Вы читаете один символ за раз, а scanf() выполняет некоторую буферизацию. Если я наберу «ABC» и нажму «Enter», ваша программа будет читать «A», выполнять действие для «A», печатать «нажать Enter, чтобы продолжить», читая «B» и «C» в scanf, который следует сразу. Так что, конечно, он вернется рано; Вы уже дали ему некоторую информацию, а именно «B» и «C».

Я предлагаю вам использовать другой метод ввода данных. Например, вы можете переключиться на строчные команды (возможно, используя fgets()), которые требуют от вас нажатия Enter на каждом шаге. Или вы можете использовать curses или любую другую платформенную функцию, необходимую для небуферизованного ввода, чтобы вы реагировали на нажатие клавиш, а не на буферизацию, предоставляемую stdio.

1 голос
/ 03 декабря 2009

Одна непосредственная вещь, которую я заметил.Ваш do while цикл проверяет val для "X", тогда как это значение фактически находится в menu.

Кроме этой возможности (val может быть "X" для начала, что может привести квыход из цикла независимо от введенного значения), ничто не выскакивает, поскольку, очевидно, вызывает преждевременный выход из функции или цикла.Я думаю, вам будет лучше опубликовать полную базу кода, поэтому мы не слишком много гадаем.

Обновление:

Не используйте следующее для домашней работы- вы почти наверняка потерпите неудачу из-за плагиата (поскольку ваши преподаватели, предполагая, что они не абсолютные дураки, будут искать работу, взятую с этих сайтов).

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

Это означает, что нет gets, вместо этого вам нужно использовать fgets, так как это может ограничить объем вводимой информации.Кроме того, я стараюсь избегать использования scanf и fscanf, поскольку любой сбой в этих функциях фактически оставляет указатель входного файла в неопределенном месте.

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

Для этого вы можете просмотреть следующий код:

#include <stdio.h>

#define FSPEC "file.txt"

// Skip to the end of the line. This is used in some
// places to ensure there's no characters left in the
// input buffer. It basically discards characters
// from that buffer until it reaches the end of a line.

static void skipLine (void) {
    char ch = ' ';
    while ((ch != '\n') && (ch != EOF))
        ch = getchar();
}

// Get a line of input from the user (with length checking).

static char *getLine (char *prompt, char *line, int sz) {
    // Output prompt, get line if available.
    // If no line available (EOF/error), output newline.

    printf ("%s", prompt);
    if (fgets (line, sz, stdin) == NULL) {
        printf ("\n");
        return NULL;
    }

    // If line was too long (no '\n' at end), throw away
    // rest of line and flag error.

    if (line[strlen (line) - 1] != '\n') {
        skipLine();
        return NULL;
    }

    // Otherwise line was complete, return it.

    return line;
}

// Output the menu and get a choice from the user.

static char doMenu (void) {
    char cmd[1+2]; // need space for char, '\n' and '\0'.

    // Output the menu.

    printf ("\n");

    printf ("\n");
    printf ("Main menu\n");
    printf ("---------\n");
    printf ("1. Input a line\n");
    printf ("2. Output the file\n");
    printf ("3. Clear the file\n");
    printf ("\n");
    printf ("x. Exit\n");
    printf ("\n");

    // Get the user input and return it.

    if (getLine ("Enter choice (1,2,3,x): ", cmd, sizeof(cmd)) == NULL)
        return '\n';

    printf ("\n");

    return cmd[0];
}

static void doOption1 (void) {
    FILE *fh;
    char *ln;
    char buff[15+2]; // need space for line, '\n' and '\0'.

    // Get and check line, add to file if okay.

    if ((ln = getLine ("Enter line: ", buff, sizeof(buff))) == NULL) {
        printf ("Bad input line\n");
    } else {
        fh = fopen (FSPEC, "a");
        if (fh != NULL) {
            fputs (ln, fh);
            fclose (fh);
        }
    }
}

static void doOption2 (void) {
    FILE *fh;
    int intch;

    // Output the file contents.

    printf ("=====\n");
    fh = fopen (FSPEC, "r");
    if (fh != NULL) {
        while ((intch = fgetc (fh)) != EOF)
            putchar (intch);
        fclose (fh);
    }
    printf ("=====\n");
}

static void doOption3 (void) {
    FILE *fh;

    // Clear the file.

    fh = fopen (FSPEC, "w");
    if (fh != NULL)
        fclose (fh);
}

// Main program basically just keeps asking the user for input
// until they indicate they're finished.

int main (void) {
    char menuItem;

    // Get asking for user input until exit is chosen.

    while ((menuItem = doMenu()) != 'x') {
        switch (menuItem) {
            case '1': doOption1(); break;
            case '2': doOption2(); break;
            case '3': doOption3(); break;
            default:  printf ("Invalid choice\n"); break;
        }
    }

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