Thread: reusing a 'deleted' record

  1. #1
    Codus Conjectus spongefreddie's Avatar
    Join Date
    Sep 2010
    Location
    USA
    Posts
    86

    reusing a 'deleted' record

    Okay, I thought I'd never have to post so much code to get help, and I'm more stubborn than most, but after spending all my waking time over the course of about 36 hours total, I'm about ready to stick a gun to my head... so, I'm asking if anyone can tell me what I'm doing wrong in this program.

    I finally figured out the fwrite() obstacle, thanks to some advice from Adak, but what I can't figure out is:

    1) How to properly 'hide' deleted records from the user.
    2) How to reuse a 'deleted' record (without the user manually dictating structure array element).
    3) How to make both numbers 1 + 2 work successfully together.
    4) How to not skip the next file when deleting the current one.

    I'm sick of this and going to bed in defeat. Anyone who can tell me where my mistakes are is Yoda, as far as I'm concerned.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAXTITL 40
    #define MAXAUTL 40
    #define MAXBKS 10
    
    struct book {
      char title[MAXTITL];
      char author[MAXAUTL];
      float value;
    };
    
    int main(void)
    {
      struct book libry[MAXBKS];
      char ch;
      int count = 0;
      int index, filecount;
      FILE * pbooks;
      int size = sizeof(struct book);  // this was to avoid using 'sizeof(struct book)'
                                       // in every fread() and fwrite()
    
      for (index = 0; index < MAXBKS; index++)    // this is to make all empty files equal to 'deleted' status
        libry[index].title[0] = '%';              // thus searchable in an 'if' statement
    
      if ((pbooks = fopen("book.txt", "r+b")) == NULL)  // this was changed from "a+b"
      {
        fputs("Can't open book.txt\n", stderr);
        exit(EXIT_FAILURE);
      }
    
      rewind(pbooks);    // goes to beginning of file - a precaution to avoid unexpected results
    
      while (count < MAXBKS && fread(&libry[count], size, 1, pbooks) == 1)
      {
        if (count == 0)
          puts("Current contents of book.txt:\n");    // this insures that the contents of the file are
                                                      // printed at the start of the program
        count++;         // finds record count in file at start of program
      }
    
      filecount = count;
    
      rewind(pbooks);    // these two statements reset the file pointer
      count = 0;         // and the record count to the beginning
    
      while (count < filecount)
      {
        if (libry[count].title[0] == '%')           // makes 'deleted' records invisible to user -
          count++;                                  // explanation of why I used '%' is below
    
        printf("%s by %s: $%.2f\n", libry[count].title, libry[count].author, libry[count].value);
    
        printf("Would you like to modify (m) or delete (d) this record? [Enter] for 'no'.\n");
    
        if ((ch = getchar()) == 'd')
        {
          libry[count].title[0] = '%';              // assigns '%' if record is 'deleted' by user
          while (getchar() != '\n')        // clears input line
            continue;
        }
    
        if (ch == 'm')
        {
          while (getchar() != '\n')        // clears input line
            continue;
    
          puts("Please make changes to book title.");
          puts("Press [Enter] at the start of a line to stop.\n");
    
          gets(libry[count].title);
          puts("Now enter the author.");
          gets(libry[count].author);
          puts("Now enter the value.");
          scanf("%f", &libry[count].value);
        }
    
        count++;
      }
    
      filecount = count;   // IMPORTANT - must assign this for fwrite() to work as expected at end
    
      if (count == MAXBKS)
      {
        fputs("The book.txt file is full.\n", stderr);
        exit(EXIT_FAILURE);
      }
    
      puts("\nPlease add new book titles.");
      puts("Press [Enter] at the start of a line to stop.\n");
    
      rewind(pbooks);
    
      for (count = 0; count < MAXBKS; count++)
      {
        if (libry[count].title[0] == '%')  // allow reuse of 'deleted' record
          break;
      }
      
      /* The following line is why I couldn't use '\0' for my deleted file marker */
    
      while (count < MAXBKS && gets(libry[count].title) != NULL && libry[count].title[0] != '\0')
      {
        puts("Now enter the author.");
        gets(libry[count].author);
        puts("Now enter the value.");
        scanf("%f", &libry[count++].value);// grabs data, THEN increments variable 'count'
    
        while (getchar() != '\n')
          continue;                        // clears input line
    
        if (count < MAXBKS)
          puts("Enter the next title.");
    
        if (libry[count].title[0] == '%')
          gets(libry[count].title);
      }
    
      puts("Here is the list of your books:\n");
    
      for (index = 0; index < count; index++)
      {
        if (libry[index].title[0] == '%')  // this makes sure 'deleted' records do not display in stdout
          ;
        else
          printf("%s by %s: $%.2f\n", libry[index].title, libry[index].author, libry[index].value);
      }
    
      rewind(pbooks);       // THIS IS VITAL TO THE PROCESS THAT FOLLOWS!!!
    
      fwrite(&libry[0], size, filecount + (count - filecount), pbooks);
                                                   
      fclose(pbooks);
    
      return 0;
    }
    V8 Interceptor: KDE 5.25.5 on Manjaro Linux 22.0.0 "Sikaris"
    Steering wheel: gcc 12.2.0 in Kate
    Supercharger: NASM 2.15.05
    Engine: AMD Ryzen 7 1700
    Dashboard: NVIDIA GeForce GTX 1060 6GB
    Rusty old trailer for hauling 3% of my Steam catalog: Windows 7 Pro 64bit SP1
    3 Antique Ford Model T automobiles for vintage LAN gaming: Windows XP SP3
    Sturdy buckboard for DOS LAN gaming: DOSBox 0.74-3 on Windows XP SP3

  2. #2
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Some suggestions:

    1) Post up a small library input file so your program can be run. If not here, then put it on Swoopshare, and post the link to it. Swoopshare is down atm, but it's at:
    http://en.swoopshare.com/
    Or any other free file depot.

    Edit: I've made up a binary file that works with my tweaked version of the program, below. (the program doesn't work well, but parts of it do.)

    http://d01.megashares.com/dl/dd0e2c7/books.bin




    2) FUNCTIONS! Huge help in both designing a program, and sorting out bugs in the code.
    If you haven't learned functions yet, then separate each part of main, that has a different purpose, and give it a comment at the start, what it should be doing.
    Last edited by Adak; 11-03-2010 at 11:47 AM.

  3. #3
    Codus Conjectus spongefreddie's Avatar
    Join Date
    Sep 2010
    Location
    USA
    Posts
    86
    Quote Originally Posted by Adak View Post
    Some suggestions:

    1) Post up a small library input file so your program can be run. If not here, then put it on Swoopshare, and post the link to it. Swoopshare is down atm, but it's at:
    http://en.swoopshare.com/
    Or any other free file depot.


    2) FUNCTIONS! Huge help in both designing a program, and sorting out bugs in the code.
    If you haven't learned functions yet, then separate each part of main, that has a different purpose, and give it a comment at the start, what it should be doing.
    Good point about functions, Adak. I should have been doing that. I've been so focused on only doing what the exercise says that I don't always use all tools at my disposal.

    I guess I'll just keep trying to make this work. I refuse to continue to the next exercise until I not only successfully complete it, but more importantly, that I understand everything that is happening on each line.

    Thanks again for your input.
    V8 Interceptor: KDE 5.25.5 on Manjaro Linux 22.0.0 "Sikaris"
    Steering wheel: gcc 12.2.0 in Kate
    Supercharger: NASM 2.15.05
    Engine: AMD Ryzen 7 1700
    Dashboard: NVIDIA GeForce GTX 1060 6GB
    Rusty old trailer for hauling 3% of my Steam catalog: Windows 7 Pro 64bit SP1
    3 Antique Ford Model T automobiles for vintage LAN gaming: Windows XP SP3
    Sturdy buckboard for DOS LAN gaming: DOSBox 0.74-3 on Windows XP SP3

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    This is a your code, with several tweaks:

    Code:
    /* I changed some names of variables: 
    libry to books
    MAXTITL and MAXAUTL to MAXTITLE and MAXAUTHOR
    pbooks to fp;
    file name from book.txt to books.txt
    */ 
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAXTITLE 40
    #define MAXAUTHOR 30
    #define MAXBKS 10
    
    struct book {
      char title[MAXTITLE];
      char author[MAXAUTHOR];
      float value;
    };
    
    void addBooks(struct book *books, FILE *fp_out);
    void sortRecords(struct book *books);
    
    int main(void)
    {
      struct book books[MAXBKS];
      char ch;
      int count = 0;
      int index, filecount, bkNum=0;
      FILE * fp_in, *fp_out;
      
      int size = sizeof(struct book);  // this was to avoid using 'sizeof(struct book)'
            // in every fread() and fwrite()
    
      //gets rid of the junk from books[] records
      for (index = 0; index < MAXBKS; index++) {   // this is to make all empty files equal to 'deleted' status
        books[index].title[0] = '\0';              // thus searchable in an 'if' statement
        strcpy(books[index].author, "");
        books[index].value = 0.0;
      } 
      if ((fp_in = fopen("books.txt", "r+b")) == NULL)  // this was changed from "a+b"
      {
        fputs("Can't open book.txt\n", stderr);
        exit(EXIT_FAILURE);
      }
    
    //  rewind(fp_in);    // goes to beginning of file - a precaution to avoid unexpected results
      
      while (count < MAXBKS && fread(&books[count], size, 1, fp_in) == 1)
      {
        if (count == 0)
          puts("Current contents of book.txt:\n");    // this insures that the contents of the file are
                                                      // printed at the start of the program
    
         /* printed records from the file */
        if(books[count].title[0] != '%') {
          printf("\n%s by %s: $%.2f\n", books[count].title, books[count].author, books[count].value);
          bkNum++;
        }
        printf("Would you like to modify (m) or delete (d) this record? [Enter] for 'no'.\n");
        if ((ch = getchar()) == 'd')
        {
          (void) getchar();   //removes the trailing newline from the input stream
          books[count].title[0] = '\0';     // assigns '%' if record is 'deleted' by user
        }
        if (ch == 'm')
        {
          puts("Please make changes to book title.");
          //puts("Press [Enter] at the start of a line to stop.\n");
          gets(books[count].title);
          puts("Now enter the author.");
          gets(books[count].author);
    
          puts("Now enter the value.");
          scanf("%f", &books[count].value);
          }
          count++; 
        }
    
      //filecount = count;   // IMPORTANT - must assign this for fwrite() to work as expected at end
      //
      if (count == MAXBKS)
      {
        fputs("The book.txt file is full.\n", stderr);
        exit(EXIT_FAILURE);
      }
      printf("\nWould you like to add new books? [y/n]: ");
      ch=getchar();
      if(ch=='y' || ch=='Y') {
        sortRecords(books);
        return 0;
        addBooks(books, fp_out);
      }
      for (count = 0; count < MAXBKS; count++)
      {
        if (books[count].title[0] == '%') { // allow reuse of 'deleted' record
          puts("Now enter the author.");
          gets(books[count].author);
          puts("Now enter the value.");
          scanf("%f", &books[count++].value);// grabs data, THEN increments variable 'count'
        }
      }
      /* The following line is why I couldn't use '\0' for my deleted file marker */
      /*
      while (count < MAXBKS && gets(books[count].title) != NULL && books[count].title[0] != '\0')
      {
        while (getchar() != '\n')
          continue;                        // clears input line
    
        if (count < MAXBKS)
          puts("Enter the next title.");
    
        if (books[count].title[0] == '%')
          gets(books[count].title);
      }
    */
      puts("Here is the list of your books:\n");
    
      for (index = 0; index < count; index++)
      {
        if (books[index].title[0] == '%')  // this makes sure 'deleted' records do not display in stdout
          ;
        else
          printf("%s by %s: $%.2f\n", books[index].title, books[index].author, books[index].value);
      }
    
      //rewind(fp);       // THIS IS VITAL TO THE PROCESS THAT FOLLOWS!!!
       
      //fwrite(&books[0], sizeof(books[0]), filecount + 1, fp_out);
      fclose(fp_in);
      fclose(fp_out);
    
      return 0;
    }
    void addBooks(struct book *books, FILE *fp_out) {
      int i,j;
      char buff[80];
      char ch;
      struct book book1;
    
      //for(i=0;i<4;i++) {
      while(ch=='y' || ch=='Y') {
        printf("\nEnter the book's title: ");
        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff)-1]='\0';
        strcpy(book1.title, buff);
    
        printf("Enter the book's author: ");
        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff)-1]='\0';
        strcpy(book1.author, buff);
    
        printf("\nEnter the value: ");
        fgets(buff, sizeof(buff), stdin);
        sscanf(buff, "%f", &book1.value);
        
        for(j=0;j<MAXBKS;j++) {
          if(books[j].title[0]=='%') {
            strcpy(books[j].title, book1.title);
            strcpy(books[j].author, book1.author);
            books[j].value = book1.value;
          }else {
            printf("\nError - array is currently full\n");
          }
        }
        printf("\nAdd another book? [y/n]: ");
        ch = getchar();
      }
      for(i=0;i<MAXBKS;i++)
        fwrite(&books[i], sizeof(books[0]), 1, fp_out);
      fclose(fp_out);
      //unlink("books.txt");
      //system("copy books.bin books.txt");
      //rename("books.bin", "books.txt");
      getch();
    }
    void sortRecords(struct book *books ) {
      int i, j, lo = 0, hi=MAXBKS; 
      struct book book1;
      char val[MAXTITLE];
      j=hi;   
      for(i=lo+1;i<hi;i++) {  
        book1 = books[i];
        j = i-1;
        while((strcmp(books[j].title, book1.title)) > 0) {
          books[j + 1] = books[j];
          --j;
          if(j<0) break;
        }   
        books[j+1] = book1;
      }
      printf("\n In sorted order: \n");
      for(i=0;i<10;i++) 
        if(books[i].title)
          printf("\nTitle: %s Author: %s Value: %.2f",books[i].title,books[i].author,books[i].value);
      getch();
    }
    I have made a file for this, and I'll post it up (I don't know why, but Swoopshare is down), have to find another file depot).

    Still disorganized as far as functions go, but it's a start.

    A binary file for this that you can download, is here:
    http://d01.megashares.com/dl/dd0e2c7/books.bin
    Last edited by Adak; 11-03-2010 at 01:35 PM.

  5. #5
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    I thought you might enjoy seeing how it moves into a more mature form.

    Code:
    /* I changed some names of variables: 
    libry to books
    MAXTITL and MAXAUTL to MAXTITLE and MAXAUTHOR
    pbooks to fp;
    file name from book.txt to books.txt
    */ 
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAXTITLE 40
    #define MAXAUTHOR 30
    #define MAXBKS 10
    
    struct book {
      char title[MAXTITLE];
      char author[MAXAUTHOR];
      float value;
    };
    
    void addBooks(struct book *books, FILE *fp_out);
    int idelete(struct book *books, char *buff);
    void menu(struct book *books, int bknum, FILE *fp_out);
    void sortRecords(struct book *books);
    void showAll(struct book *books);
    
    int main(void)
    {
      struct book books[MAXBKS];
      char ch;
      int i, count = 0;
      int index, filecount, bkNum=0;
      FILE * fp_in, *fp_out;
      
      int size = sizeof(struct book);  // this was to avoid using 'sizeof(struct book)'
            
      //gets rid of the junk from books[] records
      for (index = 0; index < MAXBKS; index++) {   // this is to make all empty files equal to 'deleted' status
        books[index].title[0] = '\0';              // thus searchable in an 'if' statement
        strcpy(books[index].author, "");
        books[index].value = 0.0;
      } 
      if((fp_in = fopen("books.txt", "r+b")) == NULL) {  // this was changed from "a+b"
        fputs("Can't open book.txt\n", stderr);
        exit(EXIT_FAILURE);
      }
      for(i=0;i<MAXBKS;i++) {      //load the array of books
        fread(&books[i], size, 1, fp_in);
        if(books[i].title)
          bkNum++;
      }
      menu(books, bkNum, fp_out);
    
      
      puts("Here is the list of your books:\n");
      for (index = 0; index < count; index++)
      {
        if (books[index].title[0] == '%')  // this makes sure 'deleted' records do not display in stdout
          ;
        else
          printf("%s by %s: $%.2f\n", books[index].title, books[index].author, books[index].value);
      }
    
      //rewind(fp);       // THIS IS VITAL TO THE PROCESS THAT FOLLOWS!!!
       
      //fwrite(&books[0], sizeof(books[0]), filecount + 1, fp_out);
      fclose(fp_in);
      fclose(fp_out);
    
      return 0;
    }
    void addBooks(struct book *books, FILE *fp_out) {
      int i,j;
      char buff[80];
      char ch;
      struct book book1;
    
      //for(i=0;i<4;i++) {
      while(ch=='y' || ch=='Y') {
        printf("\nEnter the book's title: ");
        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff)-1]='\0';
        strcpy(book1.title, buff);
    
        printf("Enter the book's author: ");
        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff)-1]='\0';
        strcpy(book1.author, buff);
    
        printf("\nEnter the value: ");
        fgets(buff, sizeof(buff), stdin);
        sscanf(buff, "%f", &book1.value);
        
        for(j=0;j<MAXBKS;j++) {
          if(books[j].title[0]=='%') {
            strcpy(books[j].title, book1.title);
            strcpy(books[j].author, book1.author);
            books[j].value = book1.value;
          }else {
            printf("\nError - array is currently full\n");
          }
        }
        printf("\nAdd another book? [y/n]: ");
        ch = getchar();
      }
      for(i=0;i<MAXBKS;i++)
        fwrite(&books[i], sizeof(books[0]), 1, fp_out);
      fclose(fp_out);
      //unlink("books.txt");
      //system("copy books.bin books.txt");
      //rename("books.bin", "books.txt");
      getch();
    }
    int idelete(struct book *books, char *buff) {
      int i, j, mid, lo, hi;
      lo=0;hi=MAXBKS;
      mid=(lo+hi)/2;
      while(lo <= hi) {
        if(strcmp(books[mid].title, buff) >0)
          lo=mid+1;
        else if(strcmp(books[mid].title, buff) <0)
          hi=mid-1;
        else
          return 1;
      }
      return 0;
    }
    void menu(struct book *books, int bkNum, FILE *fp_out) {
      char ch;
      char buff[80];
      int i, n;
      do {
        printf("\n                 <<<<      Welcome to the Main Menu       >>>> \n");
        printf("\n\t    [a]dd a record            [d]elete a record    \n");
        printf("\n\t    [e]dit a record           [f]etch a record     \n");
        printf("\n                                                     \n");
        printf("\n\t\t   Make a choice or Q to quit: ");    
        ch=getchar();
        (void) getchar();
        switch (ch) {
          case 'a':   
            printf("\nWould you like to add a new book? [y/n]: ");
            ch=getchar();
            if(ch=='y' || ch=='Y') {
              sortRecords(books);
              addBooks(books, fp_out);
            }
            break;
          case 'd':   
            printf("\nEnter the title of the book you want to delete:  ");
            fgets(buff, sizeof(books[0]), stdin); 
            idelete(books, buff);
    
            break;
          case 'e':   break;    
          case 'f':   break;
          case 'Q':   ch='q';
          case 'q':   break;
          default: printf("\n\t\t    Please enter a valid selection\n");
        };
    
      }while(ch!='q'); 
    }
    
    void sortRecords(struct book *books ) {
      int i, j, lo = 0, hi=MAXBKS; 
      struct book book1;
      char val[MAXTITLE];
      j=hi;   
      for(i=lo+1;i<hi;i++) {  
        book1 = books[i];
        j = i-1;
        while((strcmp(books[j].title, book1.title)) > 0) {
          books[j + 1] = books[j];
          --j;
          if(j<0) break;
        }   
        books[j+1] = book1;
      }
      printf("\n In sorted order: \n");
      for(i=0;i<10;i++) 
        if(books[i].title)
          printf("\nTitle: %s Author: %s Value: %.2f",books[i].title,books[i].author,books[i].value);
      
    }
    void showAll(struct book *books) {
      int i=0;
      while(i < MAXBKS) {
        if(books[i].title) {
          printf("\n%s by %s: $%.2f\n", books[i].title, books[i].author, books[i].value);
        }
      }
    }
    /*  
    code stockpile:
    
      if (ch == 'm')
        {
          puts("Please make changes to book title.");
          //puts("Press [Enter] at the start of a line to stop.\n");
          gets(books[count].title);
          puts("Now enter the author.");
          gets(books[count].author);
    
          puts("Now enter the value.");
          scanf("%f", &books[count].value);
          }
          count++; 
        }
     for (count = 0; count < MAXBKS; count++)
      {
        if(!books[count].title) { // allow reuse of 'deleted' record
          puts("Now enter the author.");
          gets(books[count].author);
          puts("Now enter the value.");
          scanf("%f", &books[count++].value);// grabs data, THEN increments variable 'count'
        }
      }
      while (count < MAXBKS && gets(books[count].title) != NULL && books[count].title[0] != '\0')
      {
        while (getchar() != '\n')
          continue;                        // clears input line
    
        if (count < MAXBKS)
          puts("Enter the next title.");
    
        if (books[count].title[0] == '%')
          gets(books[count].title);
      }
    */
    Not a lot of things work just yet, but the skeleton of the program, is starting to take shape.

    Remember, you can get the file (small though it is), from the link I posted for it, previously.
    Last edited by Adak; 11-03-2010 at 01:34 PM.

  6. #6
    Codus Conjectus spongefreddie's Avatar
    Join Date
    Sep 2010
    Location
    USA
    Posts
    86
    Quote Originally Posted by Adak View Post
    I thought you might enjoy seeing how it moves into a more mature form.

    Code:
    ...
    Not a lot of things work just yet, but the skeleton of the program, is starting to take shape.

    Remember, you can get the file (small though it is), from the link I posted for it, previously.
    Holy Mackerel, I wasn't expecting this! THANKS! I just got home from work, and I'm going to examine this very closely... I really appreciate the effort you put into helping me. I apologize for any time this may have taken from something else you were doing.

    I'll post another reply when I've fully understood where I went wrong.
    V8 Interceptor: KDE 5.25.5 on Manjaro Linux 22.0.0 "Sikaris"
    Steering wheel: gcc 12.2.0 in Kate
    Supercharger: NASM 2.15.05
    Engine: AMD Ryzen 7 1700
    Dashboard: NVIDIA GeForce GTX 1060 6GB
    Rusty old trailer for hauling 3% of my Steam catalog: Windows 7 Pro 64bit SP1
    3 Antique Ford Model T automobiles for vintage LAN gaming: Windows XP SP3
    Sturdy buckboard for DOS LAN gaming: DOSBox 0.74-3 on Windows XP SP3

  7. #7
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    I'm having trouble with the reuse the deleted records logic myself, because the data isn't handled through an index (for sorting, displaying etc.). I didn't know that was a difficulty because I never used deleted records, without having an index in place.

    Very small flat databases like this, don't need to reuse deleted records, because the amount of data they work with is well, small.

    This is a hefty program for a beginner, I must say. I feel a tad guilty putting the "use deleted records", load on you.

    Nevertheless, this is the newest version. It doesn't have a lot of stuff working just yet.
    Code:
    /* I changed some names of variables: 
    libry to books
    MAXTITL and MAXAUTL to MAXTITLE and MAXAUTHOR
    pbooks to fp;
    file name from book.txt to books.bin
    */ 
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAXTITLE 40
    #define MAXAUTHOR 30
    #define MAXBKS 10
    
    struct book {
      char title[MAXTITLE];
      char author[MAXAUTHOR];
      float value;
    };
    
    void addBooks(struct book *books);
    int idelete(struct book *books, char *buff);
    void menu(struct book *books, int bknum);
    void sortRecords(struct book *books);
    void viewAll(struct book *books);
    
    int main(void)
    {
      struct book books[MAXBKS];
      char ch;
      int i, count = 0;
      int index, filecount, bkNum=0;
      FILE * fp_in, *fp_out;
      
      int size = sizeof(struct book);  // this was to avoid using 'sizeof(struct book)'
            
      //gets rid of the junk from books[] records
      for (index = 0; index < MAXBKS; index++) {   // this is to make all empty files equal to 'deleted' status
        books[index].title[0] = '\0';              // thus searchable in an 'if' statement
        strcpy(books[index].author, "");
        books[index].value = 0.0;
      } 
      if((fp_in = fopen("books.bin", "r+b")) == NULL) {  // this was changed from "a+b"
        fputs("Can't open books.bin\n", stderr);
        exit(EXIT_FAILURE);
      }
      for(i=0;i<MAXBKS;i++) {      //load the array of books
        fread(&books[i], size, 1, fp_in);
        if(books[i].title[0])
          bkNum++;
      }
      fclose(fp_in);
      menu(books, bkNum);
    
    
      return 0;
    }
    void addBooks(struct book *books) {
      int i,j;
      char buff[80];
      char ch;
      struct book book1;
    
      
      while(ch=='y' || ch=='Y') {
        printf("\nEnter the book's title: ");
        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff)-1]='\0';
        strcpy(book1.title, buff);
    
        printf("Enter the book's author: ");
        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff)-1]='\0';
        strcpy(book1.author, buff);
    
        printf("\nEnter the value: ");
        fgets(buff, sizeof(buff), stdin);
        sscanf(buff, "%f", &book1.value);
        
        for(j=0;j<MAXBKS;j++) {
          if(books[j].title[0]=='\0') {
            strcpy(books[j].title, book1.title);
            strcpy(books[j].author, book1.author);
            books[j].value = book1.value;
          }else {
            printf("\nError - array is currently full\n");
          }
        }
        printf("\nAdd another book? [y/n]: ");
        ch = getchar();
      }
    }
    int idelete(struct book *books, char *buff) {
      int i, j, mid, lo, hi;
      lo=0;hi=MAXBKS;
      mid=(lo+hi)/2;
      while(lo <= hi) {
        if(strcmp(books[mid].title, buff) >0)
          lo=mid+1;
        else if(strcmp(books[mid].title, buff) <0)
          hi=mid-1;
        else
          return mid;
      }
      return 0;
    }
    void menu(struct book *books, int bkNum) {
      char ch;
      char buff[80];
      int i, n;
      FILE *fp;
      do {
        printf("\n                 <<<<      Welcome to the Main Menu       >>>> \n");
        printf("\n\n\t  There are %d books in the library currently    \n", bkNum);
        printf("\n\t    [a]dd a record            [d]elete a record    \n");
        printf("\n\t    [e]dit a record           [f]etch a record     \n");
        printf("\n\t    [v]iew all records √      [w]rite all records   \n");
        printf("\n\t\t   Make a choice or Q to quit: ");    
        ch=getchar();
        (void) getchar();
        switch (ch) {
          case 'a':   
            printf("\nWould you like to add a new book? [y/n]: ");
            ch=getchar();
            if(ch=='y' || ch=='Y') {
              addBooks(books);
              sortRecords(books);
    
            }
            break;
          case 'd':   
            printf("\nEnter the title of the book you want to delete:  ");
            fgets(buff, sizeof(books[0]), stdin); 
            idelete(books, buff);
    
            break;
          case 'e':  break;    
          case 'f':  break;
          case 'v':  viewAll(books); break;
          case 'w':  writeAll(books); 
                         break;
          case 'Q':  ch='q';
          case 'q':  break;
          default: printf("\n\t\t    Please enter a valid selection\n");
        };
    
      }while(ch!='q'); 
    }
    
    void sortRecords(struct book *books ) {
      int i, j, lo = 0, hi=MAXBKS; 
      struct book book1;
      char val[MAXTITLE];
      j=hi;   
      for(i=lo+1;i<hi;i++) {  
        book1 = books[i];
        j = i-1;
        while((strcmp(books[j].title, book1.title)) > 0) {
          books[j + 1] = books[j];
          --j;
          if(j<0) break;
        }   
        books[j+1] = book1;
      }
      printf("\n In sorted order: \n");
      for(i=0;i<10;i++)  {
        if(books[i].title)
          printf("\nTitle: %s Author: %s Value: %.2f",books[i].title,books[i].author,books[i].value);
      }
    }
    void viewAll(struct book *books) {
      int i=0;
      puts("\n\tHere is the list of your books:\n");
      while(i < MAXBKS) {
        if(books[i].title[0]) {
          printf("%s by %s: $%.2f\n", books[i].title, books[i].author, books[i].value);
        }
        ++i;
      }
    }
    int writeAll(struct book *books) {
      int i;
      FILE *fp;
    
      if(rename("books.bin", "books.bak")==0) {  //save current data file in backup file
        if((fp=fopen("books.bin", "wb"))==NULL) { 
          printf("\nError opening temp file, no records written to file.\n");
          return 1;
        }
      }else {
        printf("\nError renaming in function writeAll()\n");
        return 1;
      }
    
      for(i=0;i<MAXBKS;i++)  //write new data file
        fwrite(&books[i], sizeof(books[0]), 1, fp);
      fclose(fp);
    
      return 0;
    }
    Only the view option is actually working for sure, but the others are getting close.
    Last edited by Adak; 11-03-2010 at 10:34 PM.

  8. #8
    Registered User claudiu's Avatar
    Join Date
    Feb 2010
    Location
    London, United Kingdom
    Posts
    2,094
    Forgive me for barging in, but if you are looking to learn another thing to look out for is using gets(): it is inherently unsafe. I know Adak probably didn't mention it to avoid confusing you even further, but I think it's never too early to do the right thing: use fgets() instead. The FAQ on this site will explain why gets is bad and how to substitute it for fgets().
    1. Get rid of gets(). Never ever ever use it again. Replace it with fgets() and use that instead.
    2. Get rid of void main and replace it with int main(void) and return 0 at the end of the function.
    3. Get rid of conio.h and other antiquated DOS crap headers.
    4. Don't cast the return value of malloc, even if you always always always make sure that stdlib.h is included.

  9. #9
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Good ideas are always welcome, claudiu.

    gets() is easier to use, but it's so unsafe, you can't leave it behind quickly enough. I know C was intended for professional programmers to use, rather than the general hordes, but that function seems ill-designed, even so.
    Last edited by Adak; 11-04-2010 at 12:49 AM. Reason: it's "ideas", not idea's

  10. #10
    Codus Conjectus spongefreddie's Avatar
    Join Date
    Sep 2010
    Location
    USA
    Posts
    86
    Quote Originally Posted by Adak View Post
    Good idea's are always welcome, claudiu.

    gets() is easier to use, but it's so unsafe, you can't leave it behind quickly enough. I know C was intended for professional programmers to use, rather than the general hordes, but that function seems ill-designed, even so.
    Hey you guys both beat me to the punch, LOL! Here were two questions I have for Adak, now that I've looked closer at his code:

    1) Should I always try to use fgets() instead of gets()? I've heard that it poses a security risk, depending on the implementation. ANSWERED!

    2) Was it a mistake for me to use only one file pointer? Or more to the point, is it even possible to do the same task with a single file pointer?
    V8 Interceptor: KDE 5.25.5 on Manjaro Linux 22.0.0 "Sikaris"
    Steering wheel: gcc 12.2.0 in Kate
    Supercharger: NASM 2.15.05
    Engine: AMD Ryzen 7 1700
    Dashboard: NVIDIA GeForce GTX 1060 6GB
    Rusty old trailer for hauling 3% of my Steam catalog: Windows 7 Pro 64bit SP1
    3 Antique Ford Model T automobiles for vintage LAN gaming: Windows XP SP3
    Sturdy buckboard for DOS LAN gaming: DOSBox 0.74-3 on Windows XP SP3

  11. #11
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Whether you need two or one file pointers, depends on your logic. You can't have two different files using the same file pointer, at the same time. I am finding a good deal of code that I have added is now, not needed. Delete key to the rescue!

    When I started with the first version, I had a lot of problems, and lots of errors! I wanted to keep more of the original code, but I just couldn't code much, without stepping on some other bit of code. Not your code's fault, just that my logic didn't mix in well, with your code.

  12. #12
    Codus Conjectus spongefreddie's Avatar
    Join Date
    Sep 2010
    Location
    USA
    Posts
    86
    Quote Originally Posted by Adak View Post
    Whether you need two or one file pointers, depends on your logic. You can't have two different files using the same file pointer, at the same time. I am finding a good deal of code that I have added is now, not needed. Delete key to the rescue!

    When I started with the first version, I had a lot of problems, and lots of errors! I wanted to keep more of the original code, but I just couldn't code much, without stepping on some other bit of code. Not your code's fault, just that my logic didn't mix in well, with your code.
    You are being quite gracious regarding my noob-scribble, aka "spongefreddie's code."

    I got sidetracked tonight but will attack the problem in earnest tomorrow (later today, to be more precise). I really do appreciate your help. I'm sure this is eventually going to end up the way it has every time so far: I'll get a grand "aha!" moment at some point that will somehow turn all the agonizing head-banging into an oddly comforting rite of passage.
    V8 Interceptor: KDE 5.25.5 on Manjaro Linux 22.0.0 "Sikaris"
    Steering wheel: gcc 12.2.0 in Kate
    Supercharger: NASM 2.15.05
    Engine: AMD Ryzen 7 1700
    Dashboard: NVIDIA GeForce GTX 1060 6GB
    Rusty old trailer for hauling 3% of my Steam catalog: Windows 7 Pro 64bit SP1
    3 Antique Ford Model T automobiles for vintage LAN gaming: Windows XP SP3
    Sturdy buckboard for DOS LAN gaming: DOSBox 0.74-3 on Windows XP SP3

  13. #13
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Here's to "Aha!" moments! <cheers!>

    A bit more organized, the checked functions "work" but are not thoroughly tested at all. The unchecked functions do nothing (I hope! ).
    Code:
    /* I changed some names of variables: 
    libry to books
    MAXTITL and MAXAUTL to MAXTITLE and MAXAUTHOR
    pbooks to fp;
    file name from book.txt to books.txt
    */ 
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAXTITLE 40
    #define MAXAUTHOR 30
    #define MAXBKS 10
    
    struct book {
      char title[MAXTITLE];
      char author[MAXAUTHOR];
      float value;
    };
    
    int addBooks(struct book *books);
    int idelete(struct book *books, int index);
    int fetch(struct book *books, char *buff);
    void menu(struct book *books, int bknum);
    void sortRecords(struct book *books);
    void viewAll(struct book *books);
    
    int main(void)
    {
      struct book books[MAXBKS];
      char ch;
      int i;
      int index, filecount, bkNum=0;
      FILE * fp_in, *fp_out;
      
      int size = sizeof(struct book);  // this was to avoid using 'sizeof(struct book)'
            
      //gets rid of the junk from books[] records
      for (index = 0; index < MAXBKS; index++) {   // this is to make all empty files equal to 'deleted' status
        books[index].title[0] = '\0';              // thus searchable in an 'if' statement
        strcpy(books[index].author, "");
        books[index].value = 0.0;
      } 
      if((fp_in = fopen("books.bin", "r+b")) == NULL) {  // this was changed from "a+b"
        fputs("Can't open book.txt\n", stderr);
        exit(EXIT_FAILURE);
      }
      for(i=0;i<MAXBKS;i++) {      //load the array of books
        fread(&books[i], size, 1, fp_in);
        if(books[i].title[0])
          bkNum++;
      }
      fclose(fp_in);
      menu(books, bkNum);
    
      return 0;
    }
    int addBooks(struct book *books) {
      int i,j,ok;
      char buff[80];
      char ch='y';
      struct book book1;
    
      //for(i=0;i<4;i++) {
      while(ch=='y' || ch=='Y') {
        printf("\nEnter the book's title: ");
        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff)-1]='\0';
        strcpy(book1.title, buff);
    
        printf("Enter the book's author: ");
        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff)-1]='\0';
        strcpy(book1.author, buff);
    
        printf("\nEnter the value: ");
        fgets(buff, sizeof(buff), stdin);
        sscanf(buff, "%f", &book1.value);
        
        for(j=0,ok=0;j<MAXBKS;j++) {
          if(books[j].title[0]=='\0') {
            strcpy(books[j].title, book1.title);
            strcpy(books[j].author, book1.author);
            books[j].value = book1.value;
            ok=1;
            break;
          }
        }
        if(!ok) {
          printf("\nArray is full, couldn't add that record");
          return 1;   //add failed
        }
        printf("\nAdd another book? [y/n]: ");
        scanf("%1c", &ch);
        (void) getchar();
      }
      return 0;       //successful add
    }
    int idelete(struct book *books, int index) {
      books[index].title[0]='\0';
      return 0;
    }
    int fetch(struct book *books, char *buff) {
       int i=0, lo, hi, mid;
       while(books[i++].title[0]=='\0'); //find lo
       lo=i-1;
       hi = MAXBKS;
       while(lo <= hi) {
         mid=(lo + hi)/2;
         if(strcmp(books[mid].title, buff) >0)
           hi=mid-1;
        else if(strcmp(books[mid].title, buff) <0)
           lo=mid+1;
        else
          return mid;
      }
      return 0;
    }
    void menu(struct book *books, int bkNum) {
      char ch;
      char buff[80];
      int i, n, index;
      FILE *fp;
      do {
        printf("\n                 <<<<      Welcome to the Main Menu       >>>> \n");
        printf("\n\n\t  There are %d books in the library currently    \n", bkNum);
        printf("\n\t    [a]dd a record     û      [d]elete a record   û   \n");
        printf("\n\t    [e]dit a record           [f]etch a record    û   \n");
        printf("\n\t    [v]iew all records û      [w]rite all records û   \n");
        printf("\n\t\t   Make a choice or Q to quit: ");    
        fgets(buff, sizeof(buff), stdin);
        ch=buff[0];
        switch (ch) {
          case 'a':   
            printf("\nWould you like to add a new book? [y/n]: ");
            ch=getchar();
            (void) getchar();
            if(ch=='y' || ch=='Y') {
              n=addBooks(books);
              if(n==0) {   //a successful add
                sortRecords(books);
                ++bkNum;
              }
            }
            break;
          case 'd':   
            printf("\nEnter the title of the book you want to delete:  ");
            fgets(buff, sizeof(books[0]), stdin); 
            buff[strlen(buff)-1]='\0';
            index = fetch(books, buff); //get buff's index in the array
            idelete(books, index);       //so it can be deleted
            --bkNum;
            break;
          case 'e':  break;    
          case 'f':  
            printf("\nEnter the title of the book:  ");
            fgets(buff, sizeof(books[0]), stdin); 
            buff[strlen(buff)-1]='\0';
            index = fetch(books, buff);
            if(index) {
              printf("\n\t  Title: %s\n\t Author: %s\n\t  Price: %.2f",
              books[index].title, books[index].author, books[index].value);
              getch();
            }
            break;
          case 'v':  viewAll(books); break;
          case 'w':  writeAll(books); break;
    
          case 'Q':  ch='q';
          case 'q':  break;
          default: printf("\n\t\t    Please enter a valid selection\n");
        };
    
      }while(ch!='q'); 
    }
    
    void sortRecords(struct book *books ) {
      int i, j, lo = 0, hi=MAXBKS; 
      struct book book1;
      char val[MAXTITLE];
      j=hi;   
      for(i=lo+1;i<hi;i++) {  
        book1 = books[i];
        j = i-1;
        while((strcmp(books[j].title, book1.title)) > 0) {
          books[j + 1] = books[j];
          --j;
          if(j<0) break;
        }   
        books[j+1] = book1;
      }
      printf("\n In sorted order: \n");
      for(i=0;i<10;i++)  {
        if(books[i].title)
          printf("\nTitle: %s Author: %s Value: %.2f",books[i].title,books[i].author,books[i].value);
      }
    }
    void viewAll(struct book *books) {
      int i=0;
      puts("\n\tHere is the list of your books:\n");
      while(i < MAXBKS) {
        if(books[i].title[0]) {
          printf("%s by %s: $%.2f\n", books[i].title, books[i].author, books[i].value);
        }
        ++i;
      }
    }
    int writeAll(struct book *books) {
      int i;
      FILE *fp;
    
      unlink("books.bak");
      if(rename("books.bin", "books.bak")==0) {
        if((fp=fopen("books.bin", "wb"))==NULL) {
          printf("\nError opening books.bin file. No records were written.\n");
          return 1;
        }
      }else {
        printf("\nError renaming in function writeAll()\n");
        return 1;
      }
    
      for(i=0;i<MAXBKS;i++)
        fwrite(&books[i], sizeof(books[0]), 1, fp);
      fclose(fp);
    
      return 0;
    }
    Without indexing (as in sorting and displaying the records through the index), I haven't seen anything helpful come out of the reuse records idea. Of course the elements in the array all hold records that get used over and over, but so far, no big deal.

  14. #14
    Codus Conjectus spongefreddie's Avatar
    Join Date
    Sep 2010
    Location
    USA
    Posts
    86
    Quote Originally Posted by Adak View Post
    Here's to "Aha!" moments! <cheers!>

    A bit more organized, the checked functions "work" but are not thoroughly tested at all. The unchecked functions do nothing (I hope! ).
    Code:
    Adak's code here...
    Without indexing (as in sorting and displaying the records through the index), I haven't seen anything helpful come out of the reuse records idea. Of course the elements in the array all hold records that get used over and over, but so far, no big deal.
    FYI update: I'm finally up, showered, sitting at my BFP (Box o' Fragadelic Power) with a glass of my favorite Mountain Fury (superior Mountain Dew knockoff), and am working on this program.

    One thing I want to say: thanks a million for reminding me about using functions... it's a lot more fun when I can isolate the different tasks this way.
    V8 Interceptor: KDE 5.25.5 on Manjaro Linux 22.0.0 "Sikaris"
    Steering wheel: gcc 12.2.0 in Kate
    Supercharger: NASM 2.15.05
    Engine: AMD Ryzen 7 1700
    Dashboard: NVIDIA GeForce GTX 1060 6GB
    Rusty old trailer for hauling 3% of my Steam catalog: Windows 7 Pro 64bit SP1
    3 Antique Ford Model T automobiles for vintage LAN gaming: Windows XP SP3
    Sturdy buckboard for DOS LAN gaming: DOSBox 0.74-3 on Windows XP SP3

  15. #15
    Codus Conjectus spongefreddie's Avatar
    Join Date
    Sep 2010
    Location
    USA
    Posts
    86

    Working Code!

    Okay, a few things before I upload the code...

    1) I know, I know, using more global variables would cut down on the number
    of function arguments I'm passing around, but I need to go on to the next
    exercise... I've spent way too much time on this one already.

    2) Adak, thanks for the refresher on using fgets(), and the reminder about
    using functions.

    3) The program is a little bit wonky with the Enter key sometimes, but I
    went way beyond what the textbook's exercise asked me to do... couldn't
    help it, you know how it is, lol.

    4) The program isn't completely idiot-proof, but it does what I set out
    to do... which is successfully overwrite existing (deleted records) with
    new records, while making deleted records invisible.

    5) To run this program after compiling, you just need an empty text file
    named "books.bin" in the same folder as the executable. Each time you
    exit the program, all of your changes are written to the file, regardless
    of position in the structure's array sequence. That was the other problem
    I was struggling with: successfully writing all changes upon exit.

    6) The maximum records are currently set at 20, but that's easily changed
    in the second #define statement.

    This was officially the longest I've ever spent on one exercise (3 calendar days).

    Next!




    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAXCHARS 40
    #define MAXBOOKS 20
    
    struct book {
    	int flag;
    	char title[MAXCHARS];
    	char author[MAXCHARS];
    	float value;
    };
    
    
    int read_to_struct(struct book * myBooks, int booksize, int count, FILE * pbooks);
    char menu(void);
    int add_books(struct book * myBooks, int filecount, int booksize, FILE * pbooks);
    void delete_books(struct book * myBooks, int filecount, int booksize, FILE * pbooks);
    void edit_books(struct book * myBooks, int filecount, int booksize, FILE * pbooks);
    int show_books(struct book * myBooks, int init);
    void write_to_file(struct book * myBooks, int filecount, int booksize, int count, FILE * pbooks);
    
    
    int main(void)
    {
    	struct book myBooks[MAXBOOKS] = {0, "", "", (float) 0.0};	// making sure all records are invisible until used
    	int count = 0;
    	int filecount;
    	FILE * pbooks;
    	int booksize = sizeof(struct book);
    	char ch;
    	int init = 1;		// this is to set flag for show_books at beginning of program
    
    	if ((pbooks = fopen("books.dat", "r+b")) == NULL)
    	{
    		fputs("Can't open books.dat\n", stderr);
    		exit(EXIT_FAILURE);
    	}
    
    	rewind(pbooks);
    
    	filecount = count = read_to_struct(myBooks, booksize, count, pbooks); // 'filecount = count' two birds, one stone
    
    	init = show_books(myBooks, init);
    
    	init = 0;		// this is to get rid of special message after first display of books
    	
    	if (count >= MAXBOOKS)
    	{
    		puts("\nThe books.dat file is full.");
    		puts("You must overwrite an existing record.\n");
    	}
    
    	while ((ch = menu()) != 'q')
    	{
    		switch (ch)
    			{
    			case 'a' :
                  count = add_books(myBooks, filecount, booksize, pbooks);		// count must be returned for proper show_books() display
    				  filecount += count;
                  break;
    			case 'd' :
                  delete_books(myBooks, filecount, booksize, pbooks);
                  break;
    			case 'e' :
                  edit_books(myBooks, filecount, booksize, pbooks);
                  break;
    			case 's' :
                  init = show_books(myBooks, init);
                  break;
    			default	:
                  puts("That's not A, D, E, S or Q! Try again");
    			}
    	}
    
    	write_to_file(myBooks, filecount, booksize, count, pbooks);
    
    	fclose(pbooks);
    
    	puts("\nGoodbye!\n");
    
    	return 0;
    }
    /* ################################################## END OF MAIN ####################################### */
    
    
    
    // ############################################## INITIAL READ TO STRUCTURES
    int read_to_struct(struct book * myBooks, int booksize, int count, FILE * pbooks)
    {
    	while (count < MAXBOOKS && fread(&myBooks[count], booksize, 1, pbooks) == 1)	// for reading file records into structure 'myBooks'
    	{
    		if (count == 0)
    		{
    			puts("Current contents of books.dat:\n");
    		}
    
    		if (myBooks[count].flag == 0)
    			myBooks[count].flag = 0;
    		if (myBooks[count].flag == 1)		// '2' is flag for 'deleted' - '0' is assigned by default at beginning
    			myBooks[count].flag = 1;
    		if (myBooks[count].flag == 2)
    			myBooks[count].flag = 2;
    
    		count++;
    	}
    
    	return count;
    }
    
    
    // ############################################## MENU
    char menu(void)
    {
    	char ch;
    
    	puts("\n[A]dd a record");
    	puts("[D]elete a record");
    	puts("[E]dit a record");
    	puts("[S]how all records\n");
    	printf("Make a choice or [Q] to quit:");
    	ch = getchar();
    	ch = tolower(ch);
    
    	return ch;
    }
    
    
    // ############################################## ADD BOOKS
    int add_books(struct book * myBooks, int count, int booksize, FILE * pbooks)
    {
    	char temp[MAXCHARS];
    
    	while (getchar() != '\n')		// clears out input line from menu
    		continue;
    
    	while (myBooks[count].flag == 1)		// this loop bypasses all undeleted records
    	{
    		for (count = 0; myBooks[count].flag == 1; count++)
    			;
    	}	
    
    	puts("Please enter book title.");
    	fgets(temp, sizeof(myBooks->title), stdin);
    	temp[strlen(temp)-1]='\0';		// copies over the '\n' with an additional null character before end of string
    	strcpy(myBooks[count].title, temp);
    	if (strlen(temp) > 1)
    		myBooks[count].flag = 1;		// without this, show_books will only display new entries after program restart!
    	puts("Please enter author name.");
    	fgets(temp, sizeof(myBooks->author), stdin);
    	temp[strlen(temp)-1]='\0';
    	strcpy(myBooks[count].author, temp);
    	puts("Now enter the price, or 'q' to quit.");
    	scanf("%f", &myBooks[count].value);
    	count++;
    
    	while (getchar() != '\n')		// clears input line
    		continue;
    
    	return count;
    }
    
    
    // ############################################## DELETE BOOKS
    void delete_books(struct book * myBooks, int filecount, int booksize, FILE * pbooks)
    {
    	char ch;
    	int count = 0;
    
    	while (getchar() != '\n')		// clears input line from menu selection
    			continue;
    
    	while (count < filecount)
    	{
    		if (myBooks[count].flag == 0 || myBooks[count].flag == 2)	// keeps user from seeing unused or deleted records
    			count++;							// and increments count past them
    		else
    		{
    			printf("\n%s by %s: $%.2f\n", myBooks[count].title, myBooks[count].author, myBooks[count].value);
    			printf("Would you like to delete this record? 'Y' to delete, [Enter] to skip.\n");
    		}
    
    		if ((ch = getchar()) == 'Y' || ch == 'y')
    		{
    			myBooks[count].flag = 2;		// assigns '2' to flag if record is 'deleted' by user
    			while (getchar() != '\n')
    					continue;
    		}
    
    		count++;
    	}
    }
    
    
    // ############################################## EDIT BOOKS
    void edit_books(struct book * myBooks, int filecount, int booksize, FILE * pbooks)
    {
    	char temp[MAXCHARS];
    	char ch;
    	int count = 0;
    
    	while (getchar() != '\n')		// clears input line from menu selection
    					continue;
    
    	while (count < filecount)
    	{
    		if (myBooks[count].flag == 0 || myBooks[count].flag == 2)	// this prevents overwriting undeleted records
    			;
    		else
    		{
    			printf("\n%s by %s: $%.2f\n", myBooks[count].title, myBooks[count].author, myBooks[count].value);
    			printf("Would you like to edit this record? 'Y' to edit, [Enter] to skip.\n");
    		}
    
    		if ((ch = getchar()) == 'Y' || ch == 'y')
    		{
    			puts("Please make changes to book title.");
    			fgets(temp, sizeof(myBooks->title), stdin);
    			temp[strlen(temp)-1]='\0';		// copies over the '\n' with an additional null character before end of string
    			strcpy(myBooks[count].title, temp);
    			puts("Please make changes to author.");
    			fgets(temp, sizeof(myBooks->author), stdin);
    			temp[strlen(temp)-1]='\0';
    			strcpy(myBooks[count].author, temp);
    			puts("Now enter the price, or 'q' to quit.");
    			scanf("%f", &myBooks[count].value);
    		}
    
    		count++;
    	}
    }
    
    
    // ############################################## SHOW BOOKS
    int show_books(struct book * myBooks, int init)
    {
    	int index;
    
    	printf("\n");
    
    	for (index = 0; index < MAXBOOKS; index++)
    	{
    		if (myBooks[index].flag == 0 || myBooks[index].flag == 2)	// makes deleted and unused records invisible
    			;
    		else
    			printf("%s by %s: $%.2f\n", myBooks[index].title, myBooks[index].author, myBooks[index].value);
    	}
    
    	if (init == 1)
    		puts("\nPress [Enter] to continue.");
    
    	while (getchar() != '\n')		// clears input line
    			continue;
    
    	return init;
    }
    
    
    // ############################################## WRITE TO FILE
    void write_to_file(struct book * myBooks, int filecount, int booksize, int count, FILE * pbooks)
    {
    	rewind(pbooks);		// VITAL to prevent fwrite() from writing the contents of pbooks twice!!!
    	fwrite(&myBooks[0], booksize, count, pbooks);
    }
    V8 Interceptor: KDE 5.25.5 on Manjaro Linux 22.0.0 "Sikaris"
    Steering wheel: gcc 12.2.0 in Kate
    Supercharger: NASM 2.15.05
    Engine: AMD Ryzen 7 1700
    Dashboard: NVIDIA GeForce GTX 1060 6GB
    Rusty old trailer for hauling 3% of my Steam catalog: Windows 7 Pro 64bit SP1
    3 Antique Ford Model T automobiles for vintage LAN gaming: Windows XP SP3
    Sturdy buckboard for DOS LAN gaming: DOSBox 0.74-3 on Windows XP SP3

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 7
    Last Post: 10-09-2009, 06:27 AM
  2. Help with binary file c++
    By lucky_mutani in forum C++ Programming
    Replies: 4
    Last Post: 06-05-2009, 09:24 AM
  3. Inventory records
    By jsbeckton in forum C Programming
    Replies: 23
    Last Post: 06-28-2007, 04:14 AM
  4. Contest Results - May 27, 2002
    By ygfperson in forum A Brief History of Cprogramming.com
    Replies: 18
    Last Post: 06-18-2002, 01:27 PM
  5. behind and confused
    By steviecrawf in forum C Programming
    Replies: 1
    Last Post: 11-09-2001, 12:51 PM