【问题标题】:sscanf() returns part of previous lines datasscanf() 返回前几行数据的一部分
【发布时间】:2016-01-29 00:39:30
【问题描述】:

给定一个 4 行的文本文件:以逗号 (,) 作为分隔符。我通过使用 fgets 抓取每一行并将 ISBN (978-xxxxxxxxxx) 与用户提供的 ISBN (978-xxxxxxxxxx) 来定位特定的 ISBN。这工作正常。

即使 fgets() 到文件的最后一行。它仍然返回正确的信息。但是,当我试图将字符串的每个元素过滤到其受人尊敬的结构成员中以通过套接字发送时。最后一个元素返回所有正确的内容,直到最后 4 个元素/字段。除了文件的最后一行之外,不会出现此错误。

我认为这是一个 EOF 错误,但是我并不精通 sscanf() 来理解为什么会这样。

如果我要打印出 linebuf,它会返回正确的(未解析的)行。 但是,如果我打印出所有数据。它返回第三行数据的一部分。具体来说,版本份数可用份数

9780132126953,Andrew Tanenbaum & David Wetherall,Computer Networks,5,2011,Prentice-Hall,5,2
9780123745408,Michael Donahoo & Kenneth Calvert,TCP/IP Sockets in C,2,2009,Morgan Kaufman,3,0
9780133354690,William Stallings,Cryptography and Network Security,6,2014,Prentice-Hall,3,3
9780072467505,Yale Patt & Sanjay Patel,Introduction to Computing Systems from bits & gates to C & beyond 2,2004,McGraw-Hill,1,0

我的代码:

while (fgets(linebuf, 1024, file) != NULL) {
    sscanf(linebuf, "%[^,], %[^,], %[^,], %u, %u, %[^,], %u, %u\n", 
        bufferISBN, bufferAuthor, bufferTitle, 
        &bufferEdition, &bufferYear, bufferPublisher, 
        &bufferInventory, &bufferAvailable
    );

    if (strcmp(temp->isbn, bufferISBN) == 0) { // found correct line, add data to struct
        mssg.respType = Okay; // enum
        mssg.requestID = temp->requestID;
        strcpy(mssg.isbn, bufferISBN); // needs fixing
        strcpy(mssg.authors, bufferAuthor);
        strcpy(mssg.title, bufferTitle);
        strcpy(mssg.publisher, bufferPublisher);
        mssg.edition = bufferEdition;
        mssg.year = bufferYear;
        mssg.inventory = bufferInventory;                          
        mssg.available = bufferAvailable;   
    }

注意 sscanf() 的格式,我也不确定这是否正确:

"%[^,], %[^,], %[^,], %u, %u, %[^,], %u, %u\n"

我也知道我正在使用大量的 buffer 变量。

编辑:当我限制标题的长度时。它返回正常。这是为什么呢?

【问题讨论】:

  • 你真的应该检查 sscanf 的返回值
  • 我有,我现在面临的问题是当我通过 bufferISBN 到 mssg.isbn 的 strcpy() 时。 ISBN+标题被存储。但是,如果我打印出 bufferISBN,它只会返回 ISBN

标签: c fgets scanf


【解决方案1】:

有时换行符会从文本文件的最后一行中删除。要检查,请执行od -t x1 <filename>,最后一个字符应为0a

如果不是,您可以使用文本编辑器清理文件并添加换行符。

或者,您可以稍微更改代码来处理此问题:

while (fgets(linebuf, 1024, file) != NULL) {
    char *cp = strchr(linebuf, '\n');
    if (cp != NULL)
        *cp = 0;
    sscanf(linebuf, "%[^,], %[^,], %[^,], %u, %u, %[^,], %u, %u",

【讨论】:

    【解决方案2】:

    在检查返回值之前不要使用sscanf()的结果

    if (8 != sscanf(linebuf, "%[^,], %[^,], %[^,], %u, %u, %[^,], %u, %u\n", 
        bufferISBN, bufferAuthor, bufferTitle, 
        &bufferEdition, &bufferYear, bufferPublisher, 
        &bufferInventory, &bufferAvailable
        )) Handle_Error();
    

    在这种情况下,返回值不受最后一个"%u" 之后扫描的内容的影响。为确保按预期扫描所有内容,请使用 "%n" 保存扫描的 char 数量(如果达到该格式说明符)。

    int n = 0;
    sscanf(linebuf, "%[^,], %[^,], %[^,], %u, %u, %[^,], %u, %u %n", 
        bufferISBN, bufferAuthor, bufferTitle, 
        &bufferEdition, &bufferYear, bufferPublisher, 
        &bufferInventory, &bufferAvailable,
        &n);
    if (n == 0) Handle_Scan_Incomplete();
    if (linebuf[n] != '\0') Handle_Scan_Extra();
    

    请注意,'\n'' ' 作为格式指令执行相同的操作:扫描 0 个或更多空白。

    注意:非"%c","%n","%[]" 之前的空格通常不需要,因为其他说明符会占用前导空格。可以使用:

    "%[^,], %[^,], %[^,],%u,%u, %[^,],%u,%u %n"
    

    为了统一起见,建议在开始和宽度限制处留一个空格(我刚刚做了bufferISBN

    char bufferISBN[14];
    " %13[^,], %[^,], %[^,],%u,%u, %[^,],%u,%u %n"
    

    【讨论】:

    • 我修改了很多代码,但是 bufferISBN 接收 ISBN 和作者。 '在 SSCANF(解析)之后:9780123745408,Michael Donahoo 和 Kenneth Calvert,C 语言中的 TCP/IP 套接字,2009 年 2 月,Morgan Kaufman,3, 0' 它缓冲的内容ISBN 存储:9780132126953Andrew Tanenbaum 和 David Wetherall
    • 怀疑你的代码没有像这个答案char bufferISBN[14]; " %13[^,],...那样纠正宽度限制。所以 1) 检查需要的 char 数组大小,2) 为格式添加宽度限制 3) 报告 sscanf() 的返回值
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 2010-10-25
    • 2011-01-26
    • 1970-01-01
    相关资源
    最近更新 更多