Passing array of structure to fread and fwrite function in C - c

I have a questions regarding the fread() and fwrite() function in c.
Talking about the first parameter void* If i am dealing with array of structure and want to pass an entire array what should i use &arrayName or arrayName.
Now I am trying to input some data from users create a student.txt file and store the data in that file and again read that data from the same file and display it.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
struct dob
{
int year,month,date;
};
struct student
{
int roll;
char name[20],address[20],faculty[30];
struct dob a;
};
struct student s1[2],s2[2];
FILE *fp;
fp = fopen("student.txt","w+b");
if(fp == NULL)
{
printf("Cannot open file");
exit(0);
}
for(int i = 0 ; i < 2 ; i++)
{
fflush(stdin);
printf("Enter the name of student %d\n",i+1);
scanf("%[^\n]s",s1[i].name);
fflush(stdin);
printf("Enter address\n");
scanf("%[^\n]s",s1[i].address);
fflush(stdin);
printf("Enter roll no\n");
scanf("%d",&s1[i].roll);
fflush(stdin);
printf("Enter faculty\n");
scanf("%[^\n]s",s1[i].faculty);
fflush(stdin);
printf("Enter the Birth year\n");
scanf("%d",&s1[i].a.year);
printf("Enter the Birth month\n");
scanf("%d",&s1[i].a.month);
printf("Enter the Birth date\n");
scanf("%d",&s1[i].a.date);
}
fwrite(&s1,sizeof(s1),2,fp);
rewind(fp);
fread(&s2,sizeof(s2),2,fp);
for(int i = 0 ; i < 2 ; i++)
{
printf("Name : %s\n Address = %s\n Faculty = %s\n Roll = %d\n year = %d\n month = %d\n date =
%d\n",
s2[i].name,s2[i].address,s2[i].faculty,s2[i].roll,s2[i].a.year,s2[i].a.month,s2[i].a.date);
}
fclose(fp);
return 0;
}
I am asking it because both of them works for my above code.But How?
I am talking about this line
fwrite(&s1,sizeof(s1),2,fp);
fread(&s2,sizeof(s2),2,fp);
Here s1 and s2 works without & as well

Related

Create a file and write struct with data member and the file created is empty

I create a program that prompts the user to choose an option, like below:
create a file and name the file.
add component in the file
display the item in the file
exit program
So my problem is the file is created and exists in my directory, but it is empty, so where did I miss something? plus can you check whether the 2 and 3 option program are OK?
Here my program:
#include <stdio.h>
#include <stdlib.h>
int main() {
int num, name;
start:
printf("\n1. Create a file.");
printf("\n2. Add a component to the list.");
printf("\n3. Display the current list of component.");
printf("\n4. Exit program.");
printf("\n\nChoose either these four menu = ");
scanf("%d", &num);
fflush(stdin);
switch (num) {
case 1:
printf("\n\nPlease enter file name: ");
scanf("%d", &name);
FILE *pf = NULL;
char username[250];
char userfile[255];
printf("username: ");
scanf("%s", username);
sprintf(userfile, "%s.txt", username);
fflush(stdin);
goto start;
break;
case 2:
pf = fopen(userfile, "w");
if (!pf) {
fprintf(stderr, "File opening failed!\n");
return EXIT_FAILURE;
}
struct date {
int day;
int month;
int year;
};
struct details {
char name[20];
int price;
int code;
int qty;
struct date mfg;
};
struct details item[50];
int n, i;
printf("Enter number of items:");
scanf("%d", &n);
fflush(stdin);
for (i = 0; i < n; i++) {
fflush(stdin);
printf("Item name: \n");
scanf("%s", item[i].name);
fflush(stdin);
printf("Item code: \n");
scanf("%d", &item[i].code);
fflush(stdin);
printf("Quantity: \n");
scanf("%d", &item[i].qty);
fflush(stdin);
printf("price: \n");
scanf("%d", &item[i].price);
fflush(stdin);
printf("Manufacturing date(dd-mm-yyyy): \n");
scanf("%d-%d-%d", &item[i].mfg.day,
&item[i].mfg.month, &item[i].mfg.year);
}
fclose(pf);
goto start;
break;
case 3:
pf = fopen(userfile, "r");
if (!userfile) {
fprintf(stderr, "File opening failed!\n");
return EXIT_FAILURE;
}
{
printf(" ***** INVENTORY ***** \n");
printf("------------------------------------------------------------------\n");
printf("S.N.| NAME | CODE | QUANTITY | PRICE | MFG.DATE \n");
printf("-------------------------------------------------------- ---------\n");
for (i = 0; i < n; i++)
fprintf("%d %-15s %-d %-5d %-5d %d/%d/%d \n",
i + 1, item[i].name, item[i].code, item[i].qty,
item[i].price, item[i].mfg.day, item[i].mfg.month,
item[i].mfg.year);
printf("------------------------------------------------------------------\n");
}
fclose(pf);
goto start;
break;
case 4:
printf("Exit Program, Thank You, Sayonara");
break;
}
return 0;
}
There are multiple problems in your code:
the test if (!userfile) is incorrect: you should test if (!pf) instead
you open the file for reading, you should open it for writing with "w", or possibly for appending with "a".
you never write to the file. You should use fprintf(pf, ...) instead of printf.
the arrays userfile, item and variables i and n are local inside the switch statement: their contents go out of scope when you go to the start label outside de switch statement. Move all these definitions outside the switch statement.
fflush(stdin); has undefined behavior. You can consume (flush) the rest of the input line with: int c; while ((c = getchar()) != EOF && c != '\n') continue; You can define a function flush() that does it.

