sscanf отсутствует строка после совпадения% [^ -] s - PullRequest
0 голосов
/ 10 февраля 2019

У меня есть простая программа, использующая sscanf.Проблема, с которой я сталкиваюсь, заключается в том, что после сопоставления %[^-]s, sscanf кажется просто прекращает сопоставление.

Вот простой код, чтобы понять, что я имею в виду.Совпадение %s после %[^-]s %s полностью игнорируется.

ПРИМЕЧАНИЕ. Мне нужно %[^-]s, так как мне нужно, чтобы моя программа соответствовала обеим возможным строкам.

ПРИМЕЧАНИЕ 2: Iзнать, что код абсолютно небезопасен и т. д. Это всего лишь пример!

#include <stdio.h>

int main(void) {
    int matches;
    int num1, num2, num3, num4;
    char *s1[10];
    char *s2[10];
    char *s3[40];
    char *s4[50];
    char *s5[50];
    char *s6[50];
    char *s7[50];

    char fileTest[] = "29 0 8:4 / / rw,relatime shared:1 - ext4 /dev/sda4 rw,errors=remount-ro";
    // char fileTest[] = "160 48 179:56 /inte /var/oil/gaol/org.something.org/media/internal ro,nosuid,relatime - ext4 /dev/mmccc rw,data=ordered";

    matches = sscanf(fileTest, "%d %d %d:%d %s %s %[^-]s %s",
                     &num1, &num2, &num3, &num4, s1, s2, s3, s4);

    printf("matches: %d\n", matches);
    printf("num1: %d\n", num1);
    printf("num2: %d\n", num2);
    printf("num3: %d\n", num3);
    printf("num4: %d\n", num4);
    printf("s1: %s\n", s1);
    printf("s2: %s\n", s2);
    printf("s3: %s\n", s3);
    printf("s4: %s\n", s4);

    return 0;
}

Ответы [ 3 ]

0 голосов
/ 10 февраля 2019

Обратите внимание, что s после набора сканирования %[…] является литералом s, а не частью набора сканирования.В контексте, %[^-]s никогда не будет соответствовать s, поэтому любое последующее преобразование завершится неудачно.Часть %[^-] поглощает все, что не является чертой -s не является -, поэтому она разбивается вместе с пробелами и всем остальным), тогда s несовпал (потому что преобразование останавливается на - или конце строки), поэтому сканирование не проходит там, и окончательное %s никогда не совпало.

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

Существуют и другие серьезные проблемы с вашим кодом.В частности, char *s1[10]; должно быть char s1[10];, и аналогично для других массивов.Или вам нужно выполнить основные упражнения по выделению пространства для массивов, на которые можно указывать и т. Д. И, как вы, вероятно, знаете, преобразования %s%[^-]) не ограничивают входные данные.Используйте %9s или %49[^-] и т. Д. Для соответствующих размеров.См. Также Как предотвратить scanf() переполнение буфера в C?

0 голосов
/ 10 февраля 2019

В вашем коде есть несколько проблем:

  • sscanf формат для класса символов %[chars] или %[^chars], после 100].В вашем примере sscanf() попытается сопоставить s после третьей строки и потерпит неудачу, предотвращая преобразование последующих %s.

  • массивов назначения s1до s4 должно быть char массивов, а не массивов char *.

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

  • , поскольку %[^-] останавливается на - или конец входной строки, последняя строка, проанализированная %s, будет - или счетчик match будет отражать отсутствие разделителя -.Если вам нужны остальные входные данные, вы должны использовать %[^\n]

Вот исправленная версия:

#include <stdio.h>

int main(void) {
    int matches;
    int num1, num2, num3, num4;
    char s1[10], s2[10], s3[40], s4[50];

    char fileTest[] = "29 0 8:4 / / rw,relatime shared:1 - ext4 /dev/sda4 rw,errors=remount-ro";
    // char fileTest[] = "160 48 179:56 /inte /var/oil/gaol/org.something.org/media/internal ro,nosuid,relatime - ext4 /dev/mmccc rw,data=ordered";

    matches = sscanf(fileTest, "%d %d %d:%d %9s %9s %39[^-] - %49[^\n]",
                     &num1, &num2, &num3, &num4, s1, s2, s3, s4);

    printf("matches: %d\n", matches);
    printf("num1: %d\n", num1);
    printf("num2: %d\n", num2);
    printf("num3: %d\n", num3);
    printf("num4: %d\n", num4);
    printf("s1: %s\n", s1);
    printf("s2: %s\n", s2);
    printf("s3: %s\n", s3);
    printf("s4: %s\n", s4);

    return 0;
}

Выход:

matches: 8
num1: 29
num2: 0
num3: 8
num4: 4
s1: /
s2: /
s3: rw,relatime shared:1
s4: ext4 /dev/sda4 rw,errors=remount-ro
0 голосов
/ 10 февраля 2019

Спецификатор формата %[^-] соответствует всему, пока не встретится -;Таким образом, после сопоставления с этим следующий символ в буфере для проверки по строке формата будет - (если есть).Но если вы позволите этому шаблону следовать за s, то есть %[^-]s, тогда ничто больше не будет соответствовать, потому что - никогда не будет соответствовать требуемому s в строке формата.

...