3

The program should modify or delete a specific record according to employee id, in modifying part it writes the modified record as a new one at the end of the file, the deleting part works only once and then give me a segmentation fault.

Modifying:

How can I modify the code to rewrite the edited record in the same position?

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

struct record_em{
    int id;
    char name[20];
    int salary;
    int age;
};

int main( void )
{
    struct record_em employee;
    FILE *fp;
    int n;
    int ch;
    fp = fopen("empRecord.dat","rb+");

    printf("Enter Id Number:\n");
    scanf("%d",&n);
    rewind(fp);
    while (!feof(fp)){

        fscanf(fp,"%d %s %d %d", &employee.id, employee.name, &employee.salary, &employee.age);

        if (employee.id==n){
            printf("%d %s %d %d \n",employee.id, employee.name, employee.salary,employee.age);
            printf("\n Do you want to change the name ?\n");
            scanf("%d",&ch);

            if (ch==1){
                printf("Enter new name:\n");
                scanf("%s",employee.name);
            }
            printf("\n Do you want to change the salary ?(y/n)\n");
            scanf("%d",&ch);

            if ( ch==2 ){
                printf("Enter new salary:\n");
                scanf("%d",&employee.salary);
            }
            printf("\n Do you want to change the age ?(y/n)\n");
            scanf("%d",&ch);

            if ( ch==3 ){
                printf("Enter new age:\n");
                scanf("%d",&employee.age);
            }
            fseek(fp,-sizeof(employee),SEEK_CUR);
            fprintf(fp, "%d %s %d %d\n", employee.id, employee.name, employee.salary, employee.age);
            exit(0);
        }
    }
    printf("Record Not Found \n");
    return 0;
}

Deleting:

How can I modify the code to make it delete records as many times as I want?

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

struct record_em{
    int id;
    char name[20];
    int salary;
    int age;
};

int main()
{
    struct record_em employee;
    FILE *fp, *ft;
    int n;
    fp = fopen("empRecord.dat","r");
    ft = fopen("Temp.dat","wb+");

    printf("\nEnter ID of employee to delete ");

    scanf("%d",&n);
    rewind(fp);
    while (!feof(fp)){
        fscanf(fp,"%d %s %d %d", &employee.id, employee.name, &employee.salary,  &employee.age);

        if(employee.id!=n){
            fprintf(ft, "%d %s %d %d\n", employee.id, employee.name, employee.salary, employee.age);
        }
    }

    fclose(fp);
    fclose(ft);
    remove("empRecord.dat");
    rename("Temp.dat","EempRecord.dat");

    return 0;
}
Sam
  • 7,252
  • 16
  • 46
  • 65
fatimah
  • 119
  • 2
  • 4
  • 13
  • You can save the offset of information block and overwrite the changed data from that offset.Check fseek(). – Amir Naghizadeh Nov 24 '12 at 10:11
  • @tAmirNaghizadeh Um. no he can't. This record definition, though fixed in the `struct` of his code, is variant by how he is writing it to disk (because it is text translation). Make the string-representation of *any* of those fields larger than the prior, and you're overwriting data in at least one subsequent record. – WhozCraig Nov 24 '12 at 10:15
  • Right..,Since record separated by newline , he can use `strcmp()` on first recode in each line reported by `getline()`. – Amir Naghizadeh Nov 24 '12 at 10:28
  • @AlbertoBonsanto im trying to avoid using them because its something new that i do not take it in this course, i will try to use binary files, if they do not work well i will use the formatted file, Thanks a lot :) – fatimah Nov 24 '12 at 21:02

4 Answers4

3

Here is the Key point of code:

void update(char filename[],char name[])
{
    int records=0;
    FILE *fp = fopen(filename,"rb+");
    while(fread(&st,sizeof(st),1,fp)==1)
    {
         if(strcmp(name,st.name)==0)
         {
              printf("\nEnter new name: ");
              scanf("%s",st.name);
              printf("\nEnter new roll no.: ");
              scanf("%d",&st.roll);
              fseek(fp,sizeof(struct student)*records,SEEK_SET);//This is key line..
              fwrite(&st,sizeof(st),1,fp);
         }
         records++; // in the while loop...
    }
    fclose(fp);
}