How can I utilize struct arrays to output a given struct based on user-input

ISSUE: I'm trying to fill my beerData struct with data found in beer.dat, except I don't understand how structs work well enough to implement without crashing my code. I believe I need an array of structs.
The beer.dat file contents:
7 // total number of beers
Coors //beer name
1234567 // beer id
72 // beer quantity
7.40 //beer price
Miller
7777777
44
9.70
Bud
7654321
345
9.90
Wachusett
7799435
4
14.70
Corona
9999999
112
9.99
Zima
0000000
1
0.01
Mikes
0890398
12
10.99
CODE:
/*
User interface, alloc, malloc 13 points
Correct structure and array built 7 points
Recursive sort
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct beerData {
char *beer[7]; // number of brands
char *beer_name; //names
int beer_id[7]; //ID number given to beer
int beer_quantity; //stock
float beer_price; // pricing
} beer_data;
void printStr(char *line) {
char *look = "";
printf("What would you like to search for? \n");
scanf("%s", look);
//printf("Line: %s\n", line);
exit(0);
}
void search() {
//look through beer.dat for a specific beer by ID number.
char str[32];
FILE *fp = fopen("beer.dat", "r");
if (fp == NULL) {
printf("Error: can't open file to read\n");
} else {
while (!feof(fp)) {
fscanf(fp, "%s ", str);
//printf("%s\n",str);
printStr(str);
}
}
fclose(fp);
}
int main() {
int user_choice;
printf("Enter 1 to search for a beer, 2 to view the entire catalogue,"
" and 3 to place an order, press 4 to exit.\n");
while (user_choice != 4) {
scanf("%d", &user_choice);
switch (user_choice) {
case 1:
printf("Searching for a beer\n");
user_choice = 0;
search();
break;
case 2:
printf("Viewing Inventory\n");
//viewInv();
break;
case 3:
printf("Placing an order...\n");
//placeOrder();
break;
case 4:
printf("Goodbye!\n");
exit(0);
default:
printf("Incorrect entry, try again.\n");
continue;
}
}
}
I'm trying create a function that searches through the file, and finds a specific beer based on an ID given, that ID is inside a set that should be its struct... so once the ID is input, the program searches for the beer, and prints out the name, ID, quantity, and price.
For full clarity, I'll post the assignment questions in case I'm not conveying my needs properly. The assignment is to:
Searching for a beer should prompt the user for an ID number and the result should display its quantity and price, if it is in your inventory.
A view of the entire inventory will display all the beers with their ID number, price and quantity in ascending order by price. This sorting should be done using either Recursive Bubble or Recursive Selection sort.
When placing an order an invoice of the order should be printed to the screen.
First you need to declare a meaningful structure. The structure contains relevant information for each item. Example:
typedef struct beer_data
{
char name[20]; //names
int id; //ID number given to beer
int quantity; //stock
float price; // pricing
} beer_data;
Next, you need an array of this structure. Use malloc to allocate enough memory for total number of items. Example:
beer_data *beers = malloc(total * sizeof(beer_data));
Now you have beers[0], beers[1], beers[2]..., read each item in the file and put that in the structure.
To read the file, you can use fscanf or fgets.
The first line in your file is
7 // total number of beers
You can read the number 7 using fscanf:
int maximum = 0;
fscanf(fp, "%d", &maximum);
This should work fine, but there are characters after that which you are not interested in. Use fgets to read to the end of the line and discard those characters.
Start a loop and read each line, add to the structure.
With this method, if you are adding a new item, then you have to increase the memory size. See add_item which uses realloc. This might be too advanced. Alternatively, you can save the new item to the file, call free(beers), and read the file again.
typedef struct beer_data
{
char name[20]; //names
int id; //ID number given to beer
int quantity; //stock
float price; // pricing
} beer_data;
void search_by_name(beer_data *beers, int total)
{
char buf[20];
printf("Enter name to search: ");
scanf("%19s", buf);
//note, we put %19s because beers[count].name is only 20 bytes long
for(int i = 0; i < total; i++)
{
if(strcmp(beers[i].name, buf) == 0)
{
printf("Found: %s, %d, %d, %.2f\n",
beers[i].name, beers[i].id, beers[i].quantity, beers[i].price);
return;
}
}
printf("%s not found\n", buf);
}
void print_list(beer_data *beers, int total)
{
for(int i = 0; i < total; i++)
{
printf("%s %d %d %.2f\n",
beers[i].name, beers[i].id, beers[i].quantity, beers[i].price);
}
}
void add_item(beer_data *beers, int *total)
{
//note, total has to be passed as pointer
//because we are changing it
//allocate more memory:
beers = realloc(beers, sizeof(beer_data) * (*total + 1));
printf("enter name: ");
scanf("%19s", beers[*total].name);
printf("enter id:");
scanf("%d", &beers[*total].id);
printf("enter quantity:");
scanf("%d", &beers[*total].quantity);
printf("enter price:");
scanf("%f", &beers[*total].price);
//increase the total
*total += 1;
}
int main()
{
FILE *fp = fopen("beer.dat", "r");
if(!fp)
{
printf("Error: can't open file to read\n");
return 0;
}
char buf[500];
int maximum = 0;
fscanf(fp, "%d", &maximum);
//read the rest of the line and discard it
fgets(buf, sizeof(buf), fp);
//allocate memory
beer_data *beers = malloc(maximum * sizeof(beer_data));
int total = 0;
while(1)
{
fgets(buf, sizeof(buf), fp);
sscanf(buf, "%19s", beers[total].name);
if(fscanf(fp, "%d", &beers[total].id) != 1) break;
fgets(buf, sizeof(buf), fp);
if(fscanf(fp, "%d", &beers[total].quantity) != 1) break;
fgets(buf, sizeof(buf), fp);
if(fscanf(fp, "%f", &beers[total].price) != 1) break;
fgets(buf, sizeof(buf), fp);
total++;
if(total == maximum)
break;
}
fclose(fp);
int stop = 0;
while (!stop)
{
printf("\
Enter 0 to exit\n\
Enter 1 print list\n\
Enter 2 for search\n\
Enter 3 add new item\n");
int choice;
scanf("%d", &choice);
switch(choice)
{
case 0:
stop = 1;
break;
case 1:
print_list(beers, total);
break;
case 2:
search_by_name(beers, total);
break;
case 3:
add_item(beers, &total);
break;
}
printf("\n");
}
//cleanup:
free(beers);
return 0;
}

How to add strings and integers to an array then print to a text file

Goodday, when I get to entering the first name of the student, the program immediately crashes. Also I'm not exactly sure how to add the names and the ID into an array to print to the text file. May I have some assistance please?
struct records{
int id;
char fname[15];
char lname[15];
};
struct records student;
int max=1000;
int i;
srand( time(NULL) ); //random numbers generated
ATND= fopen("Student Record.txt","a");
if(ATND== NULL){
printf("ERROR!");
exit(1);
}
for(i=0; i<100; i++){
printf("Enter student\'s first name: ");
scanf("%s", student.fname[i]);
printf("\n\n");
printf("Enter student\'s last name: ");
scanf("%s", student.lname[i]);
/*randomnumber*/student.id[i]=rand() %max + 39048543;
fprintf(ATND,"%s %s %d", student.fname[i], student.lname[i], student.id[i]);
}
fclose(ATND);
Code only provides data space for 1 record whereas it appears to need 1000 records. Number of other issues. Suspect after 10 hours, OP has worked a number of them
//Definition - good
struct records {
int id;
char fname[15]; // IMO 15 is too limiting for first and last
char lname[15];
};
// Only 1 student, need many more
// struct records student;
#define STUDENT_N 1000
struct records student[STUDENT_N];
void read_records(void) {
// avoid magic numbers
// int max = 1000;
int max = STUDENT_N;
int i;
srand(time(NULL)); //random numbers generated
// ATND not declared
FILE *ATND;
ATND = fopen("Student Record.txt", "a");
if (ATND == NULL) {
printf("ERROR!");
exit(1);
}
char buf[100];
// avoid magic numbers
// for (i = 0; i < 100; i++) {
for (i = 0; i < STUDENT_N; i++) {
printf("Enter student\'s first name: ");
// don't use scanf()
// scanf("%s", student.fname[i]);
if (fgets(buf, sizeof buf, stdin) == NULL) break;
if (sscanf(buf, "%14s", student[i].fname) != 1) break;
printf("\n\n");
printf("Enter student\'s last name: ");
// Add flush to insure buffered prompts that do not end in \n are sent
fflush(stdout);
// scanf("%s", student.lname[i]);
if (fgets(buf, sizeof buf, stdin) == NULL) break;
if (sscanf(buf, "%14s", student[i].lname) != 1) break;
// /*randomnumber*/student.id[i] = rand() % max + 39048543;
/*randomnumber*/student[i].id = rand() % max + 39048543;
// Do not index the name, index the structure
// fprintf(ATND, "%s %s %d", student.fname[i], student.lname[i], student.id[i]);
fprintf(ATND, "%s %s %d", student[i].fname, student[i].lname, student[i].id);
}
fclose(ATND);
}
Assuming student.fname is a char array of sufficient size
scanf("%s", student.fname[i]);
should be
scanf("%s", student.fname);
You need to pass a pointer to the beginning of the array, NOT the value of the chars, one by one. scanf will enter the entire name in one call.

What is wrong with the following code? I am trying to search for a record in a text file

The program runs fine till I create the file and enter records from structure, but when I try to search a record by using roll no, it crashes.
I am using a structure called student to store data and then I am creating a text file and then I use a for loop to write data on the text file. Then I reopen the file and try to search a record using student roll no.
Program runs fine until I try to search the student roll no. It crashes right after I enter the student roll no to be searched.
Can anyone tell me what modification is needed to make the search work?
Below is my code:
#include<stdio.h>
struct student {
int roll_no;
char name [80];
int age;
}st[30],s;
int main ()
{
int i,n;
char fname[80];
int search;
int found;
FILE *fp;
printf("\nEnter the file name : \n");
scanf("%s",fname);
fp=fopen(fname,"w");
if(fp==NULL)
{
printf("\nCannot create file :");
exit(0);
}
printf("\nNumber of students : \n");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("\n\nInformation for student#%d : \n\n",i+1);
printf("\nStudent roll number : \n" );
scanf("%d",&st[i].roll_no);
printf("\nStudent name: \n: ");
scanf("%s",st[i].name);
printf("\nStudent age : ");
scanf("%d", &st[i].age);
}
fprintf(fp, "\nStudent roll no\t\t Student name\t\t student age\t\t\n\n");
for(i=0;i<n;i++)
{
fprintf(fp, "\n%d \t\t %s \t\t %d \t\t", st[i].roll_no,st[i].name,st[i].age);
}
fclose(fp);
fp=fopen(fname,"r+t");
if(fp==NULL)
{
printf("\nCannot open file\n");
exit(0);
}
printf("\n\nStudent roll no to be searched : ");
found=0;
scanf("%d", search);
while(!(feof(fp)) && (found==0))
{
fscanf(fp,"%d,%s,%d",&s.roll_no,s.name,&s.age);
if(s.roll_no==search)
{
fseek(fp,-sizeof(struct student), SEEK_CUR);
printf("\nEnter new name : \n");
scanf("%s", s.name);
fprintf(fp, "\n%d \t\t %s \t\t %d \t\t", s.roll_no,s.name,s.age);
found=1;
}
}
if(found=0)
{
printf("\nStudent record doesn't exist \n");
}
fclose(fp);
return 0;
}
In your code, you're missing an address-of operator in scanf(), thereby passing an invalid type of argument. Basically
scanf("%d", search);
should be
scanf("%d", &search);
That said, it is always a good practice to size-limit the inputs for string, like, for an array defined like char fname[80];, you should use
scanf("%79s",fname);
to avoid possible buffer overflow by excessively long input.
Also, always check for the return value of scanf() and family of functions to ensure their success.

