C: fscanf и размер символа / строки - PullRequest
0 голосов
/ 25 сентября 2010

Я анализирую текстовый (css) файл, используя fscanf. Основная цель проста; Я хочу вытащить все, что соответствует этому шаблону:

@ import "some / file /where.css";

Так что я использую fscanf, говорю ему читать и отбрасывать все до символа «@», а затем хранить все, пока не достигнет «;» персонаж. Вот функция, которая делает это:

char* readDelimitedSectionAsChar(FILE *file)
{
char buffer[4096];

int charsRead;
do
{
    fscanf(file, "%*[^@] %[^;]", buffer, &charsRead);

} while(charsRead == 4095);

char *ptr = buffer;
return ptr;
}

Я создал буфер, который должен содержать 4095 символов, насколько я понимаю. Тем не менее, я обнаружил, что это не так. Если у меня есть файл, который содержит соответствующую длинную строку, например:

@ import "некоторые / действительно / действительно / действительно / длинные / file / path / to / a / file";

Это усекается до 31 символа, используя буфер char [4096]. (Если я использую printf для проверки значения буфера, я обнаружу, что строка обрезана.)

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

В идеале, я бы хотел иметь возможность устанавливать буфер настолько большим, насколько это необходимо, чтобы он был «на лету», то есть fscanf просто создает буфер, достаточно большой для хранения строки. Можно ли это сделать? (Мне известен флаг% as для GNU, но это приложение Mac для OS 10.5 / 10.6, и я не уверен, будет ли это работать на этой платформе.)

Ответы [ 2 ]

2 голосов
/ 25 сентября 2010

Основная проблема, с которой вы столкнулись, заключается в том, что вы возвращаете указатель на локальный буфер в стеке, который болтается (и перезаписывается при следующем вызове).У вас также есть потенциальное переполнение буфера.Вы упомянули опцию 'a', которая очень бы помогла, но, к сожалению, это расширение GNU, которое обычно недоступно.

Во-вторых, у вас есть эта дополнительная опция для scanf, &charsRead, которая никогда не будетзаписано как нет % для него в строке формата.Таким образом, charsRead всегда будет случайным мусором - это означает, что ваш цикл будет (возможно) только один раз или (редко) цикл навсегда.Попробуйте что-то вроде

char* readDelimitedSectionAsChar(FILE *file)
{
    char buffer[4096], term[2] = "", *rv = 0;
    int len = 0;

    fscanf(file, "%*[^@]");
    while (term[0] != ';' && !feof(file)) {
        if (fscanf(file, "%4095[^;]%1[;]", buffer, term) > 0) {
            int read = strlen(buffer);
            rv = rv ? realloc(rv, len+read+1) : malloc(read+1);
            strcpy(rv+len, buffer);
            len += read;
        }
    }
    return rv;
}

Это все еще не работает в том смысле, что он будет плохо себя вести, если у вас закончится память (что может легко случиться, если вы загрузите в него огромный искаженный файл с @ в начале и нет;),

1 голос
/ 25 сентября 2010

Ваш буфер является локальным для функции.Вы назначаете указатель на него, но когда вызывающий обращается к указателю, буфер больше не существует.Может случиться что угодно.

Так что не делайте этого.

И scanf, вероятно, не подходит для работы.Я бы попробовал getc или fgets вместо.

char *readDelimitedSectionAsChar(char *buf, size_t n, char firstChar, char lastChar, FILE *f);
...