how to store and read data from files - c

I am new to C in linux. I am trying to store data to file and read them back. Is this the correct way. When I try to compile this i am getting errors. Can anyone help me please. thanks in advance.
#include<stdio.h>
typedef struct
{
int select;
char lastname[25];
char firstname[25];
char address[25];
char phonenumber[25];
} addressbook;
addressbook a[5];
FILE *fp;
int main()
{
int i;
for( i=0; i<5 ; 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("%s", a[i].phonenumber);
fp = fopen("addressbook.dat","a+");
fwrite(&a, sizeof(a), 1, fp);
fclose(fp);
}
for(i=0; i<5; i++)
{
fopen("addressbook.dat", "r");
fread(&a, sizeof(a), 1, fp );
printf("lastname:%s\n", a[i].lastname);
printf("firstname:%s\n", a[i].firstname);
printf("address:%s\n", a[i].address);
printf("phonenumber:%s\n", a[i].phonenumber);
fclose(fp);
}
return 0;
}
i am not getting any output. it was blank.

Check out this code, and let me explain you what all was wrong in your code.
#include<stdio.h>
typedef struct
{
int select;
char lastname[25];
char firstname[25];
char address[25];
char phonenumber[25];
} addressbook;
#define ARRAYLEN 2
addressbook a[ARRAYLEN];
FILE *fp;
int main()
{
int i;
fp = fopen("addressbook.dat","a+");
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("%s", a[i].phonenumber);
fwrite(&a[i], sizeof(a), 1, fp); /* notice, array indexed */
}
fclose(fp);
fopen("addressbook.dat", "r");
for(i=0; i<ARRAYLEN; i++)
{
fread(&a[i], sizeof(a), 1, fp );
printf("lastname:%s\n", a[i].lastname);
printf("firstname:%s\n", a[i].firstname);
printf("address:%s\n", a[i].address);
printf("phonenumber:%s\n", a[i].phonenumber);
}
fclose(fp);
return 0;
}
Actually, your code as-is (apart from the edit you've already done) isn't so incorrect, but it had some small yet crucial flaws.
The only real change is this :-
fwrite(&a[i],...
and,
fread(&a[i],...
i.e. pass the address of the particular array-element that you want to write, not the entire array. Also, even though you were passing address of the entire array, the no. of byte/characters you were asking library to write, was just sizeof(thestructure), so essentially the remaining was truncated. Without that, what you were writing into the file was something like...
A <-- file contents after, first iteration
AAB <-- file contents after, second iteration
AABABC <-- file contents after, third iteration
AABABCABCD <-- file contents after, fourth iteration
....
I think you'd figure out from that, what was wrong. Also the contents of your addressbook.dat was text, so a simple "cat addressbook.dat" (on Linux) would have told you what was wrong :-)
You are opening and closing file in every iteration. Now this is not an error, but just a sub-optimal thing, and quite likely to be something you do not want to do. File operations are costly, and opening/closing those cost quite a few CPU cycles. You are better off, opening file once for all writes, and once for reads. (Of course, once can remove the fclose() done after write-block and fopen() done before read-block as well, by just getting the file-pointer to the beginning of file -- left as an exercise for you).
While testing, no one wants to enter so much data. So I've added a #define (and with a newer compiler you can replace it with a const definition as well), that defines a macro which holds the addressbook array size. For testing, I keep it at "2". For production you can just change that value to "1000" and it will still work. Again, this wasn't an error, just a better style, if you will.
Oh, and BTW, pls get your indentation right. Are you coming from Python world ? Or it could be an artifact of the indentation required by SO for posting code-blocks.
HTH

It seems to me that you are not including the required headers. For example, printf requires stdio.h, so at the beginning for your file, you will need
#include <stdio.h>
CPlusPlus.com provides pretty good and easy to search documentation for C, so if you wish to use a function, you can look it up and find out which header is required.

Related

Save a struct into a file then read it in the same program

I have this struct which I stack with information, I'm doing that via pointers, after doing that I'm saving all the info into a file named person.txt and then read it in the same program.
The problems I'm having are:
I can display the final result correctly, but, the person.txt file doesn't have any meaningful text in it, it's just a bunch of unknown symbols for me (I guess it's automatically saved in bit, but I don't know why it does that).
After inserting the info and the .txt file is created and the result is displayed, after closing the program, when trying to use only the code to read the file (meaning I make a commentary out of the code I won't need), it displays me something else, totally different of what I initially introduced.
Heres the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct eu
{
char name[30];
int age,weight, number;
};
int main()
{
struct eu *Eu1, euptr;
Eu1 = &euptr;
printf("Name & Surname:");
scanf("%[^\n]", Eu1->name);
printf("\n");
printf("Age:");
scanf("%d", &Eu1->age);
printf("\n");
printf("Weigt(kg):");
scanf("%d", &Eu1->weight);
printf("\n");
printf("Telephone number:");
scanf("%d", &Eu1->number);
printf("\n\nDisplay: ");
FILE *outinfo;
outinfo = fopen("person.txt", "a");
if (outinfo == NULL)
{
fprintf(stderr, "\nSomething went wrong!\n");
}
fwrite(&Eu1, sizeof(struct eu),1,outinfo);
fclose(outinfo);
outinfo = fopen("person.txt", "r");
while(fread(&Eu1, sizeof(struct eu), 1, outinfo))
printf ("\n Name:%s\n Age:%d\n Weight:%d\n Tel. Number:%d\n ", Eu1->name, Eu1->age, Eu1->weight, Eu1->number );
fclose (outinfo);
return 0;
}
you've messed the pointers. It is ok to save whole struct into the file, here is correctly working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct eu
{
char name[30];
int age,weight, number;
};
int main()
{
struct eu eu1, *euptr;
euptr = &eu1;
printf("Name & Surname:");
scanf("%[^\n]", euptr->name);
printf("\n");
printf("Age:");
scanf("%d", &euptr->age);
printf("\n");
printf("Weigt(kg):");
scanf("%d", &euptr->weight);
printf("\n");
printf("Telephone number:");
scanf("%d", &euptr->number);
printf("\n\nDisplay: ");
FILE *outinfo;
outinfo = fopen("person.txt", "a");
if (outinfo == NULL)
{
fprintf(stderr, "\nSomething went wrong!\n");
}
fwrite(euptr, sizeof(struct eu), 1, outinfo);
fclose(outinfo);
outinfo = fopen("person.txt", "r");
while(fread(&eu1, sizeof(struct eu), 1, outinfo))
printf ("\n Name:%s\n Age:%d\n Weight:%d\n Tel. Number:%d\n ", euptr->name, euptr->age, euptr->weight, euptr->number );
fclose (outinfo);
return 0;
}
I've swapped eu1 & euptr variables for more logical naming.
fwrite will write the raw data you have given it, for the number of bytes you have specified. You are able to write this struct and read it back which is exactly what you are trying to do, all is working as intended. "Normal" text files with words use a particular encoding (usually ascii or unicode), and you need to use that encoding if you want it to be readable.
If you wanted this to be human readable, you would need to specify a format. A very simple one would be CSV (comma separated values).
So you might do something like
fprintf(outinfo, "%s,%d,%d,%d", Eu1.name, Eu1.age, Eu1.weight, Eu1.number);
//...
fseek(outinfo,0,SEEK_SET);// move to beginning of file
fscanf(outinfo, "%s,%d,%d,%d", &Eu2.name, &Eu2.age, &Eu2.weight, &Eu2.number);
this doesn't involve any error checking, and would need to be changed if your struct format changed, but would allow the file to be human readable if that was a requirement for you.

How to count number of line from binary file for C programming

typedef struct {
int ID;
char name[30];
char position[20];
char department[20];
char password[10];
int contactnumber;
int age;
char emailaddress[30];
}admin;
admin info;
void registration() {
int count=1001,y;
FILE* Admin;
Admin = fopen("Admin_info.bin", "ab");
if (Admin == NULL) {
printf("Unable to open file");
}
printf("\tPlease insert your informantion below\n");
printf("\tID: ");
scanf("%d", &info.ID);
printf("\n\tName: ");
scanf("%s", &info.name);
printf("\tPosition: ");
rewind(stdin);
scanf("%s", &info.position);
printf("\tDepartment: ");
scanf("%s", &info.department);
printf("\tPassword: ");
scanf("%s", &info.password);
printf("\tContact Number: ");
scanf("%s", &info.contactnumber);
printf("\tAge: ");
scanf("%d", &info.age);
printf("\tEmail Address: ");
scanf("%s", &info.emailaddress);
fwrite(&info, sizeof(admin), 1, Admin);
}
*I wanted to auto generate the ID. Therefore, I need to read the number of line from binary file and add by 1 and I don't know how to read the number of line. Please someone help me
You should've mentioned that it's about the file you are writing to. And there are no actual lines, since you are writing binary data to it.
You could first open the file in rb mode, fseek with 0, SEEK_END, ftell to get the file size in bytes, close it again, then divide the file size by sizeof(admin) to get your ID. Then apply your code.
EDIT after comment by chux:
It is not necessary to first open the file in rb mode and close it, as I had suggested. It is sufficient to leave it open in ab mode as done in your code and just add the fseek and ftell. Depending on the system, even the fseek is not required, but this seems not to be guaranteed by the standard.
I just found a very much related question here: Problems getting ftell() in binary append

How to read a specific line from binary file into a structure C

Essentially, I printed to a binary file using fseek() and fwrite(). However, I want to read the contents from a specific line into a structure. I also used fseek() and fread() to obtain the contents. I prompted the user to enter a code. From what I have learnt, I would use the value obtained from the user to use in the fseek function to get the specific line to start read from. Apparently, the fseek to read the contents does not work, I am getting gibberish essentially when it is displayed on the screen. Assistance is greatly appreciated.
#include <conio.h>
#include <stdio.h>
typedef struct registered
{
int compcode;
char compname[20];
int pinID;
int custID;
char IDtype[15];
int compID;
}REGISTERED;
void AddUpdate(REGISTERED info);
void SellPetrol();
void main(){
REGISTERED info = {0, "Apple", 0, 0, "passport", 0};
REGISTERED list;
AddUpdate(info);
SellPetrol();
}
void AddUpdate(REGISTERED info){
int choice;
FILE *registryfile = NULL;
registryfile = fopen("Sales.dat", "ab");
if (registryfile == NULL){
perror("Error: ");
}
else{
do{
printf("Company Code: ");
scanf("%d", &info.compcode);
printf("Company Name: ");
scanf("%s", &info.compname);
printf("Pin: ");
scanf("%d", &info.pinID);
printf("Customer ID: ");
scanf("%d", &info.custID);
printf("ID type: ");
scanf("%s", &info.IDtype);
printf("Company ID: ");
scanf("%d", &info.compID);
fseek(registryfile, (info.compcode - 1) * sizeof(REGISTERED), SEEK_SET);
fwrite(&info, sizeof(REGISTERED), 1, registryfile);
printf("Enter choice: ");
scanf("%d", &choice);
}while(choice == 1);
}
printf("\tCompany Code: %d\t\n", info.compcode);
printf("\tCustomer ID: %d\t\n", info.custID);
fclose(registryfile);
}
void SellPetrol(){
int code = 0, PIN;
REGISTERED list;
FILE *registryfile = NULL;
registryfile = fopen("Sales.dat", "rb");
if (registryfile == NULL){
perror("Error: ");
}
else{
printf("Please enter the company code: ");
scanf("%d", &code);
// printf("Please enter the PIN: ");
// scanf("%d", &PIN);
rewind(registryfile);
fseek(registryfile, (code - 1) * sizeof(REGISTERED), SEEK_SET);
fread(&list, sizeof(REGISTERED), 1, registryfile); //reads data into list
fflush(stdin);
printf("Company Code: %d\n", list.compcode);
printf("Company Name: %s\n", list.compname);
printf("Pin: %d\n", list.pinID);
printf("Customer ID: %d\n", list.custID);
printf("ID Type: %s\n", list.IDtype);
printf("Company ID: %d\n", list.compID);
}
fclose(registryfile);
}
It seems whichever method you're using to learn C is causing troubles, as the mistakes you seem to be making are common. I suggest reading a book, such as K&R2E... Do the exercises as you stumble across them; don't move on until you've completed them, and ask questions about them if necessary.
Don't fflush(stdin). fflush doesn't do what you think it does.
Check return values for functions such as fopen, scanf, fseek, fread, even fwrite. You'll probably find that your fread or scanf is returning a value indicating failure, hence the gibberish you speak of.
Be aware that C uses pass-by-value semantics ONLY. The source of at least one error in your code is a misunderstanding regarding these semantics. Namely, AddUpdate has no way to modify the variable declared within main, as it recieves a copy of that variable; at this point it seems void AddUpdate(REGISTERED info) should be void AddUpdate(void) and info should be declared within AddUpdate.
scanf("%s", &info.compname); probably doesn't do what you think it does. The %s directive tells scanf to read (metalinguistically speaking) a word (that is, a whitespace-delimitered token), not a line (a newline delimitered token), of user input. You probably want int x = scanf("%19[^\n]", info.compname); or better yet, char *x = fgets(info.compname, sizeof info.compname, stdin);...
void main() is unportable, and so is #include <conio.h>. You probably want int main(void) and ... you don't appear to be using any functions from <conio.h>, so you probably don't want anything in place of that. In C99, a main function that has no return statement will implicitly return 0; without a warning issued.

Fwrite doesn't work properly

Sorry for having this program in my native language, but I really can't seem to find why it doesn't work. So, I tested and the values of the a array are all correctly read, but when I try to look at the .dat file there is only the first word read in the for function ( a[0].marca ).
Here is the input I also tested to see if it reads correct
Here is the .dat file It only writes the first
#include <stdio.h>
#include <stdlib.h>
struct data
{
int anul;
int luna;
};
typedef struct data DATA;
struct automobil
{
char marca[20];
char carburant;
char model[5];
DATA fabricatie;
};
typedef struct automobil AUTOMOBIL;
int main()
{
AUTOMOBIL a[100];
int n;
FILE *f;
int i;
if((f=fopen("evidenta.dat","wb"))==NULL)
{
exit(1);
}
printf("Cate automobile sunt ?"); scanf("%d",&n); // The number of cars registered
for(i=0;i<n;i++) // getting the details about every car
{
printf("\nMarca ? : "); fflush(stdin); gets(a[i].marca);
printf("\nCarburant ? : "); fflush(stdin); getch(a[i].carburant);
printf("\nModelul? :"); fflush(stdin); gets(a[i].model);
printf("\nLuna fabricatie ? :"); scanf("%d",&a[i].fabricatie.luna);
printf("\nAn fabricatie ? : "); scanf("%d",&a[i].fabricatie.anul);
// After getting a line it has to write it in the binary file
fwrite(&(a[i]),sizeof(AUTOMOBIL),1,f); //It writes only a[0].marca
}
for(i=0;i<n;i++)
{
printf("\n %s",a[i].marca);
printf("\n %c",a[i].carburant);
printf("\n %s",a[i].model);
printf("\n %d",a[i].fabricatie.luna);
printf("\n %d",a[i].fabricatie.anul);
}
return 0;
}
You have to do it this way:
fwrite(&(a[i]),sizeof(AUTOMOBIL),1,f);
Alternatively you can do that outside the loop:
fwrite(a,sizeof(AUTOMOBIL),n,f);
Also don't forget to fclose.
As the others answer say you need to write to &a[i]. If you want to see the contents of the file in the moment is written, you need to disable output buffer with setbuf(f, NULL) or flush it each time you write with fflush(f).
It's because you write the first item each time - &a while expecting &(a[i]) to be written.
And do not forget to fclose the file after writing for the buffer not to be lost.
If you want to see the live changes on the file while you write, you need to disable output buffer setbuf(f,NULL) or flush it fflush(f).

Saving files into a structure

I've got a program in which I would like to read and save data into. Ideally I would like to read the data, be able to display and make changes to the data, and then be able to save it back onto another file if needed. Right now I have it to where I can read the data, but I can't make changes or save the content to another file. I'll spare you from posting my entire code, since it's rather lengthy, but here is my structure, main function, menu function and read function.
typedef struct friends_contact{
char *First_Name;
char *Last_Name;
char *home;
char *cell;
}fr;
int main() {
fr friends[5];
char buffer[BUFFSIZE];
int counter=0;
int i=0;
menu(friends, &counter,i,buffer);
getch();
return 0;
}
//Menu function
void menu(fr*friends,int* counter, int i,char buffer[]) {
int user_entry=0;
int user_entry1=0;
int user_entry2=0;
char user_entry3[50]={'\0'};
FILE *read;
printf("Welcome! Would you like to import a file? (1)Yes or (2) No");
scanf("%d",&user_entry1);
if(user_entry1==1)
{
printf("Please enter a file name");
scanf("%s",user_entry3);
read=fopen(user_entry3,"r");
}else;
do{
int result;
printf("\nPhone Book Application\n");
printf("1) Add friend\n2) Delete friend\n3) Show a friend\n4) Show phonebook\n5)Exit\n");
scanf("%d", &user_entry);
if(user_entry==1)
{
add_contact(friends,counter,i,buffer);
}
if(user_entry==2)
{
delete_contact(friends ,counter,i);
}
if(user_entry==3)
{
result=show_contact(friends ,counter,i);
if(result==0)
{
printf("\nName not Found\n");
}else
result;
}
if(user_entry==4)
{
print_contact(friends, counter,i,user_entry3);
if(user_entry1==1){
file2(friends ,counter,i,buffer,read);
}else;
}
}while(user_entry!=5);
if(user_entry==5)
{
fclose(read);
printf("Would you like to save entries to a file? (1)yes or (2) no");
scanf("%d",&user_entry2);
if(user_entry2 == 1)
{
printf("Please name your file");
scanf("%s",user_entry3);
file(friends, counter,i,user_entry3);
printf("Goodbye!");
}else if(user_entry2 == 2)
{
printf("Goodbye!");
}
}
}
My read function:
char file2(fr*friends ,int* counter, int i,char buffer[],FILE*read){
fseek(read, 0, SEEK_SET);
while (fscanf(read, "%s", buffer) != EOF)
{
friends[i].First_Name=malloc(BUFFSIZE*strlen(buffer));
strcpy(friends[i].First_Name, buffer);
printf("%s\n",friends[i].First_Name);
}
}
As I said, right now I can view the contents of the file, but I cannot edit them or even output them to another file. There are also probably things in my code that are not perfect, but I'm trying to focus on this before i worry about making other changes( Since the program works outside of the issue mentioned). I'm ready to give out a big green checkmark! :)
If you want to edit the strings in your application, bear in mind, that you will have to take care of growing the buffer when needed. It might be more reasonable to use a fixed length records (and padding the string with zeros). Then you could only check that you are not overflowing past theend of the buffer and use fread() and fwrite() to read/dump the fr structures from/to a file in one go (basically read/write sizeof(fr) - unless you run the application on machines with different endianessess it's safe).
That said, a couple of obsrvations:
use switch instead of multiple if(user_entry==x), do something in the else part (print warning or whatever) - it usually signals either a regular or an error branch in the code.
use width in fscanf(read, "%s", buffer), to specify maximum string length that can fit in buffer, remember, that the '\0' string terminator is not counted towards this, so you need to use size of buffer - 1. I.e. either hardcode it to e.g.: %50s or compile the correct format string at runtime.
malloc(BUFFSIZE*strlen(buffer)) is probably not the size you really want to allocate
always check malloc() return value!

Resources