Home > Enterprise >  Sequential search in a binary file
Sequential search in a binary file

Time:08-21

I need to find the costumer register that is stored in a binary file using his code, as it is definide on the structure above.

typedef struct Employee{
    int code;
    char name[30];
    char cpf[11];
    char birthday[11];
    double wage;
}TEmployee;

There are 100 registers of the struct above stored in a binary file, and i have to use a sequencial search to find a employee by passing his code as a parameter to the search function. Above is the function i´m currently working on. Can you guys give me some help to make this work? The output is always that the employee was not found.

TEmployee *sequencial_search(int code, FILE *file) {
    int i = 0;
    while (i < 100) {
        fseek(file, sizeof(struct Employee), SEEK_SET);
        TEmployee *emp = read(file);
        if (code == emp->code) {
            return emp;
        }
        i  ;
    }   
    return NULL;
}

read function

TEmployee *read(FILE *in) {
    TEmployee *emp = (struct Employee *) malloc(sizeof(struct Employee));
    if (fread(&emp->code, sizeof(int), 1, in) <= 0) {
            free(emp);
        return NULL;
    }

    fread(emp->name, sizeof(char), sizeof(emp->name), in);
    fread(emp->cpf, sizeof(char), sizeof(emp->cpf), in);
    fread(emp->birthday, sizeof(char), sizeof(emp->birthday), in);
    fread(&emp->wage, sizeof(double), 1, in);

    return emp;
}

main

FILE *file = fopen("prova1.dat", "wb ");
TEmployee *emp = sequencial_search(8, file);

if (emp != NULL) {
        printf("### EMPLOYEE REGISTER FOUND!!! ### \n\n");
        printf("Code: %d \n", emp->code);
        printf("Name: %s \n", emp->name);
        printf("Cpf: %s \n", emp->cpf);
        printf("Birthday: %s \n", emp->birthday);
        printf("Wage: %.2f \n", emp->wage);
    } else {
        printf("Employee register not found! \n");
        return 1;
    }

free(emp);
fclose(file);

CodePudding user response:

Problems:

Size

Size of struct differs from the sum of the size of its members due to padding.

Instead, read a whole struct.

TEmployee *read(FILE *in) {
  TEmployee *emp = malloc(sizeof *emp);
  if (emp) {
    if (fread(emp, sizeof *emp, 1, in) <= 0) {
      free(emp);
      return NULL;
    }
  }
  return emp;
}

Quitting too early

If code == emp->code is false, function returns. Better to keep going until emp == NULL or code == emp->code.

Memory leak

Make sure a free(emp) occurs for each malloc().

Why seek?

fseek(file, sizeof(struct Employee), SEEK_SET); not needed. @kaylum

Others?

Other issues may exist.


Tip: size to the object, not the type.

CodePudding user response:

Rather than attempting to write a line-by-line review of the code, it is less confusing to provide an annotated example of what would achieve your objective. "Don't do this" and "do that this way" can lead to misunderstandings and frustration.

I hope the following is easy to follow, and points you toward your objective.

Before getting into it, though, you need to be aware that "not all ints are ints" (same, too, for floating point numbers). First off is the difference between 32bit and 64 bit hardware these days. Very old compilers considered int to be 16bits. Secondly is the Big Endian vs Small Endian nature of hardware. It may not be safe to presume that this binary file is what it seems to be.

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

typedef struct { // no need for "Employee" token in this source
    int code;
    char name[30];
    char cpf[11];
    char birthday[11];
    double wage;
} TEmployee;

int sequencial_search( char *, int, TEmployee * ); // forward declaration

// main() uses a function to retrieve a single record (or fail to find it)
// prints out info if target record found

int main() {
    char *fname = "prova1.dat";  // filename should be prominent
    int findCode = 8; // target record ID should be prominent

    TEmployee emp; // 'record' buffer to use

    // pass file name, the 'target', and a buffer to be filled in (or not).
    // function returns 0 for failure to open file or find record
    if( !sequencial_search( fname, findCode, &emp ) ) {
        printf( "Employee register not found! \n" );
        return 1;
        // early exit if failed saves one level of indent
    }

    // function succeed, so show what was found
    printf( "### EMPLOYEE REGISTER FOUND!!! ### \n\n" );
    printf( "Code: %d\n", emp.code );
    printf( "Name: %s\n", emp.name );
    printf( "Cpf: %s\n", emp.cpf);
    printf( "Birthday: %s\n", emp.birthday );
    printf(" Wage: %.2f\n", emp.wage );

    return 0;
}

// returns 1 if found and passed buffer valid, or 0 if not found
int sequencial_search( char *fname, int code, TEmployee *emp ) {

    FILE *fp = fopen( fname, "rb" ); // open file here, and ensure it is closed later

    // always test for failure (bad filename, for instance)
    if( fp == NULL ) {
        fprintf( stderr, "Cannot open %s\n", fname );
        return 0;
        // again, "early return" if cannot proceed
    }

    int found = 0; // an int 'flag' set to 1 if record found

    // read in complete single records
    // let fread() determine how many records it can find
    while( !found && fread( emp, sizeof *emp, 1, fp ) == sizeof *emp )
        found = emp->code == code; // set flag true (1) if this record satisfies

    // found or not, close the file
    fclose( fp );

    return found;
}

I don't have your dataset, so cannot fully test that this is correct.

  • Related