使用fscanf扫描值或使用默认值(如果不存在值)

时间:2013-05-19 04:25:00

标签: c scanf

我有一个函数来读取具有以下格式的文本文件

 string int int
 string int int
 string int int

我想编写一个函数,将文本文件中的值分配给变量,但也会出现文本文件格式为

的情况。
string int
string int
string int

在这种情况下,我想将最后一个int变量的值设置为1.到目前为止,我的代码与第一个示例一起工作但是我有点不习惯让第二个场景工作:< / p>

void readFile(LinkedList *inList, char* file)
    {
    char tempName[30];
    int tempLoc, tempNum;

    FILE* f;
    f = fopen(file, "r");
    if(f==NULL) 
        {
        printf("Error: could not open file");
        }
    else
        {
        while (fscanf(f, "%s %d %d\n", tempName, &tempLoc, &tempNum) != EOF)
            {
            insertFirst (inList, tempName, tempLoc, tempNum);
            }
        }   
    }

1 个答案:

答案 0 :(得分:3)

在第二种情况下,fscanf将返回2而不是3.所以你可以像这样重写代码:

while (1) {
    int ret = fscanf(f, "%s %d %d\n", tempName, &tempLoc, &tempNum);
    if (ret == EOF) {
        break;
    }
    if (ret == 2) {
        tempNum = 1;
    } else if (ret != 3) {
        // line appear invalid, deal with the error
    }
    insertFirst (inList, tempName, tempLoc, tempNum);

}

更糟糕的方法是在调用fscanf之前将tempNum设置为1,并像上面一样检查EOF。但我认为上面的代码更清楚。

编辑:为了避免溢出,这会更好。代码表现更好,但写起来更难。就像上面一样,我没有为错误条件编写任何代码,但你肯定想要处理它们

char lineBuf[255];
while (fgets(lineBuf, sizeof(lineBuf), f) != NULL) {
    int spaceIdx, ret;
    const int len = strlen(lineBuf);
    if (len == (sizeof(lineBuf) - 1) {
         // line is too long - either your buf is too small and you should tell the user
         // that its input is bad
         // I recommend to treat this as an error
    }
    lineBuf[len - 1] = '\0'; // remove \n
    --len;  // update len, we've removed one character
    if (isspace(*lineBuf)) {
        // error, line should not start with a space
    }
    spaceIdx = strcspn(lineBuf, "\t ");
    if (spaceIdx == len) {
        // error, no space in this line
    }

    // Ok, we've found the space.  Deal with the rest.
    // Note that for this purpose, sscanf is a bit heavy handed (but makes the code
    // simpler). You could do it with strtol.
    // Also, the first space in the format string is important, so sscanf skips 
    // all the space at the beginning of the string.  If your format requires only
    // one space between fields, you can do sscanf(lineBuf + spaceIdx + 1, "%d %d"...

    ret = sscanf(lineBuf + spaceIdx, " %d %d", &tempLoc, &tempNum);
    if (0 == ret) {
        // error, no ints
    }
    else if (1 == ret) {
        tempNum = 1;
    }

    // at that point, you could copy the first part of lineBuf to tempName, but then
    // you have to deal with a potential overflow (and spend time on an useless copy),
    // so use lineBuf instead

    lineBuf[spaceIdx] = '\0';

    insertFirst (inList, lineBuf, tempLoc, tempNum);
}