В чем разница между scanf ("% s", & str) и scanf ("% s \ n", & str)? - PullRequest
3 голосов
/ 16 апреля 2020

Вход

На входе будет несколько строк, оканчивающихся строкой, содержащей один *. Эта последняя строка не должна быть обработана. Каждая из строк будет содержать либо Hajj, либо Umrah.

Выход

Для каждой строки ввода выведите либо Hajj-e-Akbar, либо Hajj-e-Asghar в отдельных строках без кавычек. Точный формат см. В примере.

Вот мой код для этой проблемы.

#include <stdio.h>

int main()
{
    char str[100];
    int i = 1;

    while (scanf("%s", &str))
    {
        if (str[0] == '*')
            break;
        else if (str[0] == 'H')
            printf("Case %d: Hajj-e-Akbar\n", i);
        else
            printf("Case %d: Hajj-e-Asghar\n", i);
        i++;
    }
}

Для ввода

Hajj
Umrah
*

Когда я дал этот вход в время программа выдает ожидаемый результат, печатая

Hajj
Case 1: Hajj-e-Akbar
Umrah
Case 2: Hajj-e-Asghar
*

Но после получения * в качестве ввода программа ожидает Enter. После нажатия Enter программа завершается. Но я хочу, чтобы моя программа завершала работу всякий раз, когда она получает * в качестве ввода, а не нажатием Enter. Пожалуйста, помогите мне здесь. Но это не мой вопрос. Мой вопрос для того же ввода -

Hajj
Umrah
*

Когда я беру ввод с помощью scanf("%s\n", &str). Программа не печатает вывод Case 1: Hajj-e-Akbar после первого ввода Hajj, но печатает вывод для первого ввода после получения второго ввода Umrah. Затем программа ожидает Enter для ввода *. Вывод выглядит так:

Hajj
Umrah
Case 1: Hajj-e-Akbar
*

Затем я нажимаю Enter, он печатает вывод Case 2: Hajj-e-Asghar для второго входа Umrah и затем ждет другого входа. Это выглядит как вывод после нажатия Enter.

Hajj
Umrah
Case 1: Hajj-e-Akbar
*
Case 2: Hajj-e-Asghar

Я не понимаю, как \n имеет значение в scanf.

Спасибо.

Извините, если я не могу правильно объяснить свой вопрос. Я новичок в программировании.

Ответы [ 2 ]

2 голосов
/ 16 апреля 2020

scanf считывает форматированный ввод, поэтому при использовании %s\n”, &str строка будет использована и сохранена в str, как и символ новой строки, который будет присутствовать в буфере при нажатии клавиши ввода, строка будет сохранена и символ новой строки будет отброшен.

Обратите внимание, что правильное использование: “%s\n”, str, str уже указатель, вы не должны использовать &.

Когда вы используете “%s”, &str символ новой строки останется в буфере и будет использован в следующем l oop, поэтому str будет сохранен в первой итерации, а "\n" будет сохранен в str в следующей итерации , только тогда вас снова попросят ввести данные на третьей итерации.

Для завершения, как указано в комментариях ниже, согласно определению scanf:

... любой отдельный символ пробела в строке формата потребляет все доступные последовательные символы пробела из входных данных (определяется как при вызове isspace в al oop ). Обратите внимание, что нет разницы между "\ n", "", "\ t \ t" или другими пробелами в строке формата.

Я бы также посоветовал вам ограничить размер строки, ожидаемый scanf, чтобы избежать переполнения контейнера, что-то вроде %99s для контейнера из 100 символов, как у вас, а также отметьте scanf return, в данном случае это должно быть = 1 для каждого цикла.

Чтобы сделать то, что вы хотите, я собираюсь получить символ из stdin без нажатия return, вам потребуется спецификация SO Метод c, вот небольшой пример для Windows с использованием библиотеки <conio.h> и getch():

#include <stdio.h>
#include <conio.h>

int main()
{
    int i = 1, c;

    while (1)
    {
        if ((c = getch()) == '*')
            return 0;
        else if (c == 'H')
            printf("Case %d: Hajj-e-Akbar\n", i);
        else
            printf("Case %d: Hajj-e-Asghar\n", i);
        i++;
    }
}

Для Linux одним из вариантов является также использование getch () из <ncurses.h> библиотеки, которую вам может понадобиться установить .

PS: Не волнуйтесь, ваш вопрос хорошо продуман, особенно если он занимает второе место на сайте.

1 голос
/ 16 апреля 2020

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

Вы должны проверить, возвращает ли scanf() 1, чтобы избежать бесконечно l oop когда он возвращает EOF в конце файла.

Обратите внимание также, что неверно передавать &str: str является массивом, передавая его как str будет эффективно передайте указатель на его первый элемент, что правильно.

Кроме того, вы должны указать scanf() максимальное количество символов, которое можно сохранить в массиве назначения, чтобы избежать неопределенного поведения при слишком длинном вводе. Поскольку массив определен с размером 100, строка формата должна быть "%99s", чтобы оставить место для нулевого терминатора.

Наконец, вам нужно нажать Enter после final * по 3 комбинированным причинам, каждая из которых вынуждает это поведение:

  • драйвер оконечного устройства по умолчанию является буферизованным строкой, поэтому ввод не доступен программе, пока вы не введете Enter .
  • стандартный поток ввода (stdin) по умолчанию буферизован строкой, поэтому он будет считывать данные из дескриптора системы до тех пор, пока не получит символ новой строки, и только после этого scanf() получить возможность увидеть первый символ введенной строки.
  • scanf("%s", str) будет сохранять свой входной поток до тех пор, пока не получит конец слова, символ пробела или конец файла, поэтому он не вернется когда вы набираете просто *.

Вот модифицированная версия:

#include <stdio.h>

int main() {
    char str[100];
    int i = 1;

    while (scanf("%99s", str) == 1 && str[0] != '*') {
        if (str[0] == 'H') {
            printf("Case %d: Hajj-e-Akbar\n", i);
        } else {
            printf("Case %d: Hajj-e-Asghar\n", i);
        }
        i++;
    }
    return 0;
}
...