Strange behaviour of sscanf with string

2019-09-06 19:42发布

问题:

I've got a trouble with sscanf. To check it I made a simple file, so when I compile this:

#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);
}

I get right output:

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

But when I comment lines between empty comments sings, I get:

sscan: 0
a: (null)

Question 1: How can it be so?

And a little more: if I write char *a = NULL, I get:

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

Question 2: Why?

回答1:

You're copying a string to an uninitialised pointer (a). You need to allocate storage for it (with malloc), or declare an array.

Implementations can sometimes appear to work correctly when you don't allocate any storage. When you assign NULL to a, sscanf fails to store anything, and so you try to print a "string" with a NULL pointer (which printf prints as (null) ). On some systems, your program would simply crash.

There is a compiler/library extension that allows automatic allocation of strings, but obviously this is not portable and not all compilers support it.

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

You can pass an uninitialised pointer to the function, but note the &.



回答2:

You are passing uninitialized pointer to sscanf. change char *a; to char a[100] and it should work correctly.



回答3:

You are writing data to unallocated space. char *a; is only a pointer to random memory. After you try to put data in your "string" you invoke undefined behavior and anything could happen.



回答4:

Well, the only right thing in my case, as I think, would be this:

#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);
}

In common case string s can have a very large size, so it would be better not to allocate much memory, but allocate right so, as I need.

Case with "%as" doesn't work with my gcc (4.7.2).



标签: c scanf