2013-03-14 3 views
0

У меня проблема с sscanf. Чтобы проверить это, я сделал простой файл, поэтому, когда я компилирую это:Странное поведение sscanf со строкой

#include <stdio.h> 
main(){ 
    char *a; 
    /* */ 
    char *s = "GET /something HTTP/1.1\r\n"; 
    printf("sscanf: %d\n", sscanf(s, "GET %s HTTP", a)); 
    printf("a: %s\n", a); 
    /* */ 
    printf("sscan: %d\n", sscanf("GET /more HTTP/1.1\r\n", "GET %s HTTP", a)); 
    printf("a: %s\n", a); 
} 

Я получаю правильный вывод:

sscanf: 1 
a: /something 
sscan: 1 
a: /more 

Но когда я комментирую линии между пустыми комментариями поёт, я получаю:

sscan: 0 
a: (null) 

Вопрос 1: Как это может быть так?

И еще немного: если я пишу char *a = NULL, я получаю:

sscanf: 0 
a: (null) 
sscan: 0 
a: (null) 

Вопрос 2: Почему?

+2

Вы не выделили память для 'a', поэтому' sscanf' является неопределенным поведением. Почему он притворяется, что работает в первом случае, может быть определен только путем исследования выхода компилятора. –

+0

Некоторые объяснения: сначала у меня проблема (Q2), проблема (Q1) появилась, когда я проверил (Q2). Эта проблема не позволяет мне использовать опции '-Werror -Wall' без' #pragma GCC диагностики ... ' –

+0

@ DanielFischer, спасибо, я плохо прочитал человека! –

ответ

0

Вы записываете данные в нераспределенное пространство. char *a; - это только указатель на случайную память. После того, как вы попытаетесь поместить данные в свою «строку», вы вызываете неопределенное поведение, и все может произойти.

2

Вы передаёте неинициализированный указатель на sscanf. измените char *a; на char a[100] и он должен работать правильно.

+0

'man sscanf' говорит, что существует модификатор«% as », который динамически выделяет память, но он не работает. Предораспределение памяти - это плохо, потому что она должна быть такой же, как буфер, в которой я ищу подстроку. –

5

Вы копируете строку неинициализированному указателю (a). Вам необходимо выделить хранилище для него (с malloc) или объявить массив.

Реализации иногда могут работать правильно, если вы не выделяете какое-либо хранилище. Когда вы назначаете NULL a, sscanf ничего не хранит, поэтому вы пытаетесь напечатать «строку» с помощью указателя NULL (который printf печатает как (null)). В некоторых системах ваша программа просто сработает.

Существует расширение для компилятора/библиотеки, которое позволяет автоматически выделять строки, но, очевидно, это не переносимо, и не все компиляторы поддерживают его.

char *a; 
scanf("%ms", &a;) // allocates storage for a 

Вы можете передать неиницализированный указатель на функцию, но обратите внимание на &.

+0

Почему это не на C99std? Мне кажется чрезвычайно полезным для меня (особенно для получения информации по сети). Каково падение этого? – zigo

0

Ну, единственно правильным в моем случае, как мне кажется, было бы это:

#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 

main(){ 
    char *s = strdup("GET /something HTTP/1.1\r\n"); 
    char *a, *e, *ans; 
    char *end = s + strlen(s); 
    a = strstr(s, "GET"); 
    if(!a) return -1; 
    a += 4; 
    if(a >= end) return -1; 
    e = strstr(a, "HTTP/1.1"); 
    if(!e) return -1; 
    *(--e) = 0; 
    ans = strdup(a); 
    printf("ans: %s\n", ans); 
} 

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

Корпус с "% as" не работает с моим gcc (4.7.2).

+1

Вместо этого вы можете использовать 'm' - я привел пример в свой ответ. – teppic

+0

Это не сработало. Теперь я попробую: действительно, если вы скажете 'sscanf (« GET more here »,« GET% ms », &x);' он работает! Но в первый раз я забыл амперсанд и получил неправильный результат. –

+0

Да - это потому, что 'sscanf 'необходимо изменить указатель на новую память, поэтому ему нужно' & '. – teppic

Смежные вопросы