Below is the structure of student:

struct student{
     int roll;
     char name[20];
}st;

This is the general method to modify/update the record. You can use same syntax for your employee structure.

Sam
  • 7,252
  • 16
  • 46
  • 65
Sachin Kumar
  • 781
  • 1
  • 9
  • 28
1

It's not good to manipulate a binary file using the C functions that are intended to be used to manipulate text files fprintf.

For example, in your code I see:

fseek(fp,-sizeof(employee),SEEK_CUR);
fprintf(fp, "%d %s %d %d\n", employee.id, employee.name, employee.salary, employee.age);

This will bring you problems, since you are traveling within your file as a binary file to then write characters on it. You shoud use the fwrite function instead.

My recommendation: check your whole program, define your persistence strategy and be consistent with this.

Hernan Velasquez
  • 2,770
  • 14
  • 21
  • when i use fwrite i can not have a plain text file – fatimah Nov 24 '12 at 10:25
  • @fatimah It is the variability of the text-content of your values that is making this task a bigger chore than it needs to be. Using a fixed binary record length would make scanning records, modifying them in-place, and marking them as deleted *trivial*. – WhozCraig Nov 24 '12 at 10:48
  • @WhozCraig i will try to use a fixed binary record and see what will happen :) ,, thanks a lot – fatimah Nov 24 '12 at 17:08
1

I think here is your problem, first you have a minus sign before the sizeofit's a bit weird to see that, and second the SEEK_CUR makes you move further than your current file is so take a look here fseek(), rewind()

fseek(fp,-sizeof(employee),SEEK_CUR); //This is not the definitive read below.
         ^------minus symbol.  ^------- the type of seek.

I recommend You to do some modifications:

  1. Use a common Formatted File to make your life easier, remember "The perfection is the simplicity".

  2. Use SEEK_SET to use the relative position from the beginning of the file, second use the struct's size as the parameter for sizeof.

    fseek( fp, sizeof( struct record_em), SEEK_SET );
    
  3. Use the member id as the key of your sink and use a consecutive series of numbers, but obviously you should have created a file with 100, 1000 employers.

    1 Andrew 20000 27
    ^   ^      ^    ^_____ age 
    |   |      |__________ salary ( I would have used double here)
    |   |_________________ name
    |_____________________ id ( Key for the relative position from the beginning)
    
  4. You will have to change your mind, and when you imagine "delete" a record you will write a white space (with exception of the key) example Imagine that the poor Andrew was fired and you will delete his record.

    1 "Empty space"   0   0
    ^       ^         ^   ^______ age (0 = nothing)
    |       |         |__________ salary (0 = nothing)
    |       |____________________ name ("" = nothing)
    |____________________________ id ( Key for the relative position from the beginning)
    

PD:currently adding more information.

Alberto Bonsanto
  • 17,556
  • 10
  • 64
  • 93
  • The OP's use of `fseek(fp,-sizeof(employee),<>);` to "rewind" is completely wrong. He is using variable-length "records" by writing their "text" content using unframed (no fixed widths) formatted output and input. `1 Al 25000 20\n` is nowhere near the length of `12345 Washington 125000 42\n`, yet that is how his "records" are represented. Moving around by increments of `sizeof(employee)` would make sense if he were using fixed records, **but he is *not***. This makes the job of finding, modifying, and deleting a specific record by `id` a major undertaking. – WhozCraig Nov 24 '12 at 11:26
1
SEEK_CUR

offset is relative to the current file pointer position. So, in effect, you can say, "Move to my current position plus 30 bytes," or, "move to my current position minus 20 bytes." eg. fseek(fp, -30, SEEK_CUR) ref. http://beej.us/guide/bgc/output/html/multipage/fseek.html

I don't think he is wrong in using the negative of the sizeof() function. But you would be better off using the sizeof(struct record_em) instead!

dustin
  • 4,309
  • 12
  • 57
  • 79
Swaathi Kakarla
  • 2,227
  • 1
  • 19
  • 27