【问题标题】:All content of file get duplicated while modifying a specific entry修改特定条目时文件的所有内容都会重复
【发布时间】:2016-06-29 10:19:54
【问题描述】:

此代码从二进制文件读取/写入数据。这里modify() 将接受用户的输入,在文件中搜索它。如果找到,将提示用户提供新条目,旧条目将被替换。

问题是,在modify() fwrite() 之后,如果我在break while 循环中,那么一切都会好起来的,但如果我不这样做,那么条目仍然会被修改,但内容也会随之修改的文件会被复制,为什么会这样?

与开头一样,文件中没有重复的条目。 所以我期望的是,即使我不使用break,循环也应该继续并最终在读取整个文件时终止。在这里,if(strcmp(e.name,user)==0) 仅对一个条目为真,因此控件应在此 if 块中只输入一次。那么这些条目是如何重复的呢?

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>

    void add(FILE *);
    void list(FILE *);
    void modify(FILE *);

    struct emp
    {
        char name[20];
        int id;
        float sal;
    }e;

    void add(FILE *f)
    {
        char *p=NULL;

        printf("\nEnter name id sal\n");
        scanf(" %s %d %f", e.name,&e.id,&e.sal);

        fseek(f,0,SEEK_END);
        if((fwrite(&e,sizeof(struct emp),1,f))==1)
        {
            printf("\nAdded Successfully\n");
        }
        else
        {
            printf("\nError wrting to file in ADD func\n");
        }
    }

    void list(FILE *f)
    {
        rewind(f);
        while(fread(&e,sizeof(struct emp),1,f)>0)
        {
            printf("\nRead %s %d %f\n",e.name,e.id,e.sal);
        }
    }

    void modify(FILE *f)
    {
        char user[20];
        char *p=NULL;

        printf("\nEnter name to modify\n");
        scanf(" %s", user);

        rewind(f);

        while(fread(&e,sizeof(struct emp),1,f)==1)
        {
            //printf("\n        --------------- %s %d %f\n",e.name,e.id,e.sal);
            if(strcmp(e.name,user)==0)
            {
                //fseek(f,-sizeof(struct emp),SEEK_CUR);
                printf("\nEnter new name id salary\n");
                scanf(" %s %d %f", e.name,&e.id,&e.sal);

                fseek(f,-sizeof(struct emp),SEEK_CUR);
                if(fwrite(&e,sizeof(struct emp),1,f)==1)
                {
                    printf("\nModified successfull!!\n");
                    //break;
                }
                else
                {
                    printf("\nError while modifying\n");
                }
            }
            else
            {
                printf("\n\nstring not matched\n\n");
            }
        }

    }

    int main()
    {
        char val='T';
        FILE *fp=NULL;

        if((fp=fopen("database.dat","rb+"))==NULL)
        {
            if((fp=fopen("database.dat","wb+"))==NULL)
            {
                printf("\nError opening file in wb+ mode\n");
                exit(0);
            }
        }

        do
        {
            printf("\nEnter a to add, l to list, d to delete, m to modify and e to exit\n");
            scanf(" %c", &val);

            switch(val)
            {
                case 'a':
                        add(fp);
                        break;
                case 'l':
                        list(fp);
                        break;
                case 'm':
                        modify(fp);
                        break;
                case 'd':
    //                    del(fp);
                        break;
                case 'e':
                        fclose(fp);
                        exit(0);
                        break;
                default:
                        printf("\nInvalid Input\n");
                        break;
            }

        }
        while(1);

    }

【问题讨论】:

  • 一旦你调用了未定义的行为,任何事情都可能发生。 fflush(stdin) 确实会调用未定义的行为。在此处询问之前,请删除所有已知的未定义行为案例。由于您似乎并不真正了解未定义行为的含义,因此请了解一下!
  • @Olaf 删除了所有出现的fflush(stdin)。请立即检查。

标签: c file structure


【解决方案1】:

我认为这是fread()fwrite() 之间的问题。 使用 fwrite() 修改 emp 后,继续 while 循环而不使用 fseek()。 其实之前你用fseek() 回去就OK了。 现在你必须放置另一个不会移动的 fseek(),像这样:

fseek(f, 0, SEEK_CUR);

现在您可以删除中断,您的 Modify() 函数将如下所示:

void modify(FILE *f)
{
    char user[20];
    printf("\nEnter name to modify\n");
    scanf("%s",user);
    fflush(stdin);
    rewind(f);

    while(fread(&e,sizeof(struct emp),1,f)==1)
    {
        if(strcmp(e.name,user)==0)
        {
            printf("\nEnter new name id salary\n");
            scanf("%s %d %f",e.name,&e.id,&e.sal);
            fflush(stdin);

            fseek(f,-sizeof(struct emp),SEEK_CUR);
            if(fwrite(&e,sizeof(struct emp),1,f)==1)
            {
                printf("\nModified successfull!!\n");
                //break; //This can be removed

                fseek(f, 0, SEEK_CUR); //Place this here
            }
            else
            {
                printf("\nError while modifying\n");
            }
        }
        else
        {
            printf("\n\nstring not matched\n\n");
        }
    }
}

【讨论】:

  • 是的,这行得通,但是,为什么我们需要这样做fseek(f, 0, SEEK_CUR);,因为在写入fwrite 之后,文件指针会自己指向下一个条目?所以循环应该自己从下一个条目继续?
  • 参见Standard 7.21.5.3p7:“......输出/输入不应直接跟在输入/输出后面,而没有对 fflush 函数的介入调用......”
  • @pmg "如果没有对fflush 函数或文件定位函数的干预调用,则输出不应直接跟在输入后面(fseek, fsetpos, or rewind)" 因此,如果我们使用fflush(),那么按照这个它将通过stdout完成?
  • 如果您使用fflush(),您必须将它用于您用于freads 和fwrites 的FILE *。如果该文件是输入文件,或者是输入了最后一个操作的输入/输出文件,fflush() 会导致未定义行为(据我所知,Microsoft Windows library 除外)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-31
  • 1970-01-01
  • 2015-11-12
  • 1970-01-01
相关资源
最近更新 更多