C - scanf () против get () против fgets ()

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

Единственное жесткое правило заключается в том, что все предпосылки должны выполняться до запуска целевого рецепта.

Если между x, y и z нет зависимостей и нет параллельного выполнения, GNU make, похоже, запускает их в указанном вами порядке, но это не гарантируется в Docs.

34
задан Jonathan Leffler 10 July 2015 в 03:18
поделиться

5 ответов

Да, вы хотите избежать gets. fgets всегда будет читать новую строку, если буфер был достаточно велик, чтобы вместить ее (что дает вам знать, когда буфер был слишком мал и есть еще часть строки, ожидающая чтения). Если вам нужно что-то вроде fgets, которое не будет читать новую строку (теряя индикацию слишком маленького буфера), вы можете использовать fscanf с преобразованием scan-set, например: "%N[^\n]", где 'N' заменяется на размер буфера - 1.

Один простой (хотя и странный) способ удалить новую строку из буфера после чтения с помощью fgets: strtok(buffer, "\n"); Это не то, как strtok должен использоваться, но я использовал его так чаще, чем по назначению (чего я обычно избегаю).

19
ответ дан 27 November 2019 в 05:55
поделиться
  • Никогда не используйте получает . Он не предлагает защиты от уязвимости, связанной с переполнением буфера (то есть вы не можете сказать, насколько велик буфер, который вы ему передаете, поэтому он не может помешать пользователю ввести строку, превышающую размер буфера, и затереть память).

  • Избегайте использования scanf . При неосторожном использовании он может иметь те же проблемы переполнения буфера, что и , . Даже игнорируя это, у него есть другие проблемы, которые затрудняют правильное использование .

  • Обычно вместо этого следует использовать fgets , хотя иногда это неудобно (нужно удалить новую строку, заранее определить размер буфера, а затем выяснить, что делать со строками, которые слишком длинные - вы сохраняете прочитанную часть и отбрасываете лишнее , отбрасываете все, динамически увеличиваете буфер и пытаетесь снова и т. д.). Доступны некоторые нестандартные функции, которые выполняют это динамическое распределение за вас (например, getline в системах POSIX, общедоступная функция Чака Фалконера ggets функция). Обратите внимание, что ggets имеет семантику gets в том смысле, что он удаляет за вас завершающую новую строку.

27
ответ дан 27 November 2019 в 05:55
поделиться

никогда не используйте gets(), это может привести к непредсказуемым переполнениям. Если ваш строковый массив имеет размер 1000, а я введу 1001 символ, я могу переполнить буфер вашей программы.

3
ответ дан 27 November 2019 в 05:55
поделиться

Вы правы, что никогда не должны использовать получает . Если вы хотите использовать fgets , вы можете просто перезаписать новую строку.

char *result = fgets(str, sizeof(str), stdin);
char len = strlen(str);
if(result != NULL && str[len - 1] == '\n')
{
  str[len - 1] = '\0';
}
else
{
  // handle error
}

Это предполагает отсутствие встроенных NULL. Другой вариант - POSIX getline :

char *line = NULL;
size_t len = 0;
ssize_t count = getline(&line, &len, stdin);
if(count >= 1 && line[count - 1] == '\n')
{
  line[count - 1] = '\0';
}
else
{
  // Handle error
}

Преимущество getline в том, что он выполняет выделение и перераспределение за вас, обрабатывает возможные встроенные значения NULL и возвращает счетчик, поэтому вы этого не сделаете. приходится тратить время на strlen . Обратите внимание, что вы не можете использовать массив с getline . Указатель должен иметь значение NULL или быть свободным.

Я не знаю, в чем проблема с scanf .

4
ответ дан 27 November 2019 в 05:55
поделиться

Попробуйте использовать fgets () с этой модифицированной версией вашего CharToInt ():

int CharToInt(const char *s)
{
    int i, result, temp;

    result = 0;
    i = 0;

    while(*(s+i) != '\0')
    {
        if (isdigit(*(s+i)))
        {
            temp = *(s+i) & 15;
            result = (temp + result) * 10;
        }
        i++;
    }

    return result / 10;
}

It по существу проверяет введенные цифры и игнорирует все остальное. Он очень сырой, поэтому доработайте его и посолите по вкусу.

1
ответ дан 27 November 2019 в 05:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: