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);
}
Related
How do I only save one or more items that matches my search of varunummer? This function works but if my array is limited and save the file the items saved before disappear and only the searched item/s is saved. Also how do I increase the nrOfGoods just with the nr of items matched? PS: nrOfGoods keeps track for the number of items in the array. This is what I got so far:
struct varor{
int varunummer;
char namn[WORDLENGTH];
int lagersaldo;
};
void saveProduct(struct varor reg[], int nrOfGoods){
FILE * fp;
char nameFile[WORDLENGTH];
int i, j, varunummer;
printf("Enter varunummer: ");
scanf("%d", &varunummer);
for(i=0; i<nrOfGoods; i++){
if ( reg[i].varunummer == varunummer){
printf("Enter file name to save (end with .txt): ");
scanf("%s", nameFile);
fp = fopen (nameFile, "w");
//fprintf(fp,"%d\n", nrOfGoods);// this delete all my other saved items
for(i=0;i<(nrOfGoods);i++){
fprintf(fp,"%d\n", reg[i].varunummer);
fprintf(fp,"%s\n", reg[i].namn);
fprintf(fp,"%d\n", reg[i].lagersaldo);
}
} else printf("\nVarunummer not found!\n");
}
fclose(fp);
}
You shouldn't be writing the items in a second loop. Just write the item that matches.
You also need to open the file before the loop. When you open a file in w mode it empties the file first, so each time through the loop is deleting the previous iteration.
And you shouldn't print Varunnummer not found inside the loop, since you can't tell if the item isn't found until you go through the entire array. Use a variable that you set when you find a matching item; if you never find anything, it will not be updated, and you can print a message at the end. See Searching array reports "not found" even though it's found
struct varor{
int varunummer;
char namn[WORDLENGTH];
int lagersaldo;
};
void saveProduct(struct varor reg[], int nrOfGoods){
FILE * fp;
char nameFile[WORDLENGTH];
int i, j, varunummer;
int found = 0;
printf("Enter varunummer: ");
scanf("%d", &varunummer);
printf("Enter file name to save (end with .txt): ");
scanf("%s", nameFile);
fp = fopen (nameFile, "w");
for(i=0; i<nrOfGoods; i++){
if ( reg[i].varunummer == varunummer){
fprintf(fp,"%d\n", reg[i].varunummer);
fprintf(fp,"%s\n", reg[i].namn);
fprintf(fp,"%d\n", reg[i].lagersaldo);
found = 1;
}
}
fclose(fp);
if (!found) {
printf("\nVarunummer not found!\n");
}
}
My purpose is to create programme to manage records in files using c. the programme should be able to get info from console, write to a file and then read from it. Struct itself is working fine, but I'm not getting all the values i have written(see output)
and source code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct dob
{
int date;
int month;
int year;
};
struct person
{
int id;
char firstName[20];
char lastName[20];
struct dob date;
char email[20];
int phoneNo;
}new;
void readRecordsFromFile();
void readRecordsFromKeyboard();
int main(int argc, const char * argv[]) {
puts("Hello");
while (1) {
puts("Select option. \n 1. Read records from file. \n 2. Read records from keyboard \n Type any number to exit\n");
int i;
scanf("%d", &i);
switch (i) {
case 1:
readRecordsFromFile();
break;
case 2:
readRecordsFromKeyboard();
break;
default:
return 0;
break;
}
}
return 0;
}
void readRecordsFromFile(){
//struct person new;
char filename[100];
puts("Scpecify the file name to read data");
scanf("%s", filename);
struct person *new=malloc(sizeof(struct person));
FILE * file= fopen(filename, "rb");
if (file != NULL) {
fread(new, sizeof(struct person), 1, file);
fclose(file);
}
printf("\nID: %d\nName: %s\nSurname: %s\nDay of birth:%d\nMonth of birth:%d\nYear of birth:%d\nE-mail: %s\nPhone Number: %d\n",new->id,new->firstName,new->lastName,new->date.date,new->date.month,new->date.year,new->email,new->phoneNo);
}
void readRecordsFromKeyboard(){
struct person *new=malloc(sizeof(struct person));
puts("Enter the info about person");
puts("ID number");
scanf("%d", &new->id);
puts("First Name");
scanf("%19s", new->firstName);
puts("Last name");
scanf("%19s", new->lastName);
puts("Day, month and year of birth.(by numbers, every is new line)");
scanf("%d", &new->date.date);
scanf("%d", &new->date.month);
scanf("%d", &new->date.year);
puts("Email");
scanf("%19s", new->email);
puts("Phone number");
scanf("%d", &new->phoneNo);
puts("Specify the file you want to write yor data");
char filename[100];
scanf("%99s",filename);
FILE *inputf;
inputf = fopen(filename,"wb");
if (inputf == NULL){
printf("Can not open the file.\n");
exit(0);
}else{
if (fwrite(new, sizeof(new), 1, inputf) != 1)
{
fprintf(stderr, "Failed to write to %s\n", filename);
return;
}else{
puts("Data saved\n");
printf("\nID: %d\nName: %s\nSurname: %s\nDay of birth:%d\nMonth of birth:%d\nYear of birth:%d\nE-mail: %s\nPhone Number: %d\n",new->id,new->firstName,new->lastName,new->date.date,new->date.month,new->date.year,new->email,new->phoneNo);
}
}
fclose(inputf);
}
here is your problem
inputf = fopen(filename,"wb");
This command clears file, because it file is opened with "wb".
If you are going to write multiple record in that file in several runs, open it with "wb+". Then use fseek() to go to end of file. after that write your record with fwrite().
In addition for fwrite() you need to use sizeof strusture, not pointer.Means that you need something like this:
if (fwrite(new, sizeof(struct person), 1, inputf) != 1)
{
}
It creates the temp file containing the required result. but its not removing the previous file "records.txt" and not renaming temp.txt. im using dev c++.
void delete()
{
FILE *fp, *ft;
int no;
char ch;
student stud;
fp = fopen("Records.txt","r");
printf("\nEnter student's RollNo to delete:");
scanf("%d",&no);
ft = fopen("temp.txt","w+");
while (!feof(fp))
{
fscanf(fp, "\n%d\t%s\t", &stud.roll_no, stud.name);
if (stud.roll_no != no)
{
fprintf(ft, "\n\t%d \t%s", stud.roll_no, stud.name);
}
}
fclose(fp);
fclose(ft);
remove("Records.txt");
rename("temp.txt","Records.txt");
}
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.
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");
...