在C中遇到fscanf()的麻烦

时间:2016-08-17 08:16:20

标签: c linux scanf

我正在阅读和写入(追加模式)到文件中,发生了一些非常奇怪的事情。我第一次运行它时,它会完美地读取文件,并完美地附加新行。第二次,它读取文件卡住了。

我做错了什么?

阅读:

fptr = fopen("log.txt", "r");
fseek(fptr, -70, SEEK_END); 
for(i = 0; i < 11; i++)
{
    fscanf(fptr, "%d, ", llast + i);
    printf("%d ", llast[i]);
}

/* read the last review */    
for(i = 0; i < 11; i++)
{
    fscanf(fptr, "%d, ", last + i);
    printf("%d ", last[i]);
}

fclose(fptr);

追加:

fptr = fopen("log.txt", "a");
for(i = 0; i < 11; i++)
{
    fprintf(fptr, "%d, ", *(new + i));
}
fprintf(fptr, "\n");
fclose(fptr); 

最后两行的log.txt文件包含:

7, 4, 0, 10, 2, 8, 9, 5, 6, 3, 1, 
3, 7, 5, 6, 9, 2, 4, 10, 0, 1, 8, 

完整代码:

#include <stdio.h>
#include <stdlib.h> /* for the rand function */

int main()
{
int last[11] = {0};
int llast[11] = {0};
int new1[11] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
int i = 0, j = 0;
int rev = 0;
int flag = 0;
int big_flag = 0;
FILE *fptr;

printf("\nThe last review:\n");
PrintRev();
printf("\n\n");

/* open the log file of the reviews, and load the last two into arrays */
fptr = fopen("log.txt", "r");

/* read the review before the last review*/
fseek(fptr, -70, SEEK_END); 

for(i = 0; i < 11; i++)
{
    fscanf(fptr, "%d, ", llast + i);
    printf("%d ", llast[i]);
}

/* read the last review */    
for(i = 0; i < 11; i++)
{
    fscanf(fptr, "%d, ", last + i);
    printf("%d ", last[i]);
}

fclose(fptr);

/* create a new arrangement of reviewing */

/* the big flag is used for the extreme case when the first 10 reviewers are assigned
   but a problem occurs in the last remaining option for the last reviewer -
   so instead of running into a dead end of endless-loop, if there is a problem,
   we start over again ... */
while(!big_flag)
{
    for(i = 0; i < 10; i++)
    {
        flag = 0;
        /* the small flag is used to make sure the first 10 reviewers follow the rules */
        while(!flag)
        {
            rev = (rand() % 11);
            if((rev != i) && /* you can't review yourself */
               (rev != last[i]) &&  /* you can't review the person you did last time */
               (rev != llast[i]) && /* let's try without the last-last time */
               (rev != (i - 1)) && (rev != (i + 1)) && /* you can't review your neighbour */
               (new1[rev] != i)) /* you can't review the person reviewing you */
            {
                flag = 1;                
                /* a reviewer can't review more than one person... so we check if he wasn't
                   chosen before */
                for(j = 0; j < i; j++)
                {
                    if(rev == new1[j])
                    {
                        flag = 0;
                    }
                }
            }
        }
        new1[i] = rev;
    }

    /* find the only remaining id of reviewer */
    rev = 55; /* sum of 0,1, ... 10 */
    for(i = 0; i < 10; i++)
    {
        rev -= new1[i];
    }
    /* check if the remaining id is valid */ 
    if((rev != i) && 
       (rev != last[i]) &&  
       (rev != llast[i]) && /* let's try without the last-last time */
       (rev != (i - 1)) && 
       (new1[rev] != i))
    /* if so, appoint it, and raise the big flag to exit the loop */
    {
        new1[10] = rev;
        big_flag = 1;
    } 
}

/* append the new arrangement to file */
fptr = fopen("log.txt", "a");
for(i = 0; i < 11; i++)
{
    fprintf(fptr, "%d, ", *(new1 + i));
}

fclose(fptr); 




return 0;
}

1 个答案:

答案 0 :(得分:0)

您的代码中至少存在一个问题。你说log.txt包含行,并且你在最后添加了一行,但你的代码永远不会输出一个'\n',所以你永远不会写EOL标记。正如你所说的那样,使用Linux,磁盘上的行确实是单个字符'\n',但是你的代码在Windows "\r\n" = &GT;换句话说,现在的代码不可移植。

但如果您只想在Unix系统上运行,只需在写入11个值后添加一个新行:

/* append the new arrangement to file */
fptr = fopen("log.txt", "a");
for(i = 0; i < 11; i++)
{
    fprintf(fptr, "%d, ", *(new1 + i));
}
fputc('\n', fptr);
fclose(fptr); 

我可以运行5次,它确实添加了5行(正好35个字符......)

要小心: 在这里,你实际上是处理文本文件,好像它是一个大小为35的记录的二进制文件。这是不可移植的,因为行的结尾不同,但是由于另一个原因它是危险的:as as它是一个文本文件,可以用文本编辑器打开,比如vi。如果有人打开文件并且无意中在最后两行之一的末尾添加了一些空格,您会期望什么?记录长度不会超过35个字符,您将读取错误的值。并且由于您未能测试任何输入函数的结果(既不是open也不是fscanf),并且您没有测试您的读取值是0到10,您的程序可能会崩溃而没有任何有用的消息。

TL / DR:为所有open和fscanf调用添加测试,并控制每行包含0到10之间的所有值