sscanf扫描特定大小的字符串

时间:2013-07-20 05:53:52

标签: c overflow printf scanf

我想在下面的代码中只扫描“sizeof(out)”字符串'out'。 'input'字符串可能不仅仅是out,因此out可能会产生溢出。格式字符串也可以使用sprintf / snprintf完成。

#include<stdio.h>
#define BUFSZ 4

int main()
{
  char input[16]="#123 abcdefg";
  int k;
  char out[BUFSZ];

  sscanf(input,"#%d %s",&k,out);
  /* Something like %ns where n is the size of out in above line */ 

  printf("%d\n",k);
  printf("%s\n",out);
  return 0;
}

3 个答案:

答案 0 :(得分:2)

#include<stdio.h>

#define BUFSZ 4

#define _S(x) #x
#define S(x) _S(x)

int main(void){
    char input[16]="#123 abcdefg";
    int k;
    char out[BUFSZ+1];

    sscanf(input,"#%d %" S(BUFSZ) "s",&k,out);//field size -1 for End Of String(\0)

    printf("%d\n",k);
    printf("%s\n",out);
    return 0;
}

答案 1 :(得分:0)

您需要创建另一个字符串,用作sscanf的格式字符串。这允许您将字符串大小(BUFSZ)插入格式字符串。

  char format_str[20];

  sprintf(format_str, "#%%d %%%ds", BUFSZ - 1);
  sscanf(input,format_str,&k,out);

答案 2 :(得分:0)

我对上面的解释进行了一些扩展,并提供了一些可执行的解释和一些测试用例,以便您查看验证选项。

#include<stdio.h>
#define BUFSZ 4

void PrintLine() { printf("---------------------------\n"); }

int MyIntegerScan(const char* input, int * integer, char * outbuf, size_t outbufSize)
{
    char format_str[20];
    sprintf(format_str, "%s%d%s", "#%d %n%", outbufSize -1 ,"s%n%*s%n");
    //"#%d %n%4s%n%*[^]%n"
    // ^----------------'#'   Character
    //    ^-------------' '   Any ammoutn of whitespace
    //   ^--------------%d    Decimal
    //        ^---------%4s   String Limited to 4 charcters, leave space for terminating zero
    //      ^---^-----^-%n    how many characters were read
    //             ^----%*[^] match anything without storing it

    int check0 = 0, check1 = 0, check2 = 0;

    printf("input: '%s'\n", input);
    *integer = 0;
    *outbuf = 0;

    int count = sscanf(input, format_str, integer, &check0, outbuf, &check1, &check2);

    switch (count)
    {
        case 0: printf("did not find number and string\n"); break;
        case 1: printf("did not find string\n"); break;
        case 2: printf("found both\n"); break;
        default: printf("unexpected error during scanf\n"); break;
    }

    if (check1 < check2)
        printf("unmatched rest: '%s'\n", input + check1);

    if (check1 == check2 && count == 2) 
        printf("length exactly as expected\n");

    if (check1 == check2 && count != 2)
        printf("did not fully match\n");

    if ((check1 - check0) < (outbufSize - 1) && count >= 2)
        printf("length shorter than expected\n");

    printf("matched: '%d' '%s'\n", *integer, outbuf);
    PrintLine();
    return 0;
}

int main()
{
    char out[BUFSZ];
    int k;

    //I want to have only "sizeof(out)" string 'out' to be scanned in the below code. 
    PrintLine();
    MyIntegerScan("#123 abc", &k, out, BUFSZ); //Happy Path
    MyIntegerScan("#123      abc", &k, out, BUFSZ); //A lot of whitespace
    MyIntegerScan("#123 a", &k, out, BUFSZ); //Input Very Short
    MyIntegerScan("#123 a noise", &k, out, BUFSZ); //Input Very Short Followed by noise
    MyIntegerScan("#123 abcdefg", &k, out, BUFSZ); //Input Too Long
    MyIntegerScan("#123", &k, out, BUFSZ); //Missing Text
    MyIntegerScan("# asdf", &k, out, BUFSZ); //Missing Number

    return 0;
}