Writing in a binary file - c

My program scans names and birth years and stores them in an array of structures. Scanning from keyboard and printing in screen works fine, but I'm not sure whether printing in my binary file is correct because my program runs without errors and I can't check if the data has been printed correctly in the binary file.
My question is about whether the syntax of my "fwrite" functions is correct.
#include <stdio.h>
#define MAXNAME 50 //size of name
#define MAXPERSONS 2 //Max num of persons
typedef struct{
char name[MAXNAME];
int year;
}person_t;
int read_person(person_t[], int);//scans the person
int write_person(const person_t[], int, FILE*);//prints the persons in the screen and the bfile
int main()
{
FILE *pfile;
person_t v[3];
int iscan=0,iprint;
if((pfile=fopen("persons.bin","wb"))==NULL) printf("couldnt open<vehicles.txt>\n");
else{
while(iscan<MAXPERSONS){
read_person(&v[iscan],iscan+1);
iscan++;
}
for(iprint=0;iprint<iscan;iprint++)
write_person(&v[iprint],iprint+1,pfile);
}
fclose(pfile);
printf("\n\n");
return 0;
}
int read_person(person_t v[],int i)
{
printf("Person %d",i);
printf("\n\tName: ");
fflush(stdin);
gets(v->name);
printf("\n\tYear: ");
scanf("%d",&v->year);
}
int write_person(const person_t v[],int j, FILE *pfile)
{
//print in screen
printf("\nPerson %d",j);
printf("\n\tName: %s\n",v->name);
printf("\n\tYear: %d\n",v->year);
//print in the binary file
fwrite(v->name,sizeof(char),1,pfile);
fwrite(&v->year,sizeof(int),1,pfile);
}
This program reads from the bin file
#include<stdio.h>
#define MAXNAME 50 //size of name
#define MAXPERSONS 2 //Max num of persons
typedef struct{
char name[MAXNAME];
int year;
}person_t;
int read_person(person_t[], int, FILE*);
int write_person(const person_t[], int);
int main(){
FILE *pfile;
person_t v[3];
int iscan=0,iprint;
if((pfile=fopen("persons.bin","rb"))==NULL) printf("couldnt open<vehicles.txt>\n");
else{
while(iscan<MAXPERSONS){
read_person(&v[iscan],iscan+1,pfile);
iscan++;
}
for(iprint=0;iprint<iscan;iprint++)
write_person(&v[iprint],iprint+1);
}
fclose(pfile);
printf("\n\n");
return 0;
}
int read_person(person_t v[],int i, FILE *pfile){
//read from the binary file
fread(v->name, sizeof(v->name),1,pfile);
fread(&v->year,sizeof(v->year),1,pfile);
}
int write_person(const person_t v[],int j){
//print in screen
printf("\nPerson %d",j);
printf("\n\tName: %s\n",v->name);
printf("\n\tYear: %d\n",v->year);
}

Suggest changing fwite() to write the full size of person_t.
int write_person(const person_t v[], int j, FILE *pfile) {
//print in screen
printf("\nPerson %d",j);
printf("\n\tName: %s\n",v[j].name);
printf("\n\tYear: %d\n",v[j].year);
//print in the binary file
if (1 != fwrite(&v[j], sizeof(v[j]),1, pfile)) handle_error();
return 0;
}
int read_person(person_t v[], int i) {
printf("Person %d",i);
printf("\n\tName: ");
// don't do this fflush(stdin);
// consider scanf() gets(v.name);
// " %49[^\n]": space to consume leading whitespace, 49 (50 -1 ) limit input, [^\n] to read any text but \n
if (1 != scanf(" %49[\n]", v[i].name)) handle_error();
printf("\n\tYear: ");
if (1 != scanf("%d",&v[i].year)) handle_error();
return 0;
}

You might consider writing and reading the entire person_t struct.
int write_person(const person_t v[],int j, FILE *pfile)
{
//print in screen
printf("\nPerson %d",j);
printf("\n\tName: %s\n",v[j].name);
printf("\n\tYear: %d\n",v[j].year);
fwrite(&(v[j]),sizeof(person_t),1,pfile);
}
The general idea you are approaching is called 'serialization' or 'marshalling' (depending upon author). There are many ways serialize or marshall data, but some good approaches are JSON, UBJSON, MessagePack, and ProtocolBuffers, among others.

Related

Why fseek does not return a position here, but just redirecting fread to a specific record?

