Nongreedy fscanf и проверка на препълването на буфера в c

Търся fscanf да идентифицира кога се случи потенциално препълване и не мога да си обясня как най-добре да го направя.

Например за файл, съдържащ низа

**a**bb**cccc**

I do a

char str[10];
while (fscanf(inputf, "*%10[^*]*", str) != EOF) {

}

защото ми е гарантирано, че това, което е между ** и **, обикновено е по-малко от 10. Но понякога може да получа

**a**bb**cccc*

(без последното *) или дори потенциално препълване на буфера.

Обмислях да използвам

while (fscanf(inputf, "*%10[^*]", str) != EOF) {

}

(без последното *) или даже

while (fscanf(inputf, "*%10s*", str) != EOF) {

}

но това ще върне целия низ. Опитах се да видя дали мога да проверя за наличие или липса на *, но не мога да накарам това да работи. Виждал съм също внедряване на fgets, но предпочитам да не го усложнявам. Някакви идеи?


person Rio    schedule 12.04.2011    source източник


Отговори (2)


Не ми е ясно какво точно искаш. Това ли е да прескочите произволен брой звезди и след това да прочетете до 9 символа без звезди в буфер? Ако е така, опитайте това:

void read_field(FILE *fin, char buf[10])
{
    int c;
    char *ptr = buf;
    while ((c = getc(fin)) == '*')
        /*continue*/;
    while (c != '*' && c != EOF && ptr < buf+9)
    {
        *ptr++ = c;
        c = getc(fin);
    }
    *ptr = '\0';
    /* skip to next star here? */
}

Ще забележите, че не използвам fscanf. Това е така, защото fscanf почти винаги създава повече проблеми, отколкото си струва. Горното е по-скоро типично, но мога да бъда уверен, че прави това, което описах.

person zwol    schedule 12.04.2011
comment
Хм, но се надявах да използвам fscanf... идеята е да се прочетат всички знаци в рамките на звездите или да се изведе грешка, ако е над 10 знака. - person Rio; 12.04.2011
comment
Добре, тогава в този случай просто поставете if (ptr == buf+9) throw_error() след втория цикъл while. Наистина, повярвайте ни, не искате fscanf. - person zwol; 12.04.2011

Докато fscanf() изглежда е проектиран като анализатор на изрази с общо предназначение, малко програмисти разчитат на тази способност. Вместо това използвайте fgets(), за да прочетете текстов ред и след това използвайте анализатор по ваш избор или дизайн, за да разчлените текстовия буфер.

Използването на пълните функции на fgets() е странно при различни реализации и не винаги осигурява пълна функционалност, нито дори да ги внедри правилно.

person wallyk    schedule 12.04.2011
comment
Мисля, че имахте предвид fscanf там, където написахте fgets? - person zwol; 12.04.2011
comment
@Zack: Не, не fscanf(), който понякога работи добре, но често не работи или причинява толкова много проблеми, че ви се иска да не сте го използвали. fgets() е много по-управляема входно-изходна функция: тя чете, докато буферът се запълни или се срещне край на реда. Допълнителна логика следва неговия призив да направи каквато и да е фантастична обработка, която е необходима. - person wallyk; 12.04.2011
comment
Добре, но вие казвате, че fgets изглежда е проектиран като анализатор на изрази с общо предназначение, което няма никакъв смисъл (но има, ако сте искали да напишете fscanf) - person zwol; 12.04.2011
comment
@Zack: благодаря. Коригирах го. (Може би сега ще получа няколко гласа?) - person wallyk; 12.04.2011