Thread: File modification problem

  1. #1
    Registered User
    Join Date
    Jan 2008
    Posts
    5

    File modification problem

    Ohk the program is that there are 2 files customer and transaction. The customer file holds information about customer and their balance. The transaction file holds information about the current deposits or withdrawals made by the customer. The user needs to make a program to modify the existing fields in the customer file based on the trasactions in the transactions file. Now the code for the program is :-
    Code:
    /*program to read transactions file and modify the customer file accordingly*/
    #include<stdio.h>
    main()
    {
        FILE *fc,*ft;
        struct customer
        {
            int accno;
            char name[40];
            float balance;
        };
        struct transaction
        {
            int accno;
            char type;
            float amount;
        };
        struct customer c;
        struct transaction t;
        int slen = sizeof(struct customer);
        fc = fopen("customer.txt","r+");
        ft = fopen("transaction.txt","r");
        if(fc == NULL)
        {
            printf("Cannot open target file");
            fclose(ft);
            exit(1);
        }
        if(ft == NULL)
        {
            printf("Cannot open transactions file");
            fclose(fc);
            exit(2);
        }
        /*code to modify customer file based on the information in the transactions file*/
        while(fscanf(ft,"%d %c %f",&t.accno,&t.type,&t.amount) != EOF)
        {
            fseek(fc,0,0);
            while(fscanf(fc,"%d %s %f",&c.accno,c.name,&c.balance) != EOF)
            {
                if(c.accno == t.accno)
                {
                    if(t.type == 'D')
                        c.balance += t.amount;
                    else
                        c.balance -= t.amount;
                    fseek(fc,-slen,SEEK_CUR);
                    fprintf(fc,"%d %s %.3f\n",c.accno,c.name,c.balance);
                    break;
                }
            }
        }
        fclose(fc);
        fclose(ft);
    }
    Now the problem is that in the customer file i have saved 2 values : -
    1 rahul 300.000000
    2 priyanka 400.000000


    and in the trasactions file i have saved 2 values
    1 W 299.000000
    2 D 400.000000

    My ideal output should be
    1 rahul 1.000
    2 priyanka 800.000

    But the actual output come out to
    1 rahul 300.000000
    2 priyanka 400.000000
    1 rahul 1.000
    2 priyanka 800.000


    I think i've used the logic for fseek correctly but obviously theres some problem there. It should replace the values but its just appending the result at the end. If i remove the fseek command, it does not print anything. I know its a bad habit to not try to debug ur own code, but i've racked my brains over this for too long. I just want a hint as to where am going wrong. I'll try to figure out the actual solution myself. But i just want to know if theres something wrong with my syntax for fseek
    Last edited by Salem; 09-12-2010 at 12:36 AM. Reason: Added [code][/code] tags - learn to use them yourself

  2. #2
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    You have taken a mis-step, here.

    Don't think "change the file". Think "change the fields" in one record. The records will not have the same size in bytes, so scrap fseek().

    accno is your key, so simply read in the file until you find that key, using fread(), and when found, change the fields appropriately. Use sizeof(yourStruct), instead of calculating the right size by hand. There may be a bit of padding in each record.

    This may seem like a slow way to do things, but it's not as slow as you think. Modern HD's will cache a large part (or all), of the file, with one read, anyway.

    Welcome to the forum Led, and remember to use code tags around your program. (In the advanced editing window, highlight your code, and click on the # icon at the top of the window).
    Last edited by Adak; 09-12-2010 at 02:26 AM.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    You're using printf/scanf on the files, so this isn't going to work.
    fseek(fc,-slen,SEEK_CUR);

    To be able to use fseek means you need fixed length records. Printing a name using %s will be variable length.

    Typically, you use fread() and fwrite() to do this
    Eg
    fread( &cust, sizeof(cust), 1, fc )

    > fseek(fc,0,0);
    Why didn't you use SEEK_SET?

    Also, you should have a
    fflush(fc);
    following the write to the file, before you try to read it again.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Jan 2008
    Posts
    5
    Theres a problem i've been having with fread and fwrite. While making the customer file for example, i used the following code

    Code:
    #include<stdio.h>
    main()
    {
        FILE *fp;
        char another;
        another = 'Y';
        struct customer
        {
            int accno;
            char name[40];
            float balance;
        };
        struct customer c;
        fp = fopen("customer.dat","wb");
        if(fp == NULL)
        {
            printf("Cannot open file");
            fclose(fp);
            exit(1);
        }
        while(another == 'Y')
        {
            printf("Enter customer detials\n");
            scanf("%d %s %f",&c.accno,c.name,&c.balance);
            fwrite(&c,sizeof(c),1,fp);
    
            printf("Add another?\n");
            fflush(stdin);
            scanf("%c",&another);
        }
        fclose(fp);
        return 0;
    }
    I'm new to programming, and i don't know where am going wrong here. The book i've been referring to for C has exactly the same syntax. When i run the program it executes properly. I give input as
    1 rahul 200

    But when i try to open the file or even when i run a program to view the contents of the file the output shows
     rahul @ ÿ" 8ÿ" Äÿ" ÕŒñuÓdßìþÿÿÿ HC

    its just reading and printing garbage values for some reason. FYI Am referring to Let us C by yashwant kanetkar. And am using code blocks with gnucc compiler. But even visual c++ gives me the same error.

  5. #5
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Don't let the garbage deter you - this is the right way to go, and quite a thing of elegance when you see it working right.

    I know it's frustrating - but hang in there. You're close. I'm putting your code into good old Turbo C and looking at it, just now.

    Back in a bit.

    Code:
    #include<stdio.h>
    main()
    {
        FILE *fp;
        char another;
        int i;
        struct customer
        {
            int accno;
            char name[40];
            float balance;
        };
        struct customer c;
        another = 'Y';
    
        fp = fopen("customer.dat","wb");
        if(fp == NULL)
        {
            printf("Cannot open file");
            fclose(fp);
            exit(1);
        }
        while(another == 'Y')
        {
            printf("Enter customer details\n");
            scanf("%d %s %f",&c.accno,c.name,&c.balance);
            fwrite(&c,sizeof(c),1,fp);
    
            printf("Add another?\n");
            //fflush(stdin); this has been deprecated, for
            //input streams. (use for output streams only)
            //replace with:
            i=getchar();
            scanf("%c",&another);
            i=getchar();  //removes the newline left by scanf();
        }
        fclose(fp);
        
        //end of writing data, start of reading data
        
        fp = fopen("customer.dat","rb");
        if(fp == NULL)
        {
            printf("Cannot open file for reading");
            fclose(fp);
            exit(1);
        }
        another = 'Y';
        while(another == 'Y')
        {
            printf("Enter customer detials\n");
            //scanf("%d %s %f",&c.accno,c.name,&c.balance);
            fread(&c,sizeof(c),1, fp);
    
            //fwrite(&c,sizeof(c),1,stdout); //shows the "gobbledy-gook".
            printf("\n\n");
            printf("\n  Number: %d", c.accno);
            printf("\n    Name: %s", c.name);
            printf("\n Balance: %.2f\n", c.balance);
    
            printf("Read another record?\n");
            
            
            scanf("%c",&another);
            i=getchar();  //removes the newline left by scanf();
        }
        fclose(fp);
        printf("\n\n\t\t\t    press enter when ready");
        i=getchar(); ++i;
        return 0;
    }
    Made some changes to accommodate TC. Now shows the file contents in readable form.
    Last edited by Adak; 09-12-2010 at 03:11 AM.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > //fflush(stdin); this has been deprecated, for
    > //input streams. (use for output streams only)
    > //replace with:
    You can't deprecate what was never valid to begin with.

    You really ought to try this using fgets(), then all that "getchar() to remove the \n" stuff goes away. Which would be a good thing, because your current approach is pretty much broken anyway.

    How?
    Well if the user types in say "yes\n" rather than "y\n", then this happens
    - y is consumed by the scanf(%c)
    - e is consumed by your getchar
    - the code loops, and the scanf(%d) is wondering WTF "s\n" is supposed to mean.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    fflush() for input streams was and is still listed, in the help topics for Turbo C.

    My understanding is that they worked for TC, in DOS, but do not work in the NT kernel of Windows (all Windows since Windows 2000). I have not conducted any comprehensive tests on that, however.

    fgets() is a far superior input method than scanf(), no doubt.

  8. #8
    Registered User
    Join Date
    Jan 2008
    Posts
    5
    am using code blocks with gnucc compiler on win 7 and fflush() works fine

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > fflush() for input streams was and is still listed, in the help topics for Turbo C.
    You should try reading the standard once in a while, rather than trotting out the same old "well my compiler does ... and it works for me" line.

    > I have not conducted any comprehensive tests on that, however.
    There is no need to test it. If you just read the standard and understand that flushing input streams is a broken idea, then you can just stop caring that the foo compiler does it, and the bar compiler doesn't.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Quote Originally Posted by led1090 View Post
    am using code blocks with gnucc compiler on win 7 and fflush() works fine
    fflush() on the output streams should always work. The problem has been fflush() with the input streams - especially stdin (the keyboard, generally).

    The standard is overdue, of course, but the problem is, it's a moving target that the compiler makers have not been too anxious to follow.

    Some have extensions that preceed the standard, others have no intentions of implementing certain parts of the standard.

    All hail the standard! For whatever it's worth.

  11. #11
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    WTF are you smoking?
    C89 is well over 20 years old - what exactly are you waiting for?

    If you're pinning your hopes that C0X will suddenly allow flushing input streams, then excuse me while I ROFLMAO.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  12. #12
    Registered User
    Join Date
    Jan 2008
    Posts
    5

    Unhappy

    Ohk more problem i got the files customer and transaction working properly with fread and fwrite but when i compile the operations file which is supposed to modify records in customer some problems occur.


    Code:
    #include<stdio.h>
    main()
    {
        FILE *fp,*fs;
        struct customer
        {
            int accno;
            char name[40];
            float balance;
        };
        struct transaction
        {
            int accno;
            char type;
            float amount;
        };
        struct customer c;
        struct transaction t;
        fp = fopen("customer.dat","rb+");
        fs = fopen("transaction.dat","rb");
        if(fp == NULL)
        {
            printf("Cannot open customer file");
            fclose(fs);
            exit(1);
        }
        if(fs == NULL)
        {
            printf("Cannot topen transaction file");
            fclose(fs);
            exit(2);
        }
        while(fread(&t,sizeof(t),1,fs) == 1)
        {
            fseek(fp,0,SEEK_SET);
            while(fread(&c,sizeof(c),1,fp) == 1)
            {
                if(c.accno == t.accno)
                {
                    if(t.type == 'D')
                        c.accno += t.amount;
                    else
                        c.accno -= t.amount;
                    fseek(fp,-sizeof(c),SEEK_CUR);
                    fwrite(&c,sizeof(c),1,fp);
                }
            }
        }
        fclose(fp);
        fclose(fs);
    }
    the input given in customer file is
    1 rahul 200

    the input given in transactions file is
    1 D 200

    the output i get from operations file is
    201 rahul 200
    0 0.000000
    0 0.000000
    0 0.000000
    0 0.000000
    0 0.000000
    0 0.000000
    0 0.000000
    0 0.000000
    0 0.000000

    This does not keep on looping. It eventually terminates. If i comment out both the fseek statements, output is
    1 rahul 200

    It does not print the value at the end as it shud if i comment out the fseek commands. This can only mean that for some reason fwrite is not working. I just don't understand why.

  13. #13
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    I use this format when I want to reposition a file pointer:

    Code:
    fseek   Repositions the file pointer of a stream.
    
     Syntax:
       int fseek(FILE *stream, long offset, int whence);
    
     Prototype in:
     stdio.h
    
     Remarks:
    fseek sets the file pointer associated with stream to a new position that is
    offset bytes from the file location given by whence.
    
    For text mode streams, offset should be 0 or a value returned by ftell.
    
    whence must be one of the values 0, 1, or 2, which represent three symbolic
    constants (defined in stdio.h) as follows:
    
       whence         ³ File location
     ===============================Í
       SEEK_SET   (0) ³ File beginning
       SEEK_CUR   (1) ³ Current file pointer position
       SEEK_END   (2) ³ End-of-file
    
    fseek discards any character pushed back using ungetc.
    
    fseek is used with stream I/O. For file handle I/O, use lseek.
    
    After fseek, the next operation on an update file can be either input or
    output.
    
     Return Value:
    fseek returns 0 if the pointer is successfully moved. It returns a nonzero
    on failure.
    
    fseek can return a zero, indicating that the pointer has been moved
    successfully, when in fact it has not been. This is because DOS, which
    actually resets the pointer, does not verify the setting.
    
    fseek returns an error code only on an unopened file or device.
    
     Portability:
    fseek is available on all UNIX systems and is defined in ANSI C.
    
     See Also:
      fgetpos      fsetpos    lseek     setbuf
      fopen        ftell      rewind    tell
    
     Example:
     #include <stdio.h>
    
     long filesize(FILE *stream);
    
     int main(void)
     {
        FILE *stream;
    
        stream = fopen("MYFILE.TXT", "w+");
        fprintf(stream, "This is a test");
        printf("Filesize of MYFILE.TXT is %ld bytes\n", filesize(stream));
        fclose(stream);
        return 0;
     }
    
     long filesize(FILE *stream)
     {
        long curpos, length;
    
        curpos = ftell(stream);
        fseek(stream, 0L, SEEK_END);
        length = ftell(stream);
        fseek(stream, curpos, SEEK_SET);
        return length;
     }
    The above is from Borland Turbo C, so it might be "old fashioned", I don't know. It works for me.

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    For an update file, you need to use fflush() between writing and reading.

    And it wouldn't do any harm either to throw in a bit of error checking as well, to make sure you're not doing something dumb before announcing to the world "it doesn't work".
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  15. #15
    Registered User
    Join Date
    Jan 2008
    Posts
    5
    thanks you guys for your help. Nailed it

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Subtle(?) File I/O Problem
    By cecomp64 in forum C Programming
    Replies: 9
    Last Post: 07-16-2008, 11:39 AM
  2. Can we have vector of vector?
    By ketu1 in forum C++ Programming
    Replies: 24
    Last Post: 01-03-2008, 05:02 AM
  3. gcc link external library
    By spank in forum C Programming
    Replies: 6
    Last Post: 08-08-2007, 03:44 PM
  4. File I/O problem
    By 81N4RY_DR460N in forum C++ Programming
    Replies: 12
    Last Post: 09-03-2005, 12:14 PM
  5. Encryption program
    By zeiffelz in forum C Programming
    Replies: 1
    Last Post: 06-15-2005, 03:39 AM