So i basically have a binary input folder containing some students and their information. And i don't understand some things regarding the fseek and fread there after "while" function. After i run it, and type a key to search for a student, it prints the student associated with that key instead of the one on that position (dimension in bytes from the origin as offset). And i want to know why, in order to use the information to my project, as this program is a kind of tutorial from the professor. Thank you in advance!
*EDIT ( Second program is my attempt for the project, but with cars. Its output is the car on position "chooseKey" and not with "chooseKey" as an atribute, as the first program. And i don t know what i did wrong.)
#include <stdio.h>
#include <conio.h>
typedef struct {
int nrm;
char CNP[14];
char nume[30];
int an;
int grupa;
unsigned char note[20];
char is;
} STUDENT;
int filesize(FILE* f, int rec_size)
{
long crt_pos;
int size;
crt_pos = ftell(f);
fseek(f, 0, SEEK_END) ;
size=ftell(f) / rec_size;
fseek(f, crt_pos, SEEK_SET);
return size;
}
void main()
{ char numefr[30] = "Studenti_r_f.dat";
FILE* f;
STUDENT x;
int key, dim;
fopen_s(&f, numefr, "rb+");
dim=filesize(f, sizeof(STUDENT));
printf_s("Enrollment number: ");
scanf_s("%d", &key);
while(key != 0)
{
//check key range
if(key >= dim)
printf_s("\nThere is no student with this enrollment number. Try again?");
else
{
//check if valid key
fseek(f, key*sizeof(STUDENT), SEEK_SET);
fread(&x, sizeof(STUDENT), 1, f);
if(x.is == 0)
printf("\nThere is no student with this enrollment number. Try again?");
else
printf_s("\nStudent: %s, Year: %d, Group: %d, ATP grade: %d\n",x.nume,x.an,x.grupa,x.note[5]);
}
printf_s("\n\nEnrollment number (or 0): ");
scanf_s("%d", &key);
}
fclose(f);
printf("\nDone. Press a key.",numefr);
_getch();
}
typedef struct {
int key;
char color[20];
int price;
char brand[15];
}CAR ;
int sizeOfFile(FILE* inBinFile, int sizeOfRecord)
{
long currentPosition;
int size;
currentPosition = ftell(inBinFile);
fseek(inBinFile, 0, SEEK_END);
size = ftell(inBinFile) / sizeOfRecord;
fseek(inBinFile, currentPosition, SEEK_SET);
return size;
}
void main()
{
FILE * inBinFile;
CAR var;
int chooseKey, fileDim;
printf_s("Type a key to identify a car..."); // 20 records in the file
scanf_s("%d", &chooseKey);
fopen_s(&inBinFile, "Machines.bin", "rb+");
fileDim = sizeOfFile(inBinFile, sizeof(CAR));
while (chooseKey != -1)
{
if (chooseKey >= fileDim)
printf_s("\nNo car with key %d found. Retry.", chooseKey);
else
{
fseek(inBinFile, chooseKey*sizeof(CAR), SEEK_SET);
fread(&var, sizeof(CAR), 1, inBinFile);
printf_s("\nThe %d key indicates to the %s car coloured in %s which cost %d dollars", chooseKey, var.brand, var.color, var.price);
}
printf_s("\n\n\nTo search for another car enter a key, or hit 1 and enter to stop: ");
scanf("%d", &chooseKey);
}
fclose(inBinFile);
printf_s("\nAlright. Press any key...");
_getch();
} ```

Search returning only the first result in structure C

I am trying to read a file and print the records where the jumper has exceeded the distance provided by the user, but the search only returns the first line in the file and that's it, i know there is something wrong in the logic but i cant put my finger on it.
#include<stdio.h>
#include<string.h>
typedef struct {
char fname[30];
char lname[30];
char nationality [30];
double distance;
}Player;
void print(Player p) {
printf("%s %s %s %f \n", p.fname, p.lname, p.nationality, p.distance);
}
int search(double distance, Player allPlayers[], int max){
int i=0;
for(i=0; i<max; i++){
if(distance > allPlayers[i].distance){
return i;
}
return -1;
}
}
void load (char filename[10], Player players[]){
char tempfName [30];
char templName [30];
char tempNationality [30];
double tmpdistance;
FILE * input=fopen(filename,"r+");
if(input==NULL)
printf("Error found in opening the file\n");
else {
printf("The data are loaded successfully.\n");
int counter = 0;
while(!feof(input)){
strcpy(tempfName," ");
fscanf(input, "%s %s %s %f",tempfName, templName, tempNationality, &tmpdistance);
if(strcmp(tempfName, " ") !=0){
strcpy(players[counter].fname, tempfName);
strcpy(players[counter].lname, templName);
strcpy(players[counter].nationality, tempNationality);
players[counter].distance = tmpdistance;
counter++;
}
}
fclose(input);
}
}
int main (int argc, char *argv[]){
Player players2[40];
char myFileName[10] ="jump.txt";
load(myFileName, players2);
double tmpdistance;
printf("Please enter the distance threshold: ");
scanf("%lf", &tmpdistance);
printf("The jumpers exceeded 8.10 m are: \n");
int index = -1;
index = search(tmpdistance,players2,40);
if(index!=-1)
print(players2[index]);
else
printf("NOT Found! \n");
return 0;
}
some sample data from the file I'm trying to read :
Arsen Sargsyan Armenia 7.62
Boleslav Skhirtladze Georgia 7.26
Christian Reif Germany 7.92
Christopher Tomlinson Great_Britain 8.06
In your search() function:
if(distance > allPlayers[i].distance){
return i;
}
This will return the first jumper whose performance is less than the distance provided.
If you replace it with:
if(allPlayers[i].distance > distance){
return i;
}
It will return the first jumper whose performance is greater than the distance provided, which is what you want.
Also:
Don't loop over feof() to read a file: Why is “while ( !feof (file) )” always wrong?
You're printing "The data are loaded successfully" when you haven't loaded the data yet - you've just opened the file
You don't need the arguments to main()
You don't need to initialise index to -1 as you assign it in the next line
You don't need to specify the size of myFileName as the compiler can work it out

Customer data file code in C.Facing issues

The code is supposed to Accept Data,Display the entire data stored till the current execution,Modify or make changes to the already accepted data.
WHAT IM LOOKING FOR IN AN ANSWER:how to write the code for a Modify module?
how to correct the Add or accept data,Display
data so they function perfectly.
#include<stdio.h>
typedef struct
{
int select;
char lastname[25];
char firstname[25];
char address[25];
int phonenumber[25];
} addressbook;
#define ARRAYLEN 2 //The lecturer told to use this "#define ARRAYLEN 2
addressbook a[ARRAYLEN]; //but why 2?and why use ARRAYLEN 2 with define
FILE *fp;
int main() //how is it affecting my program
{
int i;
int c;
int fgetc(FILE *stream);
int fputc(int c,FILE *stream);
fp = fopen("addressbook.dat","a+");
//ADD
for( i=0; i<ARRAYLEN ; ++i)
{
printf("enter details\n");
printf("enter lastname:\n");
scanf("%s", a[i].lastname);
printf("enter firstname:\n");
scanf("%s", a[i].firstname);
printf("enter address:\n");
scanf("%s", a[i].address);
printf("enter phone number:\n");
scanf("%d", a[i].phonenumber);
fwrite(&a[i], sizeof(a), 1, fp); /* notice, array indexed */
};
fclose(fp);
//DISPLAY
fopen("addressbook.dat", "r");
for(i=0; i<ARRAYLEN; ++i)
{
fread(&a[i], sizeof(a), 1, fp );
fgetc;
printf("first name is %s",a[i].firstname);
printf("last name is %s",a[i].lastname);
printf("the address is %s",a[i].address);
printf("the phonenumber is %d",a[i].phonenumber);
};
fclose(fp);
return 0;
}
IMPORTANT NOTE: I use a windows vista os and the compiler is Turbo C++

Load data from file in C

I'm creating a simple C program - employee database... My data are stored in a .txt file, separated by commas and \n, so it looks like this:
data1,id1,name1
data2,id2,name2
What is the best way (in C, not C++) to load all data from the file and every value save as independent variable (e.g. p->data, p->id, p->name)?
This is the code I use to store data into variables (not into the file, variables just for the script):
void insert(emp *p,int n)
{
p=p+n;
printf("\nenter name of emplyee:");
_flushall();
gets(p->name);
printf("\nenter employee id:");
scanf("%d",&p->empid);
printf("\nenter salary of the emplyee:");
scanf("%d",&p->salary);
printf("\nenter phone no of the emplyee:");
flushall();
gets(p->ph);
}
And this script saves data to a file:
void sejv(emp *p,int n)
{
int i;
FILE *fptr;
fptr=fopen("ulozka.txt","w+");
if(fptr==NULL){
printf("Error opening file!");
getchar();
}
printf("Ukladani...");
for(i=0;i<n;i++)
{
fprintf(fptr,"%d,%s,%d,%s\n",p->empid,p->name,p->salary,p->ph);
p=p+1;
}
fclose(fptr);
exit(0);
}
All I need is to load the data to the main function so I can work with it.
EDIT:
I'm adding the rest of my code:
typedef struct employee
{
char name[20],ph[20];
int empid,salary;
}emp;
void main()
{
emp e;
emp *p;
int n=0,ch;
p=&e;
}
And "something" from the function I need to create...
void nacti(emp *p,int n)
{
int i;
FILE *fptr;
fptr=fopen("ulozka.txt","r");
if(fptr==NULL){
printf("Error opening file!");
getchar();
}
printf("Nacitani...");
//loading function
p=p+n;
fscanf(fptr,"%d,%[^\,],%d,%s", &p->empid, p->name, &p->salary,p->ph);
printf("%s", p->name);
}
I need a function that would read the data from the txt file by collumns and rows (a loop that would add the data from the first row to a p, then increase the value of p by 1, insert data from the second row and so on...)
Thank you for any advice...
Check the below code it can be done ad shown below:
struct data
{
int index;
int id;
char name[30];
};
int main ()
{
struct data p[3];
int i=0;
FILE *fp = fopen("input.txt","r+");
while(fscanf(fp,"%d,%d,%s",&p[i].index,&p[i].id,p[i].name) != EOF)
{
i++;
}
i=0;
while(i<3)
{
fprintf(fp,"%d %d %s\n",p[i].index,p[i].id,p[i].name);
i++;
}
fclose(fp);
}

Why can't I input a filename for opening in c?

I have been attempting to debug this program with my limited knowledge, and have compared it with other programs in which i've used the same methods to retrieve a filename for opening. However, it seems that for some odd reason the program does not recieve user input for filename, sometimes getting caught in some sort of an elusive loop.
I have used both:
scanf("%s\n", filename);
and:
gets(filename);
(i know gets is "dangerous" but this is a program that is not going to be distributed, it is an assignment in a college level class)
here is the main() function and the getssn() function (which does get user input successfully):
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAXS 19
#define MAXR 999
//structure defining a given client
typedef struct person {
unsigned int ssn, age, height, weight, income;
char name[MAXS+1], job[MAXS+1], religion[MAXS+1], major[MAXS+1], minor[MAXS+1], gender;
}PERSON;
//get and check for ssn validity
int getssn(){
int num;
printf("\nSSN: ");
scanf("%d", &num);
if(num<=99999999 || num>999999999){
printf("\nPlease input a valid SSN.\n");
return 0;
}
else
return num;
}
//read the specified file and check for the input ssn
int readfile(FILE *fptr, PERSON **rptr, int *count){
int v=0, i, j;
char n2[MAXS+1], b[2]=" ";
for(i=0; i<MAXR; i++){
j=i;
//read the file in chunks
if(fscanf(fptr, "%c\n%d\n%19s %19s\n%d\n%19s\n%d\n%19s\n%19s\n%d\n%d\n%19s\n\n",
&rptr[j]->gender, &rptr[j]->ssn, rptr[j]->name, n2, &rptr[j]->age,
rptr[j]->job, &rptr[j]->income, rptr[j]->major, rptr[j]->minor,
&rptr[j]->height, &rptr[j]->weight, rptr[j]->religion)==EOF)
i=MAXR;
//make first and last name one element
strcat(rptr[j]->name, b);
strcat(rptr[j]->name, n2);
//if we find a match, tell main the id
if(rptr[MAXR]->ssn==rptr[j]->ssn)
v=j;
}
//count how many clients we have
*count=j;
return v;
}
//commpare age and income
int cmpai(PERSON rec1, PERSON rec2){
int a=0, inc=0;
if(rec1.age<=(rec2.age+10) && rec1.age>=(rec2.age-10))
a=1;
if(rec1.income<=(rec2.income+10000) && rec1.income>=(rec2.income-10000))
inc=1;
if(a==1 && inc==1)
return 1;
else
return 0;
}
//compare hobbies
int cmph(PERSON rec1, PERSON rec2){
if(strcmp(rec1.major,rec2.major)==0 && strcmp(rec1.minor, rec2.minor)==0)
return 1;
else
return 0;
}
//compare weight, height, and religion
int cmpwhr(PERSON rec1, PERSON rec2){
int w=0, h=0, r=0;
double n1, n2;
n1=rec1.height;
n2=rec2.height;
if(n1<=(n2*1.1) && n1>=(n2*0.9))
h=1;
n1=rec1.weight;
n2=rec2.weight;
if(n1<=(n2*1.1) && n1>=(n2*0.9))
w=1;
if(strcmp(rec1.religion, rec2.religion)==0)
r=1;
if(r==1 && h==1 && w==1)
return 1;
else
return 0;
}
//sort the ids in ascending order by ssn for proper output
void sort(int *A, int count){
int i, j, temp;
for(i=0; i<count; i++)
for(j=0; j<count; j++)
if(A[i+1]<A[i]){
temp=A[i];
A[i]=A[i+1];
A[i+1]=temp;
}
}
//display the possible matches in ascending ssn order
void display(int matches[], PERSON rec[], int count){
int i;
for(i=0; i<count; i++){
if(matches[i]==rec[i].ssn)
printf("%s\n", rec[i].name);
}
}
int main(){
int valid=-1, i, counter=0, *c=&counter, id[MAXR-1], totalmatches;
char filename[MAXS];
FILE *fp;
PERSON record[MAXR+1], *rp[MAXR+1];
//get a ssn from the user
do{
record[MAXR].ssn=getssn();
}while(record[MAXR].ssn==0);
//get a filename
printf("Name of file of records: ");
scanf("%s", filename);
printf("%s", filename);
//open the file, if possible
if((fp=fopen(filename, "r"))==NULL)
perror(filename);
else{
printf("test");
for(i=0; i<=MAXR; i++){
rp[i]=&record[i];
id[i]=0;
}
//read the file, find the matching ssn
valid=readfile(fp, rp, c);
//check if the ssn is in the file, if not tell the user
if(valid<0){
printf("\nSSN %d is not found in file %s.\n", record[MAXR].ssn, filename);
return EXIT_FAILURE;
}
else {
//check for matches and count how many we have
for(i=0; i<counter; i++){
if(i!=valid)
if(record[valid].gender!= record[i].gender)
if(cmpai(record[valid], record[i])==1 || cmph(record[valid], record[i])==1 || cmpwhr(record[valid], record[i])==1){
id[i]=record[i].ssn;
totalmatches+=1;
}
}
//if we have matches sort them and display them, otherwise tell the user he has no match in this group
if(totalmatches>0){
sort(id, counter);
display(id, record, counter);
}
else
printf("\nNo matches.\n");
fclose(fp);
return EXIT_SUCCESS;
}
}
}
This is the current input(single quotes)/output:
run
[Switching to process 6956]
Running…
SSN: '111223333'
Name of file of records: 'clients.txt'
clients.txttest
Debugger stopped.
Program exited with status value:0.
You should your getssn() function. You need to put in a return statement.
int getssn(){
int num;
printf("\nSSN: ");
scanf("%d", &num);
return num; // You MUST put this in.
}
This will improve this code:
do{
record[MAXR].ssn=getssn();
}while(record[MAXR].ssn==0);
If you forget the return, then getssn() might return 0 forever.
You should also tell us what exact output you are seeing. You should copy all the output into your question also.
Never use any of the scanf family of functions; they don't give you nearly enough control over what happens on invalid input, and scanf("%s") is just as dangerous as gets.
But this is probably not your immediate problem. That's much more likely to be a case of trying to open a file by partial pathname when it's not in the current working directory. Try typing in the full pathname (/home/kabir/filename, C:\users\kabir\filename, sort of thing). Also, changing
printf("\nCould not open file\n");
to
perror(filename);
will give you more information when things go wrong.
It should be
scanf("%s", filename)
i.e. remove the \n
Unrelated, but you seem to have forgotten return num at the end of getssn().
Looking at your current code (8:10 pm Dublin/London time), you should use this instead:
//get a filename
printf("Name of file of records: ");
//scanf("%s", filename);
printf("scanned file: <%s>\n", filename);
//open the file, if possible
if((fp=fopen(filename, "r"))==NULL)
perror(filename);
else{
printf("test\n");
...

Resources