sscanf()返回前一行数据的一部分

时间:2015-10-29 01:45:29

标签: c fgets scanf

给出4行的文本文件:用逗号(,)作为分隔符分隔。我通过使用fgets获取每一行并将ISBN(978-xxxxxxxxxx)与用户提供的ISBN进行比较来查找特定的ISBN。这很好用。

即使fgets()到文件的最后一行。它仍然返回正确的信息。但是,因为我试图将字符串的每个元素过滤到其受尊重的struct成员中以通过套接字发送。最后一个元素返回所有正确的内容,直到最后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"

我也知道我正在使用的大量缓冲区变量。

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

2 个答案:

答案 0 :(得分:0)

有时,换行符不在文本文件的最后一行。要检查,请执行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",

答案 1 :(得分:0)

在检查返回值

之前,请勿使用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"