Thread: File update with fseek and printf an arr of strutc.

  1. #1
    Registered User
    Join Date
    Jan 2012
    Posts
    29

    File update with fseek and printf an arr of strutc.

    Hello there! I have this code for my project

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <conio.h>
    
    int main()
    {
        int a=0,b=0,e=0,h=0,i=0,j=0,x=0;
        int hm,nb;
        char c,d;
    
        FILE *p;
        p=fopen("test.txt","a+b");
    
        struct store
        {
            char title[100];
            char author[50];
            char genre[25];
            char year[10];
            char pages[10];
            char price[10];
            int howmany;
     };
    
        store base[50];
        for(i=0;i<50;i++)
        {
            strcpy(base[i].title,"(null)");
            strcpy(base[i].author,"(null)");
            strcpy(base[i].genre,"(null)");
            strcpy(base[i].year,"(null)");
            strcpy(base[i].pages,"(null)");
            strcpy(base[i].price,"(null)");
            base[i].howmany=0;
        }
        fread(base,sizeof(store),50,p);
    
        do
        {
            printf("\tMENU\n");
            printf("\t1. Quick add book.\n"); /*READY*/
            printf("\t4. Inventory.\n");
            printf("\t5. Exit.\n"); /*READY*/
    
            char tmp[100];
            fgets(tmp,100,stdin);
            sscanf(tmp,"%c",&c);
    
            switch(c)
            {
                case '1': /*adds just one book - DONE*/
                    hm=0;
                    system("cls");
                    while(strcmp(base[e].title,"(null)")!=0)
                    {
                        e++;
                        if(e==50)
                            break;
                    }
                    if(strcmp(base[e].title,"(null)")==0)
                    {        
                        printf("What is the title of the book?\n");
                        fgets(base[e].title,sizeof(base[e].title),stdin);
                        for(j=0;j<50;j++)
                            for(x=0;x<50;x++)    
                                if(x!=j && strcmp(base[x].title,base[j].title)==0)
                                {
                                    if(strcmp(base[x].title,"(null)")==0)
                                        break;
                                    else if(strcmp(base[j].title,"(null)")==0)
                                        break;
                                    else
                                    {
                                    printf("This book is already in our data base! Press ENTER to continue.\n");
                                    getchar();
                                    strcpy(base[e].title,"(null)");
                                    base[j].howmany=base[j].howmany+1;
                                    hm=1;
                                    system("cls");
                                    break;
                                    }
                                }
                                else
                                {
                                }
                        if(hm==0)
                        {
                            printf("What is the author of the book?\n");
                            fgets(base[e].author,sizeof(base[e].author),stdin);
                            printf("What kind of genre is that?\n");
                            fgets(base[e].genre,sizeof(base[e].genre),stdin);
                            printf("What year the book was released?\n");
                            fgets(base[e].year,sizeof(base[e].year),stdin);
                            printf("How many pages does the book count?\n");
                            fgets(base[e].pages,sizeof(base[e].pages),stdin);
                            printf("What is the price?\n");
                            fgets(base[e].price,sizeof(base[e].price),stdin);
                            base[e].howmany=1;
                            printf("Book(s) added succesfully! Press ENTER to return to the menu.\n");    
                        }
                        else
                            break;
                    }
                    else
                    {
                        printf("Our database is full! Press ENTER to continue.\n");
                        getchar();
                        system("cls");
                    }                
                    getchar();
                    system("cls");
                    break;
    
        
                case '4': /*inventory*/
                    system("cls");
                    for(b=0;b<10;b++)
                        printf("Title: %sAuthor: %sGenre: %sYear: %sPages: %sPrice: %sQuantity:%d\n\n",base[b].title,base[b].author,base[b].genre,base[b].year,base[b].pages,base[b].price,base[b].howmany);
                    break;
                    
    
                case '5':
                    system("cls");
                    printf("Thank You! Press ENTER to leave");
                    getchar();
                    break;
    
                default:
                    system("cls");
                    printf("Error, press any key to back to the main menu");
                    getchar();
                    system("cls");
            }    
        }while(c!='5');
        fwrite(base,sizeof(store),50,p);
        fclose(p);
    And my problem is, my file is not updating. I mean, when I used Hexprobe I see changes in text file, but program cannot read them. I know I need to use fseek function, but I have no idea how. I did try all morning, but nothing happens, or all I get is rubish...

    And there is another question. When I printf my 'base'. I get sth like:

    Title: The Mist
    Author: S. King
    Genre: Horror
    Year: 1980
    Pages: 999
    Price: 39,99
    Quantity: 1

    but my purpose is to have it like this:
    The Mist S. King Horror 1980 999 39,99 1

    How can I do that?

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,793
    open file for reading
    read all
    close it
    open file for writing
    write all
    close it
    check the result
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    David J. Wheeler

  3. #3
    Registered User
    Join Date
    Nov 2011
    Posts
    52
    Here's a reference for fseek()
    fseek - C++ Reference

    use SEEK_SET with position 0 to put it at the beginning of the file.

    regarding the printf issue. You are storing the '\n' when you hit enter when entering the value that's why when you print the value it also prints the '\n'.

  4. #4
    Registered User
    Join Date
    Jan 2012
    Posts
    29
    Quote Originally Posted by vart View Post
    open file for reading
    read all
    close it
    open file for writing
    write all
    close it
    check the result
    The result is when I don't read it, program gets no data from file. But how does it help, or I misunderstood this simple task? .

    Quote Originally Posted by mnd22 View Post
    You are storing the '\n' when you hit enter when entering the value that's why when you print the value it also prints the '\n'.
    Yes, I didn't show it, but I'm aware of that. I tried to omit this with my brilliant idea
    Code:
    printf("%s\b",base[b].title")
    but obviously it didn't help.

  5. #5
    Registered User
    Join Date
    Nov 2011
    Posts
    52
    You are opening the file in a+b mode. When you save the changes it will append it at the end of the file not update the data. Try to do what vart said or open the file with "r+b" then fseek at position 0 to update the file. r+b will allow you to update the binary file on any position. a+b will always put new data at the end of the file.

  6. #6
    Registered User
    Join Date
    Jan 2012
    Posts
    29
    Quote Originally Posted by mnd22 View Post
    open the file with "r+b" then fseek at position 0 to update the file. r+b will allow you to update the binary file on any position.
    Shall fseek be before or after fread? I believe I did exactly what You said but I see no progress...

    Excuse me that, but I'm newbie with this...
    Last edited by blunt; 01-20-2012 at 02:25 PM.

  7. #7
    Registered User
    Join Date
    Nov 2011
    Posts
    52
    Quote Originally Posted by blunt View Post
    Shall fseek be before or after fread? I believe I did exactly what You said but I see no progress...

    Excuse me that, but I'm newbie with this...
    Yes after fread. Just before you do fwrite(). Post your updated code I am not sure how you did the changes.

  8. #8
    Registered User
    Join Date
    Jan 2012
    Posts
    29
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <conio.h>
     
    int main()
    {
        int a=0,b=0,e=0,h=0,i=0,j=0,x=0;
        int hm,nb;
        char c,d;
     
        FILE *p;
        p=fopen("test.txt","r+b");
     
        struct store
        {
            char title[100];
            char author[50];
            char genre[25];
            char year[10];
            char pages[10];
            char price[10];
            int howmany;
     };
     
        store base[50];
        for(i=0;i<50;i++)
        {
            strcpy(base[i].title,"(null)");
            strcpy(base[i].author,"(null)");
            strcpy(base[i].genre,"(null)");
            strcpy(base[i].year,"(null)");
            strcpy(base[i].pages,"(null)");
            strcpy(base[i].price,"(null)");
            base[i].howmany=0;
        }
        fread(base,sizeof(store),50,p);
     
        do
        {
            printf("\tMENU\n");
            printf("\t1. Quick add book.\n"); /*READY*/
            printf("\t4. Inventory.\n");
            printf("\t5. Exit.\n"); /*READY*/
     
            char tmp[100];
            fgets(tmp,100,stdin);
            sscanf(tmp,"%c",&c);
     
            switch(c)
            {
                case '1': /*adds just one book - DONE*/
                    hm=0;
                    system("cls");
                    while(strcmp(base[e].title,"(null)")!=0)
                    {
                        e++;
                        if(e==50)
                            break;
                    }
                    if(strcmp(base[e].title,"(null)")==0)
                    {        
                        printf("What is the title of the book?\n");
                        fgets(base[e].title,sizeof(base[e].title),stdin);
                        for(j=0;j<50;j++)
                            for(x=0;x<50;x++)    
                                if(x!=j && strcmp(base[x].title,base[j].title)==0)
                                {
                                    if(strcmp(base[x].title,"(null)")==0)
                                        break;
                                    else if(strcmp(base[j].title,"(null)")==0)
                                        break;
                                    else
                                    {
                                    printf("This book is already in our data base! Press ENTER to continue.\n");
                                    getchar();
                                    strcpy(base[e].title,"(null)");
                                    base[j].howmany=base[j].howmany+1;
                                    hm=1;
                                    system("cls");
                                    break;
                                    }
                                }
                                else
                                {
                                }
                        if(hm==0)
                        {
                            printf("What is the author of the book?\n");
                            fgets(base[e].author,sizeof(base[e].author),stdin);
                            printf("What kind of genre is that?\n");
                            fgets(base[e].genre,sizeof(base[e].genre),stdin);
                            printf("What year the book was released?\n");
                            fgets(base[e].year,sizeof(base[e].year),stdin);
                            printf("How many pages does the book count?\n");
                            fgets(base[e].pages,sizeof(base[e].pages),stdin);
                            printf("What is the price?\n");
                            fgets(base[e].price,sizeof(base[e].price),stdin);
                            base[e].howmany=1;
                            printf("Book(s) added succesfully! Press ENTER to return to the menu.\n");    
                        }
                        else
                            break;
                    }
                    else
                    {
                        printf("Our database is full! Press ENTER to continue.\n");
                        getchar();
                        system("cls");
                    }                
                    getchar();
                    system("cls");
                    break;
     
         
                case '4': /*inventory*/
                    system("cls");
                    for(b=0;b<10;b++)
                        printf("Title: %sAuthor: %sGenre: %sYear: %sPages: %sPrice: %sQuantity:%d\n\n",base[b].title,base[b].author,base[b].genre,base[b].year,base[b].pages,base[b].price,base[b].howmany);
                    break;
                     
     
                case '5':
                    system("cls");
                    printf("Thank You! Press ENTER to leave");
                    getchar();
                    break;
     
                default:
                    system("cls");
                    printf("Error, press any key to back to the main menu");
                    getchar();
                    system("cls");
            }    
        }while(c!='5');
    fseek(p,0,SEEK_SET);
        fwrite(base,sizeof(store),50,p);
        fclose(p);
    @edit: Ou, it works for now. But still not sure about solution. Feels so unsolid

    But what about second problem? Printing it?
    Last edited by blunt; 01-20-2012 at 04:23 PM.

  9. #9
    Registered User
    Join Date
    Dec 2011
    Posts
    795
    I commend you for using fgets(), and not scanf. Not sure if line 48 is really necessary though, there's probably a more elegant way to eat the '\n' without making a temp..

    However, you should put your struct array in the heap, not the stack. The reason being is that the struct alone takes up 209 bytes, it probably gets word-aligned up to 212, and you're generating fifty of them. That's 10.6 kb you're using of stack memory, which is generally a bad practice. The (surprisingly simple) solution, is to make your main struct a pointer, and call malloc() at the beginning, and free() at the end. The same can be done with the arrays inside, by changing them to char pointers and allocating/freeing them dynamically with the main struct.

    Every time someone deletes <conio.h>, someone saves a kitten. (seriously though, do it, conio is outdated and useless)

    Why do you have so many counter variables at the beginning? Not only are you zeroing them twice (once in the declaration and once in the loop), you can reuse one variable for all the counters, provided they're not nested. The only time you'll need multiple counters is for nested loops, which you have a couple (two for's inside a do-while). Also, the variables "h", "a", "nb", and "d" are unused (and named horribly).

    Lines 61-86 are really clunky, and there's probably a much better way to do it. Currently, you're doing 2500 iterations, and calling strcmp three times during each iteration. Using braces would really help the structure of the code, and might remove the reason for allocating 4 bytes for "hm", a seemingly magic-number repository that is only zero or one.

    Edit: I decided I'd paste it into GCC and try it out, turns out that forgetting the "struct" keyword creates tons of errors. Change "store base" into "struct store base".
    Last edited by memcpy; 01-20-2012 at 05:24 PM.

  10. #10
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    A better solution is to replace this:
    Code:
        struct store
        {
            char title[100];
            char author[50];
            char genre[25];
            char year[10];
            char pages[10];
            char price[10];
            int howmany;
     };
      
        store base[50];
        for(i=0;i<50;i++)
        {
            strcpy(base[i].title,"(null)");
            strcpy(base[i].author,"(null)");
            strcpy(base[i].genre,"(null)");
            strcpy(base[i].year,"(null)");
            strcpy(base[i].pages,"(null)");
            strcpy(base[i].price,"(null)");
            base[i].howmany=0;
        }
    With this:
    Code:
        struct store
        {
            char title[100];
            char author[50];
            char genre[25];
            char year[10];
            char pages[10];
            char price[10];
            int howmany;
     } base[50] = { { 0 } };
    Now you can get rid of all of those strcmp checks and simply do:
    Code:
    if( base[ x ].title[ 0 ] == 0 )
    {
        ... this is unused
    }
    Unless this is some kind of embedded system, I wouldn't worry about 10k of stack space in something so trivial.


    Quzah.
    Hope is the first step on the road to disappointment.

  11. #11
    Registered User
    Join Date
    Jan 2012
    Posts
    29
    There are unused variables because this is not a whole code, just 1/7.

    I'm aware that there is better way to do this, but my deadline is Monday, and with my C knowledge it would take a week to rewrite it. That's why my code has 900 lines, I could use some functions, could use a pointers, but I understand it only in theory.
    you're doing 2500 iterations
    Yea, that's right. I had an idea - didn't work, then another one - didn't work, then I connected both of them, it worked more or less, so I finally added some mayo and it's working - so I won't touch it 'cause I'll ruin it.

  12. #12
    Registered User
    Join Date
    May 2009
    Posts
    3,864
    Quote Originally Posted by memcpy View Post
    Edit: I decided I'd paste it into GCC and try it out, turns out that forgetting the "struct" keyword creates tons of errors. Change "store base" into "struct store base".
    Note: This may also be an indication that the Compiler is doing an "C++" compile instead of "C" compile. In C++, the struct keyword is optional.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  13. #13
    Registered User
    Join Date
    Jan 2012
    Posts
    29
    Is there any idea to print it nicely?

  14. #14
    Registered User
    Join Date
    Nov 2011
    Location
    Saratoga, California, USA
    Posts
    334
    To remove the newlines?

    Code:
    int chomp( char * str )
    {
        int n ;
    
        n = strlen(str) - 1 ;
    
        if( str[ n ] == '\n' )
        {
            str[ n ] = '\0' ;
            return 1 ;
        }
    
        return 0 ;
    }

  15. #15
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    void chomp( char * s )
    {
        s[ strcspn( s, "\n" ) ] = '\0';
    }

    Quzah.
    Hope is the first step on the road to disappointment.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File I/O: Offsetting file pointer (fp) using fseek
    By yesyesyes in forum C Programming
    Replies: 5
    Last Post: 03-21-2011, 05:33 PM
  2. Tailing a file, fseek help
    By drshmoo in forum C Programming
    Replies: 1
    Last Post: 03-18-2011, 10:43 AM
  3. Update a file in C
    By flyjason in forum C Programming
    Replies: 2
    Last Post: 06-06-2007, 03:43 PM
  4. c script help to read a file & update
    By indy in forum C Programming
    Replies: 8
    Last Post: 12-01-2003, 11:32 AM
  5. file index update error
    By daluu in forum C Programming
    Replies: 1
    Last Post: 04-28-2003, 02:47 AM

Tags for this Thread