Программирование на C: Как использовать sscanf с разделителем ':'? - PullRequest
0 голосов
/ 12 февраля 2012

Я пытался извлечь часы, секунды и минуты из введенного текста, используя sscanf.После выполнения функции sscanf только переменная s, которая содержит секунды, имеет правильное значение.h и m, в которых есть часы и минуты, содержат только нули.Пожалуйста, предложите внести изменения в мой код ниже.

     char text[20];
     if (fgets(text, sizeof text, stdin)!= NULL){
         char* newline = strchr(text, '\n');
         if (newline != NULL){
             *newline = '\0';
         }
     }
     uint8_t s = 0;
     uint8_t m = 0;
     uint8_t h = 0;
     sscanf(text, "%02i:%02i:%02i",&h,&m,&s);

Обратите внимание, в тексте отладчика правильные значения.

Ответы [ 2 ]

3 голосов
/ 12 февраля 2012

Эта программа:

#include <stdio.h>

int main(void)
{
    const char hhmmss[] = "10:32:54";
    int hh, mm, ss;
    if (sscanf(hhmmss, "%i:%i:%i", &hh, &mm, &ss) != 3)
        printf("Failed to scan 3 values from '%s'\n", hhmmss);
    else
        printf("From <<%s>> hh = %d, mm = %d, ss = %d\n", hhmmss, hh, mm, ss);
    return 0;
}

дает такой вывод:

From <<10:32:54>> hh = 10, mm = 32, ss = 54

Преобразования %02i также должны работать, но цифры несколько лишние.


Измененный вопрос показывает, что переменные имеют тип uint8_t, и в этом случае вы должны использовать правильные спецификаторы преобразования из <inttypes.h>:

#include <stdio.h>
#include <inttypes.h>

int main(void)
{
    const char hhmmss[] = "10:32:54";
    uint8_t s;
    uint8_t m;
    uint8_t h;

    if (sscanf(hhmmss, "%02" SCNi8 ":%02" SCNi8 ":%02" SCNi8, &h, &m, &s) != 3)
        printf("Failed to scan 3 values from '%s'\n", hhmmss);
    else
        printf("From <<%s>> h = %d, m = %d, s = %d\n", hhmmss, h, m, s);
    return 0;
}

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

2 голосов
/ 12 февраля 2012

@ Ответ Джонатана Леффлера совершенно верный, но ...

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

  • Если вам нужно прочитать отдельные символы, используйте getchar.
  • Если вы хотите прочитать строку, scanf имеет все проблемы переполнения буфера gets.
  • Если вы хотите читать числа, синтаксический анализ scanf подвержен ошибкам и сложен в использовании. Вместо этого используйте strtoul и strtod.
  • Если у вас более сложный ввод, все только хуже.

Что делать?

  • Чтение собственного ввода с использованием чего-то лучшего, чем gets, то есть без проблем с переполнением буфера. Не пытайтесь совмещать ввод байтов с их интерпретацией.
  • Используйте комбинацию strcspn, strspn, stroul и strtod в сочетании с некоторым пользовательским кодом для сканирования ввода.

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

...