C++ 使用sscanf c+检查格式并获取数字+;

C++ 使用sscanf c+检查格式并获取数字+;,c++,scanf,C++,Scanf,我需要检查一个字符数组以获得一种特定的简单格式,并同时获取其中两个数字的值。消息格式为:开始号码结束。我所能想到的就是: int x,y; if ( sscanf(buffer, "START %d %d END", &x, &y) != 2) return false; ... ... ... return true; 但这当然成功了,即使结局完全不同,因为数字是获得的。最好的方法是什么?谢谢你的建议。在检查了C标准之后,我很惊讶没有便携式的方法来检测这一点 在Li

我需要检查一个字符数组以获得一种特定的简单格式,并同时获取其中两个数字的值。消息格式为:开始号码结束。我所能想到的就是:

int x,y;
if ( sscanf(buffer, "START %d %d END", &x, &y) != 2) 
    return false;
...
...
...
return true;

但这当然成功了,即使结局完全不同,因为数字是获得的。最好的方法是什么?谢谢你的建议。

在检查了C标准之后,我很惊讶没有便携式的方法来检测这一点

在Linux上设置
errno
,您也可以使用
ferror
。在Windows上也设置了
errno
,但MSDN没有提到
ferror


您可以为一个凌乱但可移植的解决方案执行此操作:

int x,y;
char d;
if ( sscanf(buffer, "START %d %d EN%c", &x, &y, &d) != 3 || 'D' != d)
    return false;
试一试


我总是觉得使用sscanf()和类似的函数很麻烦。尽管其他解决方案更加优雅,但我更喜欢基于strtok()的更简单、更易于维护的代码。这里有一个小程序可供试验:

#include <cstdio>
#include <cstring>

int main()
{
    char buf[250];

    const char* delimiters=" \n";

    while(fgets(buf,250,stdin)!=nullptr){
        // fgets() reads the newline...
        printf("%s",buf);
        // Tokenize the buffer using 'delimiters'.  The nullptr will re-use the same buffer.
        char* pBegin = strtok(buf,delimiters);
        char* pNumb1 = strtok(nullptr,delimiters);
        char* pNumb2 = strtok(nullptr,delimiters);
        char* pEnd   = strtok(nullptr,delimiters);
        // Protect our strcmp from a nullptr(missing data) and do some validity tests.
        if((pEnd!=nullptr)&&(strcmp(pBegin,"BEGIN")==0)&&(strcmp(pEnd,"END")==0)){
            printf("  Begin = '%s'\n",pBegin); 
            printf("  Numb1 = '%s'\n",pNumb1); 
            printf("  Numb2 = '%s'\n",pNumb2); 
            printf("  End   = '%s'\n",pEnd); 
        }else{
            printf("  Error!\n");
        }
    }
}
这就是输出

BEGIN 106 635 END
  Begin = 'BEGIN'
  Numb1 = '106'
  Numb2 = '635'
  End   = 'END'
BEGIN 107 636 END
  Begin = 'BEGIN'
  Numb1 = '107'
  Numb2 = '636'
  End   = 'END'
BEGaN 108 637 ENDING
  Error!
BeGIN 115 644 End
  Error!
BEGIN 116 645 END
  Begin = 'BEGIN'
  Numb1 = '116'
  Numb2 = '645'
  End   = 'END'
BEGIN 117 646 END of it all
  Begin = 'BEGIN'
  Numb1 = '117'
  Numb2 = '646'
  End   = 'END'
BEgIN 128 657 END
  Error!
BEGIN 129 658 END
  Begin = 'BEGIN'
  Numb1 = '129'
  Numb2 = '658'
  End   = 'END'
BEGIN 130 659 Finish
  Error!
131 660 END
  Error!
BEGIN 662 END
  Error!
BEGIN 136 665 
  Error!
BEGIN 136 
  Error!
BEGIN 
  Error!

  Error!

看起来你把缓冲区的内容和字符串“START%d%d END”弄混了。sscanf需要一个包含您的字符串的缓冲区和一个包含格式数据的第二个字符串,即
sscanf(“开始9 10结束”,%s%d%d%s),buff1,&x,&y,buff2)
。您想做什么?使用格式化字符串“START%d%d”调用sscanf,如果一切正常,则使用格式化字符串“%s”调用sscanf,并将结果与“END”进行比较。@auburg,格式数据是
“START%d%d END”
,即字符串必须包含这些普通字符。在scanf格式中使用%s是危险的,应始终避免使用,如果使用%5s和%3s,您的建议就可以了。@user121270,请参阅上面的注释,%s是危险的,如果您使用%3s并传递指向至少4字节数组的指针,您的建议就可以了。
ferror
sscanf
无关,因为它不从文件流读取。@JonathanWakely很抱歉,我正在阅读
fscanf
sscanf
的文档。您的解决方案因
缓冲区而失败。
按住START-END我已经保证结束后不会有任何内容,因此这个解决方案对我来说非常有效。
BEGIN 106 635 END
BEGIN 107 636 END
BEGaN 108 637 ENDING
BeGIN 115 644 End
BEGIN 116 645 END
BEGIN 117 646 END of it all
BEgIN 128 657 END
BEGIN 129 658 END
BEGIN 130 659 Finish
131 660 END
BEGIN 662 END
BEGIN 136 665 
BEGIN 136 
BEGIN 
BEGIN 106 635 END
  Begin = 'BEGIN'
  Numb1 = '106'
  Numb2 = '635'
  End   = 'END'
BEGIN 107 636 END
  Begin = 'BEGIN'
  Numb1 = '107'
  Numb2 = '636'
  End   = 'END'
BEGaN 108 637 ENDING
  Error!
BeGIN 115 644 End
  Error!
BEGIN 116 645 END
  Begin = 'BEGIN'
  Numb1 = '116'
  Numb2 = '645'
  End   = 'END'
BEGIN 117 646 END of it all
  Begin = 'BEGIN'
  Numb1 = '117'
  Numb2 = '646'
  End   = 'END'
BEgIN 128 657 END
  Error!
BEGIN 129 658 END
  Begin = 'BEGIN'
  Numb1 = '129'
  Numb2 = '658'
  End   = 'END'
BEGIN 130 659 Finish
  Error!
131 660 END
  Error!
BEGIN 662 END
  Error!
BEGIN 136 665 
  Error!
BEGIN 136 
  Error!
BEGIN 
  Error!

  Error!