Save, find and remove structure from txt file

I am studying IT and programming is something new for me. Last week I got a task to do. I have to write a program which can save a structure (personal data of company's workers) to file.txt. Program should be able to find a specific person (putting his name or surname) and delete all people whose got a surname given by user as well. These all tasks should be in separate functions. Till now I wrote this function:
void struktura()
{
struct Person
{
char name[30];
char surname[30];
int age;
int height;
int weight;
};
int ile;
int i = 0;
printf("\n");
printf("How many persons would you like add to database (max 10 at once): ");
scanf("%d", &ile);
printf("\n");
if (ile >= 0)
{
printf("You added no one.\n");
}
else
{
struct Person *osoba[10]; //
while (i < ile)
{
osoba[i] = (struct Person*) malloc(sizeof (struct Person));
printf("Give a name: ");
scanf("%s", osoba[i]->name);
printf("Give a surname: ");
scanf("%s", osoba[i]->surname);
printf("Age: ");
scanf("%d", &osoba[i]->age);
printf("Height: ");
scanf("%d", &osoba[i]->height);
printf("Weight: ");
scanf("%d", &osoba[i]->weight);
printf("\n");
i = i + 1;
}
printf("You have added: \n\n");
i = 0;
while (i < ile)
{
printf("%d) Name: %s, Surname: %s, Age: %d years, Height: %d cm, Weight: %d kg.\n", i + 1, osoba[i]->name, osoba[i]->surname, osoba[i]->age, osoba[i]->height, osoba[i]->weight);
i = i + 1;
}
for (i = 0; i < ile; i++)
{
free(osoba[i]);
}
}
}
In additition, I have a code which save these persons to the file.txt. I would like to separate code (below) to another function but I don't know how to pass a structure to function.
FILE *save;
char name[30];
printf("\nWhere to save a database: ");
scanf("%s", name);
save = fopen(name, "a");
if (save == NULL)
{
printf("This file doesn't exist!");
getchar();
exit(1);
}
i = 0;
while (i < ile)
{
fprintf(save, "Name: %s, Surname: %s, Age: %d years, Height: %d cm, Weight: %d kg.\n",osoba[i]->name, osoba[i]->surname, osoba[i]->age, osoba[i]->height, osoba[i]->weight);
i = i + 1;
}
fclose(save);
I wrote a function, which opens the whole content of file.txt as well. What I missing is : how to find a specific person and how to delete these persons(I was thinking about opening a second temporary file and copy an content of original file except these lines which include given name/surname) (all in separate functions). Do you have any ideas how I could do this? I was looking for it in some books but I couldn't find any help.
I would like to separate code (below) to another function but I don't
know how to pass a structure to function.
Define struct Person outside and above the functions, so it can be used in all of them. Then you can put the code which saves the persons to the file in a function
void save(int ile, struct Person *osoba[ile])
{
…
}
and call this with
save(ile, osoba);
how to find a specific person
You could use the following function, which is a little more complicated than necessary for the finding task, but can be reused for another purpose:
char prformat[] =
"Name: %s, Surname: %s, Age: %d years, Height: %d cm, Weight: %d kg.\n";
char scformat[] =
"Name: %[^,], Surname: %[^,], Age:%d years, Height:%d cm, Weight:%d kg.\n";
// Read the data file "file.txt", look for 'name' or 'surname' (unless NULL),
// and output line(s) to 'out' if or unless they match (depending on 'match')
scan(char *name, char *surname, _Bool match, FILE *out)
{
FILE *fp = fopen("file.txt", "r");
if (!fp) perror("file.txt"), exit(1);
struct Person osoba;
while (fscanf(fp, scformat, osoba.name, osoba.surname,
&osoba.age, &osoba.height, &osoba.weight) == 5
)
if ( name && strcmp(osoba. name, name) == 0 == match
|| surname && strcmp(osoba.surname, surname) == 0 == match
)
if (fprintf(out, prformat, osoba.name, osoba.surname,
osoba.age, osoba.height, osoba.weight)
< 0) perror(""), exit(1);
fclose(fp);
}
calling it with
char name[30];
printf("Give a name or surname to find: ");
if (scanf("%29s", name) == 1)
scan(name, name, 1, stdout); // print matching lines to stdout
delete all people whose got a surname given by user …
(I was thinking about opening a second temporary file and copy an content of original file except these lines …
You were thinking right:
printf("Give a surname to delete: ");
if (scanf("%29s", name) == 1)
{
FILE *fp = fopen("file.tmp", "w");
if (!fp) perror("file.tmp"), exit(1);
scan(NULL, name, 0, fp); // print non-matching lines to tempfile
if (fclose(fp) < 0) perror("file.tmp"), exit(1);
remove("file.txt");
if (rename("file.tmp", "file.txt") != 0) perror("file.tmp");
}

Resources